hunk.code_window:   POST_BODY_FORMAT_OPTIONS,
     REST_PLUGIN_PACKAGE_NAME,
     POST_BODY_FORMATS,
     CONTENT_TYPE,
     PLUGIN_TYPE_API,
   } from "constants/ApiEditorConstants";
   import history from "utils/history";
   import {
  
hunk.labels: keep keep keep keep replace keep keep keep
hunk.file_path: app/client/src/sagas/ApiPaneSagas.ts
hunk.type: replace
file: import React from "react";
  import { connect } from "react-redux";
  import { RouteComponentProps, withRouter } from "react-router";
  import styled from "styled-components";
  import { AppState } from "reducers";
  import { APIEditorRouteParams } from "constants/routes";
  import { Spinner, IIconProps } from "@blueprintjs/core";
  import { BaseTextInput } from "components/designSystems/appsmith/TextInputComponent";
  import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
  import Fuse from "fuse.js";
  import Button from "components/editorComponents/Button";
  import {
    DragDropContext,
    Draggable,
    DragStart,
    Droppable,
    DropResult,
  } from "react-beautiful-dnd";
  import { PageListPayload } from "constants/ReduxActionConstants";
  import TreeDropdown from "components/editorComponents/actioncreator/TreeDropdown";
  import { theme } from "constants/DefaultTheme";
  import { Colors } from "constants/Colors";
  import { ControlIcons } from "icons/ControlIcons";
  
  const LoadingContainer = styled(CenteredWrapper)`
    height: 50%;
  `;
  
  const Wrapper = styled.div`
    height: 100%;
    width: 100%;
    flex-direction: column;
  `;
  
  const Controls = styled.div`
    padding: 10px;
  `;
  
  const SearchBar = styled(BaseTextInput)`
    margin-bottom: 10px;
    input {
      background-color: #23292e;
      border: none;
      color: ${(props) => props.theme.colors.textOnDarkBG}
      :focus {
        background-color: #23292e;
      }
    }
    .bp3-icon {
      background-color: #23292e;
    }
  `;
  
  const PageContainer = styled.div`
    padding: 5px 0;
  `;
  
  const PageName = styled.h5<{ isMain: boolean }>`
    display: block;
    width: 100%;
    height: 20px;
    padding-left: 5px;
    font-size: 16px;
    color: white;
    border-right: 4px solid;
    margin: 10px 0;
    border-color: ${(props) =>
      props.isMain ? props.theme.colors.primaryOld : "transparent"};
  `;
  
  const PageDropContainer = styled.div`
    min-height: 32px;
    margin: 5px;
    background-color: ${(props) => props.theme.colors.paneBG};
  
    .createBtn {
      border: none;
      color: ${Colors.WHITE} !important;
      width: 100%;
      display: block !important;
      font-weight: normal;
      font-size: 14px;
      line-height: 20px;
  
      &:hover {
        color: ${Colors.WHITE} !important;
        background-color: ${Colors.BLUE_CHARCOAL} !important;
  
        svg {
          path {
            fill: ${Colors.WHITE};
          }
        }
      }
      &:focus {
        color: ${Colors.WHITE} !important;
        background-color: ${Colors.BLUE_CHARCOAL} !important;
  
        svg {
          path {
            fill: ${Colors.WHITE};
          }
        }
      }
    }
    .highlightButton {
      color: ${Colors.WHITE} !important;
      background-color: ${Colors.BLUE_CHARCOAL} !important;
      width: 100%;
      display: block !important;
      font-weight: normal;
      font-size: 14px;
      line-height: 20px;
  
      svg {
        path {
          fill: ${Colors.WHITE};
        }
      }
    }
  
    .linkStyles {
      text-decoration: none !important;
    }
  `;
  
  const ItemsWrapper = styled.div`
    flex: 1;
  `;
  
  const NoItemMessage = styled.div`
    color: #d0d7dd;
    padding-left: 12px;
    padding-top: 23px;
    font-size: 14px;
    line-height: 20px;
    padding-bottom: 10px;
  `;
  
  const ItemContainer = styled.div<{
    isSelected: boolean;
    isDraggingOver: boolean;
    isBeingDragged: boolean;
  }>`
    height: 32px;
    width: 100%;
    padding: 8px 12px;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
    margin-bottom: 2px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    background-color: ${(props) =>
      props.isSelected || props.isBeingDragged
        ? props.theme.colors.paneCard
        : props.theme.colors.paneBG};
    :hover {
      background-color: ${(props) =>
        props.isDraggingOver
          ? props.theme.colors.paneBG
          : props.theme.colors.paneCard};
    }
  `;
  
  const StyledAddButton = styled(Button)<IIconProps>`
    &&& {
      outline: none;
  
      padding: 10px !important;
    }
    span {
      font-weight: normal !important;
    }
  `;
  
  interface ReduxStateProps {
    pages: PageListPayload;
  }
  
  type Item = { id: string; name: string; pageId: string };
  type PageWiseList = Array<{ name: string; id: string; items: Item[] }>;
  
  type EditorSidebarComponentProps = {
    isLoading: boolean;
    list: Array<Item>;
    selectedItemId?: string;
    itemRender: (item: any) => JSX.Element;
    onItemCreateClick: (pageId: string) => void;
    onItemSelected: (itemId: string, itemPageId: string) => void;
    moveItem: (itemId: string, destinationPageId: string) => void;
    copyItem: (itemId: string, destinationPageId: string) => void;
    deleteItem: (itemId: string, itemName: string, pageName: string) => void;
    createButtonTitle: string;
  };
  
  type Props = ReduxStateProps &
    RouteComponentProps<APIEditorRouteParams> &
    EditorSidebarComponentProps;
  
  type State = {
    search: string;
    itemDraggingFrom: string;
    itemDragging: string;
  };
  
  const FUSE_OPTIONS = {
    shouldSort: true,
    threshold: 0.5,
    location: 0,
    minMatchCharLength: 3,
    findAllMatches: true,
    keys: ["name"],
  };
  
  class EditorSidebar extends React.Component<Props, State> {
    constructor(props: Props) {
      super(props);
      this.state = {
        search: "",
        itemDraggingFrom: "",
        itemDragging: "",
      };
    }
  
    handleSearchChange = (e: React.ChangeEvent<{ value: string }>) => {
      const value = e.target.value;
      this.setState({
        search: value,
      });
    };
  
    handleItemSelect = (itemId: string, itemPageId: string) => {
      this.props.onItemSelected(itemId, itemPageId);
    };
  
    onDragEnd = (result: DropResult) => {
      this.setState({
        itemDraggingFrom: "",
        itemDragging: "",
      });
      if (
        result.destination &&
        result.source.droppableId !== result.destination.droppableId
      ) {
        this.props.moveItem(result.draggableId, result.destination.droppableId);
      }
    };
  
    onDragStart = (result: DragStart) => {
      const draggingFrom = result.source.droppableId;
      this.setState({
        itemDraggingFrom: draggingFrom,
        itemDragging: result.draggableId,
      });
    };
  
    getSearchFilteredList = () => {
      const { search } = this.state;
      const { list } = this.props;
      const fuse = new Fuse(list, FUSE_OPTIONS);
      return search ? fuse.search(search) : list;
    };
  
    getPageWiseList = (items: Item[]): PageWiseList => {
      const {
        match: {
          params: { pageId },
        },
        pages,
      } = this.props;
      pages.sort((x, y) =>
        x.pageId === pageId ? -1 : y.pageId === pageId ? 1 : 0,
      );
      return pages.map((page) => {
        return {
          id: page.pageId,
          name: page.pageName,
          items: [...items.filter((item) => item.pageId === page.pageId)].sort(
            (a, b) => {
              const name1 = a.name.toLowerCase();
              const name2 = b.name.toLowerCase();
              if (name1 < name2) return -1;
              if (name1 > name2) return 1;
              return 0;
            },
          ),
        };
      });
    };
  
    handleCreateNew = (pageId: string) => {
      this.props.onItemCreateClick(pageId);
    };
  
    render() {
      const {
        isLoading,
        itemRender,
        selectedItemId,
        location,
        createButtonTitle,
      } = this.props;
  
      const { search } = this.state;
      const filteredList = this.getSearchFilteredList();
      const pageWiseList = this.getPageWiseList(filteredList);
      const destinationPageId = new URLSearchParams(location.search).get(
        "importTo",
      );
  
      return (
        <React.Fragment>
          {isLoading ? (
            <LoadingContainer>
              <Spinner size={30} />
            </LoadingContainer>
          ) : (
            <Wrapper>
              <ItemsWrapper>
                <Controls>
                  <SearchBar
                    icon="search"
                    input={{
                      value: search,
                      onChange: this.handleSearchChange,
                    }}
                    placeholder="Search"
                  />
                </Controls>
                <DragDropContext
                  onDragStart={this.onDragStart}
                  onDragEnd={this.onDragEnd}
                >
                  <React.Fragment>
                    {pageWiseList.map((page, i) => {
                      return (
                        <PageContainer key={page.id}>
                          <PageName isMain={i === 0}>{page.name}</PageName>
                          <Droppable
                            droppableId={page.id}
                            type="API"
                            isDropDisabled={
                              page.id === this.state.itemDraggingFrom
                            }
                          >
                            {(provided, snapshot) => (
                              <PageDropContainer
                                ref={provided.innerRef}
                                {...provided.droppableProps}
                              >
                                {provided.placeholder}
                                <div>
                                  <StyledAddButton
                                    text={createButtonTitle}
                                    icon="plus"
                                    fluid
                                    className={
                                      destinationPageId === page.id
                                        ? "highlightButton"
                                        : "createBtn"
                                    }
                                    style={{ padding: "10px" }}
                                    onClick={() => this.handleCreateNew(page.id)}
                                  />
                                  {page.items.length === 0 && (
                                    <NoItemMessage>
                                      {"No APIs on this page yet"}
                                    </NoItemMessage>
                                  )}
                                  {page.items.map((item: Item, index) => (
                                    <Draggable
                                      key={item.id}
                                      draggableId={item.id}
                                      index={index}
                                    >
                                      {(provided) => (
                                        <ItemContainer
                                          isSelected={item.id === selectedItemId}
                                          isDraggingOver={snapshot.isDraggingOver}
                                          isBeingDragged={
                                            this.state.itemDragging === item.id
                                          }
                                          ref={provided.innerRef}
                                          {...provided.draggableProps}
                                          {...provided.dragHandleProps}
                                          onClick={() =>
                                            this.handleItemSelect(
                                              item.id,
                                              item.pageId,
                                            )
                                          }
                                        >
                                          {itemRender(item)}
                                          {this.state.itemDragging !==
                                            item.id && (
                                            <React.Fragment>
                                              <TreeDropdown
                                                defaultText=""
                                                onSelect={() => {
                                                  return null;
                                                }}
                                                selectedValue=""
                                                optionTree={[
                                                  {
                                                    value: "copy",
                                                    onSelect: () => null,
                                                    label: "Copy to",
                                                    children: pageWiseList.map(
                                                      (p) => ({
                                                        label: p.name,
                                                        id: p.id,
                                                        value: p.name,
                                                        onSelect: () =>
                                                          this.props.copyItem(
                                                            item.id,
                                                            p.id,
                                                          ),
                                                      }),
                                                    ),
                                                  },
                                                  {
                                                    value: "move",
                                                    onSelect: () => null,
                                                    label: "Move to",
                                                    children: pageWiseList
                                                      .filter(
                                                        (p) => p.id !== page.id,
                                                      )
                                                      .map((p) => ({
                                                        label: p.name,
                                                        id: p.id,
                                                        value: p.name,
                                                        onSelect: () =>
                                                          this.props.moveItem(
                                                            item.id,
                                                            p.id,
                                                          ),
                                                      })),
                                                  },
                                                  {
                                                    value: "delete",
                                                    onSelect: () =>
                                                      this.props.deleteItem(
                                                        item.id,
                                                        item.name,
                                                        page.name,
                                                      ),
                                                    label: "Delete",
                                                    intent: "danger",
                                                  },
                                                ]}
                                                toggle={
                                                  <ControlIcons.MORE_HORIZONTAL_CONTROL
                                                    width={theme.fontSizes[4]}
                                                    height={theme.fontSizes[4]}
                                                  />
                                                }
                                              />
                                            </React.Fragment>
                                          )}
                                        </ItemContainer>
                                      )}
                                    </Draggable>
                                  ))}
                                </div>
                              </PageDropContainer>
                            )}
                          </Droppable>
                        </PageContainer>
                      );
                    })}
                  </React.Fragment>
                </DragDropContext>
              </ItemsWrapper>
            </Wrapper>
          )}
        </React.Fragment>
      );
    }
  }
  
  const mapStateToProps = (state: AppState): ReduxStateProps => ({
    pages: state.entities.pageList.pages,
  });
  
  export default withRouter(connect(mapStateToProps)(EditorSidebar));
  