# ExportTo

**Category:** Features/Export

## Design

### ExportTo

The ExportTo is a platformised solution for exporting lists of data.

This feature allows users to choose which data they want to export, whether it’s all the data in their table, filtered items, or items they’ve selected manually.

It consists of two parts: Client - responsible for the button and modal, and Server - that holds the logic and data.


### Server Implementation

To work with this feature, you need to implement the API on the server side. All server-related information can be found in the [Export Service documentation](https://dev.wix.com/docs/rest/business-management/export/export-async-job-v1/integration).

```tsx
import { ExportButton } from '@wix/patterns';
```

---

### Variations

### Export all table

```tsx
import { Avatar, Page } from '@wix/design-system';
import React from 'react';
import {
  CollectionToolbarFilters,
  ExportButton,
  Filter,
  Table,
  PageWrapper,
  MultiSelectCheckboxFilter,
  OffsetQuery,
  stringsArrayFilter,
  useTableCollection,
  useExportConfig,
  useStaticListFilterCollection,
  ToolbarTitle,
} from '@wix/patterns';
import { queryContacts } from '@wix/ambassador-contacts-v4-contact/http';
import { Contact } from '@wix/ambassador-contacts-v4-contact/types';
import { useHttpClient } from '@wix/yoshi-flow-bm';

type ContactsFilters = {
  level: Filter<string[]>;
};

function ExportAllTable() {
  const httpClient = useHttpClient();

  const state = useTableCollection<Contact, ContactsFilters>({
    queryName: 'ExportAllTable',
    fetchData: (query: OffsetQuery<ContactsFilters>) => {
      const { limit, offset, search, filters } = query;
      return httpClient
        .request(
          queryContacts({
            query: { paging: { limit, offset }, filter: filters },
            search,
          }),
        )
        .then(({ data: { contacts = [], pagingMetadata } }) => ({
          items: contacts,
          total: pagingMetadata?.total,
        }));
    },
    itemKey: (item) => item.id as string,
    itemName: (item) => item.name as string,
    fetchErrorMessage: () => 'Error fetching contacts',
    filters: {
      level: stringsArrayFilter(),
    },
  });

  const exportConfig = useExportConfig<Contact, ContactsFilters>({
    transformPlatformizedQuery: ({
      platformizedQuery,
      wixPatternsQuery,
      selectedItems,
    }) => {
      // TODO: add logic here
      return {
        ...platformizedQuery,
        paging: {
          limit: 20,
        },
      };
    },
    methodMetadata: {
      artifact: 'com.wixpress.fedinfra.exportservice.export-service',
      service: 'ExportService',
      method: 'QueryProductsExportSpi',
    },
    fields: [
      { id: 'contact.id', header: 'id' },
      { id: 'contact.info.name.first', header: 'First Name' },
      { id: 'contact.info.name.last', header: 'Last Name' },
      { id: 'contact.primary_info.email', header: 'Email' },
    ],
  });
  const collection = state.collection;
  const levelsCollection = useStaticListFilterCollection(
    collection.filters.level,
    [
      'Beginner',
      'Amateur',
      'Semi-Pro',
      'Professional',
      'World Class',
      'Legendary',
      'Ultimate',
    ],
  );

  return (
    <PageWrapper>
      <Page height="400px">
        <Page.Header title="Contacts" />
        <Page.Content>
          <Table
            state={state}
            title={<ToolbarTitle title="Contacts" showTotal />}
            columns={[
              {
                title: '',
                width: '50px',
                render: (contact) => (
                  <Avatar
                    name={contact.name}
                    imgProps={{ src: contact.image }}
                  />
                ),
              },
              {
                title: 'Name',
                width: '250px',
                render: (contact) => contact.name,
              },
              {
                title: 'Level',
                render: (contact) => contact.level,
              },
              {
                title: 'Last Seen',
                render: (contact) => contact.lastSeen?.toLocaleString(),
              },
            ]}
            filters={
              <CollectionToolbarFilters
                inline={1}
                panelTitle="Filter your contacts"
              >
                <MultiSelectCheckboxFilter
                  popoverProps={{ appendTo: 'window' }}
                  filter={collection.filters.level}
                  collection={levelsCollection}
                  renderItem={(level) => ({ title: level })}
                />
              </CollectionToolbarFilters>
            }
            exportButton={<ExportButton {...exportConfig} />}
          />
        </Page.Content>
      </Page>
    </PageWrapper>
  );
}
```

### Export filtered table

Export the table with the filters applied

```tsx
import { Avatar, Page } from '@wix/design-system';
import React from 'react';
import {
  CollectionToolbarFilters,
  ExportButton,
  Filter,
  Table,
  PageWrapper,
  MultiSelectCheckboxFilter,
  OffsetQuery,
  stringsArrayFilter,
  useTableCollection,
  useExportConfig,
  useStaticListFilterCollection,
  ToolbarTitle,
} from '@wix/patterns';
import { queryContacts } from '@wix/ambassador-contacts-v4-contact/http';
import { Contact } from '@wix/ambassador-contacts-v4-contact/types';
import { useHttpClient } from '@wix/yoshi-flow-bm';

type ContactsFilters = {
  level: Filter<string[]>;
};

function ExportFlilteredTable() {
  const httpClient = useHttpClient();

  const state = useTableCollection<Contact, ContactsFilters>({
    queryName: 'contacts-BulkActions',
    fetchData: (query: OffsetQuery<ContactsFilters>) => {
      const { limit, offset, search, filters } = query;
      return httpClient
        .request(
          queryContacts({
            query: { paging: { limit, offset }, filter: filters },
            search,
          }),
        )
        .then(({ data: { contacts = [], pagingMetadata } }) => ({
          items: contacts,
          total: pagingMetadata?.total,
        }));
    },
    itemKey: (item) => item.id as string,
    itemName: (item) => item.name as string,
    fetchErrorMessage: () => 'Error fetching contacts',
    filters: {
      level: stringsArrayFilter({
        initialValue: ['Beginner'],
      }),
    },
  });

  const exportConfig = useExportConfig<Contact, ContactsFilters>({
    saveAs: ({ wixPatternsQuery }) =>
      `Contacts [${wixPatternsQuery.filters.level?.join(', ')}]`,
    transformPlatformizedQuery: ({
      platformizedQuery,
      wixPatternsQuery,
      selectedItems,
    }) => {
      // TODO: add logic here
      return {
        ...platformizedQuery,
        paging: {
          limit: 20,
        },
      };
    },
    methodMetadata: {
      artifact: 'com.wixpress.fedinfra.exportservice.export-service',
      service: 'ExportService',
      method: 'QueryProductsExportSpi',
    },
    fields: [
      { id: 'contact.id', header: 'id' },
      { id: 'contact.info.name.first', header: 'First Name' },
      { id: 'contact.info.name.last', header: 'Last Name' },
      { id: 'contact.primary_info.email', header: 'Email' },
    ],
  });
  const collection = state.collection;
  const levelsCollection = useStaticListFilterCollection(
    collection.filters.level,
    [
      'Beginner',
      'Amateur',
      'Semi-Pro',
      'Professional',
      'World Class',
      'Legendary',
      'Ultimate',
    ],
  );

  return (
    <PageWrapper>
      <Page height="400px">
        <Page.Header title="Contacts" />
        <Page.Content>
          <Table
            state={state}
            title={<ToolbarTitle title="Contacts" showTotal />}
            columns={[
              {
                title: '',
                width: '50px',
                render: (contact) => (
                  <Avatar
                    name={contact.name}
                    imgProps={{ src: contact.image }}
                  />
                ),
              },
              {
                title: 'Name',
                width: '250px',
                render: (contact) => contact.name,
              },
              {
                title: 'Level',
                render: (contact) => contact.level,
              },
              {
                title: 'Last Seen',
                render: (contact) => contact.lastSeen?.toLocaleString(),
              },
            ]}
            filters={
              <CollectionToolbarFilters
                inline={1}
                panelTitle="Filter your contacts"
              >
                <MultiSelectCheckboxFilter
                  popoverProps={{ appendTo: 'window' }}
                  filter={collection.filters.level}
                  collection={levelsCollection}
                  renderItem={(level) => ({ title: level })}
                />
              </CollectionToolbarFilters>
            }
            exportButton={<ExportButton {...exportConfig} />}
          />
        </Page.Content>
      </Page>
    </PageWrapper>
  );
}
```

### Export table with selection / bulk selection

Export only the selected items from the table

```tsx
import {
  Avatar,
  Card,
  CustomModalLayout,
  Modal,
  Page,
  Text,
} from '@wix/design-system';
import React from 'react';
import {
  ExportButton,
  Filter,
  Table,
  PageWrapper,
  MultiBulkActionToolbar,
  OffsetQuery,
  stringsArrayFilter,
  useTableCollection,
  useExportConfig,
  ToolbarTitle,
} from '@wix/patterns';
import { Block, ChangeOrder, Download, Edit } from '@wix/wix-ui-icons-common';
import { queryContacts } from '@wix/ambassador-contacts-v4-contact/http';
import { Contact } from '@wix/ambassador-contacts-v4-contact/types';
import { useHttpClient } from '@wix/yoshi-flow-bm';

type ContactsFilters = {
  level: Filter<string[]>;
};

function ExportToBulkSelectExample() {
  const httpClient = useHttpClient();

  const state = useTableCollection<Contact, ContactsFilters>({
    queryName: 'contacts-BulkActions',
    fetchData: (query: OffsetQuery<ContactsFilters>) => {
      const { limit, offset, search, filters } = query;
      return httpClient
        .request(
          queryContacts({
            query: { paging: { limit, offset }, filter: filters },
            search,
          }),
        )
        .then(({ data: { contacts = [], pagingMetadata } }) => ({
          items: contacts,
          total: pagingMetadata?.total,
        }));
    },
    itemKey: (item) => item.id as string,
    itemName: (item) => item.name as string,
    fetchErrorMessage: () => 'Error fetching contacts',
    filters: {
      level: stringsArrayFilter({
        initialValue: ['Beginner'],
      }),
    },
  });

  const exportConfig = useExportConfig<Contact, ContactsFilters>({
    transformPlatformizedQuery: ({
      platformizedQuery,
      wixPatternsQuery,
      selectedItems,
    }) => {
      // TODO: add logic here
      return {
        ...platformizedQuery,
        paging: {
          limit: 20,
        },
      };
    },
    methodMetadata: {
      artifact: 'com.wixpress.fedinfra.exportservice.export-service',
      service: 'ExportService',
      method: 'QueryProductsExportSpi',
    },
    fields: [
      { id: 'contact.id', header: 'id' },
      { id: 'contact.info.name.first', header: 'First Name' },
      { id: 'contact.info.name.last', header: 'Last Name' },
      { id: 'contact.primary_info.email', header: 'Email' },
    ],
  });
  const collection = state.collection;
  React.useEffect(() => {
    collection.bulkSelect.selectAll();
  }, []);

  return (
    <PageWrapper>
      <Page height="400px">
        <Page.Header title="Contacts" />
        <Page.Content>
          <Table
            state={state}
            title={<ToolbarTitle title="Contacts" showTotal />}
            columns={[
              {
                title: '',
                width: '50px',
                render: (contact) => (
                  <Avatar
                    name={contact.name}
                    imgProps={{ src: contact.image }}
                  />
                ),
              },
              {
                title: 'Name',
                width: '250px',
                render: (contact) => contact.name,
              },
              {
                title: 'Level',
                render: (contact) => contact.level,
              },
              {
                title: 'Last Seen',
                render: (contact) => contact.lastSeen?.toLocaleString(),
              },
            ]}
            bulkActionModal={({
              isModalOpen,
              selectedValues,
              closeModal,
              query,
            }) => (
              <Modal isOpen={isModalOpen}>
                <CustomModalLayout
                  height={300}
                  dataHook="bulk-action-custom-modal-layout"
                  title="Edit Contacts"
                  primaryButtonOnClick={closeModal}
                  primaryButtonText="save"
                  secondaryButtonOnClick={closeModal}
                  secondaryButtonText="cancle"
                >
                  {selectedValues.map((value, index) => (
                    <Card>
                      <Text
                        key={value.id}
                        dataHook={`selected-value-text-${index}`}
                      >
                        Page: {query.page}; Name: {value.name}
                      </Text>
                    </Card>
                  ))}
                </CustomModalLayout>
              </Modal>
            )}
            bulkActionToolbar={({ selectedValues, openModal }) => {
              const disabled = selectedValues.length > 4;
              return (
                <MultiBulkActionToolbar
                  primaryActionItems={[
                    {
                      dataHook: 'edit-button',
                      onClick: openModal,
                      label: 'Edit',
                      prefixIcon: <Edit />,
                      biName: 'edit',
                    },
                    {
                      dataHook: 'download-button',
                      onClick: openModal,
                      label: 'Download',
                      prefixIcon: <Download />,
                      tooltip: disabled
                        ? 'Downloading is supported for up to 10 items'
                        : undefined,
                      disabled,
                      biName: 'download',
                    },
                  ]}
                  secondaryActionItems={[
                    {
                      dataHook: 'block-button',
                      onClick: openModal,
                      label: 'Block',
                      prefixIcon: <Block />,
                      biName: 'block',
                    },
                    {
                      dataHook: 'change-button',
                      onClick: openModal,
                      label: 'Change',
                      disabled,
                      prefixIcon: <ChangeOrder />,
                      biName: 'change',
                    },
                  ]}
                />
              );
            }}
            exportButton={<ExportButton {...exportConfig} />}
          />
        </Page.Content>
      </Page>
    </PageWrapper>
  );
}
```

### CTA is out of the table

The export button is out of the table

```tsx
import { Avatar, Page, Button } from '@wix/design-system';
import React from 'react';
import {
  CollectionToolbarFilters,
  ExportModal,
  Filter,
  Table,
  PageWrapper,
  MultiSelectCheckboxFilter,
  OffsetQuery,
  stringsArrayFilter,
  useTableCollection,
  useExportConfig,
  useStaticListFilterCollection,
  ToolbarTitle,
} from '@wix/patterns';
import { queryContacts } from '@wix/ambassador-contacts-v4-contact/http';
import { Contact } from '@wix/ambassador-contacts-v4-contact/types';
import { useHttpClient } from '@wix/yoshi-flow-bm';

type ContactsFilters = {
  level: Filter<string[]>;
};

function ExportToCTAOutOfTheTable() {
  const httpClient = useHttpClient();

  const state = useTableCollection<Contact, ContactsFilters>({
    queryName: 'contacts-ExportToCTAOutOfTheTable',
    paginationMode: 'offset',
    itemKey: (item) => item.id as string,
    itemName: (item) => item.name as string,
    fetchData: (query: OffsetQuery<ContactsFilters>) => {
      const { limit, offset, search, filters } = query;
      return httpClient
        .request(
          queryContacts({
            query: { paging: { limit, offset }, filter: filters },
            search,
          }),
        )
        .then(({ data: { contacts = [], pagingMetadata } }) => ({
          items: contacts,
          total: pagingMetadata?.total,
        }));
    },
    fetchErrorMessage: () => 'Error fetching contacts',
    filters: {
      level: stringsArrayFilter({
        initialValue: ['Beginner'],
      }),
    },
    limit: 50,
  });

  const { table } = state;
  const { collection } = table;

  const exportConfig = useExportConfig<Contact, ContactsFilters>({
    saveAs: ({ wixPatternsQuery }) =>
      `Contacts [${wixPatternsQuery.filters.level?.join(', ')}]`,
    transformPlatformizedQuery: ({
      platformizedQuery,
      wixPatternsQuery,
      selectedItems,
    }) => {
      // TODO: add logic here
      return {
        ...platformizedQuery,
        paging: {
          limit: 20,
        },
      };
    },
    methodMetadata: {
      artifact: 'com.wixpress.fedinfra.exportservice.export-service',
      service: 'ExportService',
      method: 'QueryProductsExportSpi',
    },
    fields: [
      { id: 'contact.id', header: 'id' },
      { id: 'contact.info.name.first', header: 'First Name' },
      { id: 'contact.info.name.last', header: 'Last Name' },
      { id: 'contact.primary_info.email', header: 'Email' },
    ],
  });

  const levelsCollection = useStaticListFilterCollection(
    collection.filters.level,
    [
      'Beginner',
      'Amateur',
      'Semi-Pro',
      'Professional',
      'World Class',
      'Legendary',
      'Ultimate',
    ],
  );

  return (
    <PageWrapper>
      <Page height="400px">
        <Page.Header
          actionsBar={
            <Button onClick={() => table.exportState?.open()}>Export</Button>
          }
        />
        <Page.Content>
          <Table
            state={state}
            title={<ToolbarTitle title="title" showTotal />}
            columns={[
              {
                title: '',
                width: '50px',
                render: (contact) => (
                  <Avatar
                    name={contact.name}
                    imgProps={{ src: contact.image }}
                  />
                ),
              },
              {
                title: 'Name',
                width: '250px',
                render: (contact) => contact.name,
              },
              {
                title: 'Level',
                render: (contact) => contact.level,
              },
              {
                title: 'Last Seen',
                render: (contact) => contact.lastSeen?.toLocaleString(),
              },
            ]}
            filters={
              <CollectionToolbarFilters
                inline={1}
                panelTitle="Filter your contacts"
              >
                <MultiSelectCheckboxFilter
                  popoverProps={{ appendTo: 'window' }}
                  filter={collection.filters.level}
                  collection={levelsCollection}
                  renderItem={(level) => ({ title: level })}
                />
              </CollectionToolbarFilters>
            }
            exportModal={<ExportModal {...exportConfig} />}
          />
        </Page.Content>
      </Page>
    </PageWrapper>
  );
}
```

## API

### API

The `ExportTo` is a platformised solution for exporting lists of data.

It consists of two parts:

- **Client**: Configure the `exportButton` prop or the `exportModal` prop. `exportModal` provides you with the functionality to open an export modal using a custom CTA, and `exportButton` is a built-in CTA that opens an export modal.
- **Server**: All server related docs can be found [here](https://dev.wix.com/docs/rest/business-management/export/export-async-job-v1/integration)

#### Client `exportButton`

Add an `exportButton` prop to your `Table`, and pass an `ExportButton` component:

```jsx
//...
import { useExportConfig, Table } from '@wix/patterns';

const exportConfig = useExportConfig({
  /* ... */
});

export default () => {
  return (
    } />
  );
};
```

#### Client `exportModal`

Add an `exportModal` prop to your `Table`, and pass an `ExportModal` component.
To open the modal use `table` from `useTableCollection` hook as `table.exportState.open()`

```jsx
//...
import React from 'react';
import { useExportConfig, useTableCollection, Table } from '@wix/patterns';
import { Button } from '@wix/design-system';

const state = useTableCollection({ /* ... */ });
const exportConfig = useExportConfig({
  /* ... */
});

export default () => {
  return (
      <>
         state.table.exportState.open()}>
        } />
      
  );
};
```

See example and API tab for more details.


### transformPlatformizedQuery

The `transformPlatformizedQuery` is used for mapping between the `wixPatternsQuery` to `QueryV2`, which is the standard way to fetch data from the API/SPI server.

For example, in case of stores' `Product`:

```ts
const exportStateQueryProductsExportSpi = useExport({
  transformPlatformizedQuery: ({
    platformizedQuery,
    wixPatternsQuery,
    selectedItems,
  }) => {
    const {
      filters: { collections, stockStatus: [stockStatus = undefined] = [] },
    } = wixPatternsQuery;
    // In case the user chose to export selected items
    if (selectedIds && selectedIds.length) {
      // Filter by selectedIds
      platformizedQuery.filter = {
        includeHidden: true,
        value: JSON.stringify({
          id: { $hasSome: selectedIds },
        }),
      };
    } else {
      // In case the user chose to export filters
      platformizedQuery.filter = {
        includeHidden: true,
        value: JSON.stringify({
          // filter by collection IDs
          ...(collections
            ? {
                'collections.id': { $hasSome: collections.map((c) => c.id) },
              }
            : {}),
          // filter by stockStatus
          ...(stockStatus
            ? {
                inventoryStatus: stockStatus.id,
              }
            : {}),
        }),
      };
    }

    return {
      ...platformizedQuery,
      paging: {
        limit: 20,
      },
    };
  },
});
```


### Props

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `transformPlatformizedQuery` | `TransformQuery<T, F>` | No | - | A function to transform the cairo query to a QueryV2 object (which will be used to fetch data from the server): - `platformizedQuery`: QueryV2 - `wixPatternsQuery`: ComputedQueryFull<F> - `selectedItems?`: string[] - `uncheckedValues?`: T[] - `isSelectAll`: boolean The function should return a QueryV2 instance or a promise of QueryV2 |
| `differentQueryEndpointThanCollection` | `boolean` | No | - | When set to `true`, the export progress will not show total / out of items. |
| `customTotal` | `CustomTotalFn<T, F>` | No | - | A function that returns the number of total items in the export, to show in the progress bar. Use this option when the export has a different total than the collection itself. For example: table is showing products, but the export includes also variants. The function accepts the same arguments as `transformPlatformizedQuery`, with the following modifications: - `platformizedQuery` is already the transformed QueryV2 returned from `transformPlatformizedQuery` - `collectionTotalPromise` - A promise that resolves to the `total` of the underlying table collection. |
| `methodMetadata` | `MethodMetadata` | Yes | - | The target endpoint to query data from. This endpoint must be verified to be compatible with export-service first, see [server side docs](https://dev.wix.com/docs/rest/business-management/export/export-async-job-v1/integration) - `artifact: string` - `service: string` - `method: string` |
| `arrayFieldDelimiter` | `"SEMICOLON" \| "SEMICOLON_AND_SPACE"` | No | `SEMICOLON` | The delimiter to use for array fields |
| `methodSpec` | `{ requestQueryFieldNumber?: "DEFAULT" \| "FIELD_2" \| "FIELD_3" \| "FIELD_4" \| "FIELD_5" \| "FIELD_6" \| "FIELD_7" \| "FIELD_8" \| "FIELD_9"; responsePagingMetadataFieldName?: string \| ... 1 more ...; responseRepeatedFieldName?: string \| ... 1 more ... \| undefined; } \| undefined` | No | - | Additional endpoint possible variations `requestQueryFieldNumber?: number` - The field number of the request query field. The default is field number = 1 `responseRepeatedFieldName: string \| null` - The name of the response repeated field, i.e items/contacts/products etc. (required) `responsePagingMetadataFieldName?: string \| null` - The name of the response PagingMetadata field (default=paging_metadata) |
| `fields` | `FieldDescriptor[]` | Yes | - | Translated CSV headers - `id?`: string; The path to the field out of the query response items. You can ask your BED team to create a list of available paths by running this [Scala script](https://bo.wix.com/wix-docs/rest/drafts/exportservice/integration#drafts_exportservice_integration_fields). - `header?`: string; How to present the filed in the CSV headers (translated). |
| `saveAs` | `SaveAsFn<T, F>` | No | - | Optional function to configure the download file name: - `platformizedQuery`: QueryV2 - `wixPatternsQuery`: ComputedQueryFull<F> - `selectedItems?`: string[] - `uncheckedValues?`: T[] The function should return a string |
| `exportModalFooter` | `{ text: string; }` | No | - | Optional footer for export modal `text`: string |
| `exportModalTitle` | `string` | No | - | Optional custom title for the items to export |
| `onProgressModalTitle` | `string` | No | - | Optional custom title during the export process |
| `exportToCSVMessage` | `string` | No | - | Optional custom message for the items that will be exported to CSV |

## BI

### Export To Events

 Event   |   Description   |
--------- | --------------- |
[144:125](https://bo.wix.com/data-tools/bi-catalog-app/event/144:125) | Sent when a user clicks the "Export" CTA in a Wix Patterns component
[144:126](https://bo.wix.com/data-tools/bi-catalog-app/event/144:126) | Sent when user changes selection in the Wix Patterns export modal
[144:127](https://bo.wix.com/data-tools/bi-catalog-app/event/144:127) | Sent when the user clicks any CTA in the export modal
[144:128](https://bo.wix.com/data-tools/bi-catalog-app/event/144:128) | Sent when the export process begins
[144:129](https://bo.wix.com/data-tools/bi-catalog-app/event/144:129) | Sent when the user tries to cancel the export process AFTER it has begun
[144:130](https://bo.wix.com/data-tools/bi-catalog-app/event/144:130) | Sent when the user clicks any of the CTAs in the "Cancel the export?" modal
[144:131](https://bo.wix.com/data-tools/bi-catalog-app/event/144:131) | Sent when the export process ends, either successfully or not (failed/stopped by user)
[144:132](https://bo.wix.com/data-tools/bi-catalog-app/event/144:132) | Sent when the export ends successfully and the user is prompted that the file is being downloaded
[144:133](https://bo.wix.com/data-tools/bi-catalog-app/event/144:133) | Sent when the toast that tells the user that the export is done and the file is being downloaded is dismissed (by user or automatically)
[144:134](https://bo.wix.com/data-tools/bi-catalog-app/event/144:134) | Sent when the user clicks the "Download Manually" button in the toast that is displayed after the export process is complete
[144:135](https://bo.wix.com/data-tools/bi-catalog-app/event/144:135) | Sent when the user clicks a CTA in the "Export Failed" modal



### Component load events
Event   |   Description   |
--------- | --------------- |
[144:110](https://bo.wix.com/data-tools/bi-catalog-app/event/144:110) | Sent when a Wix Patterns component starts loading
[144:111](https://bo.wix.com/data-tools/bi-catalog-app/event/144:111) | Sent when a Wix Patterns component is done loading


#### 🐪 Couldn't find what you need?
* Check our [BI Catalog](https://bo.wix.com/data-tools/bi-catalog-app?viewId=all-items-view&selectedColumns=src%2Cevid%2Cname%2Cowner%2Cproduct%2CuserType+false%2CdateUpdated%2CdateCreated+false%2CcreatedBy+false%2Cstatus&source=%5B%7B%22id%22%3A%22144%22%2C%22name%22%3A%22144+-+Cairo%22%7D%5D)
* Contact us on [#cairo-bi](https://wix.slack.com/archives/C03N53KURH9)


## Testkit

### Usage

`getExportButton` API is exposed from the `` [testkit](./?path=/story/components-collection--table&activeTab=Testkit)

### Export `HttpClient` Mocks

#### BM Flow

When using `Flow BM` testkit, use the [wixPatternsTestProviderPropsOverrides](./?path=/story/testing-component-tests--component-tests#TableTestDriver.ts) Wix Patterns helper for injecting all relevant mocks.

#### Manually

For manually adding mocks:

```ts
import { exportServiceMocks } from '@wix/patterns/testkit';
import { HttpClientMock, whenRequest } from '@wix/http-client-testkit';

const httpClient = new HttpClientMock([...exportServiceMocks(whenRequest)]);
```


