@ant-design/icons#DatabaseFilled TypeScript Examples

The following examples show how to use @ant-design/icons#DatabaseFilled. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: any-brick.editor.tsx    From next-basics with GNU General Public License v3.0 5 votes vote down vote up
export function AnyBrickEditor({
  nodeUid,
}: EditorComponentProps): React.ReactElement {
  const node = useBuilderNode({ nodeUid });
  const mountPoints = useBuilderNodeMountPoints({ nodeUid });

  let icon: JSX.Element;
  let displayType = DisplayType.DEFAULT;

  if (node.type === "provider" || node.bg) {
    displayType = DisplayType.PROVIDER;
    icon = <DatabaseFilled />;
  } else if (node.type === "template") {
    displayType = DisplayType.TEMPLATE;
    icon = <GoldenFilled />;
  } else if (node.portal) {
    displayType = DisplayType.PORTAL;
    icon = <MessageFilled />;
  }

  return (
    <EditorContainer nodeUid={nodeUid}>
      <div
        className={classNames(
          styles.wrapper,
          styles[displayType],
          mountPoints.length > 0 ? styles.hasChildren : styles.noChildren,
          {
            [styles.isExpandableTemplate]: node.$$isExpandableTemplate,
          }
        )}
      >
        {mountPoints.length > 0 ? (
          mountPoints.map((mountPoint) => (
            <SlotContainer
              key={mountPoint}
              nodeUid={nodeUid}
              slotName={mountPoint}
            />
          ))
        ) : (
          <>
            {icon && <div className={styles.icon}>{icon}</div>}
            <div className={styles.name}>{node.alias}</div>
          </>
        )}
      </div>
    </EditorContainer>
  );
}
Example #2
Source File: ExportToExcelActionBar.tsx    From condo with MIT License 5 votes vote down vote up
ExportToExcelActionBar: React.FC<IExportToExcelActionBarProps> = (props) => {
    const {
        searchObjectsQuery,
        sortBy,
        exportToExcelQuery,
        hidden = false,
        useTimeZone = true,
        disabled = false,
    } = props

    const intl = useIntl()
    const ExportAsExcelLabel = intl.formatMessage({ id: 'ExportAsExcel' })
    const timeZone = intl.formatters.getDateTimeFormat().resolvedOptions().timeZone

    const [
        exportToExcel,
        { loading: isXlsLoading },
    ] = useLazyQuery(
        exportToExcelQuery,
        {
            onError: error => {
                const message = get(error, ['graphQLErrors', 0, 'extensions', 'messageForUser']) || error.message
                notification.error({ message })
            },
            onCompleted: data => {
                if (window) {
                    window.location.href = data.result.linkToFile
                }
            },
        },
    )

    const variablesData = {
        dv: 1,
        sender: getClientSideSenderInfo(),
        where: searchObjectsQuery,
        sortBy: sortBy,
        timeZone: undefined,
    }
    const deps = [exportToExcel, searchObjectsQuery, sortBy, variablesData]

    if (useTimeZone) {
        variablesData.timeZone = timeZone
        deps.push(timeZone)
    }

    const handleExportToExcel = useCallback(() => {
        exportToExcel({ variables: { data: variablesData } })
    }, deps)

    return (
        <Form.Item noStyle>
            <ActionBar hidden={hidden}>
                <Button
                    type={'sberBlack'}
                    secondary
                    icon={<DatabaseFilled/>}
                    loading={isXlsLoading}
                    onClick={handleExportToExcel}
                    disabled={disabled}
                >
                    {ExportAsExcelLabel}
                </Button>
            </ActionBar>
        </Form.Item>
    )
}
Example #3
Source File: BrickItem.spec.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
describe("BrickItem", () => {
  afterEach(() => {
    jest.clearAllMocks();
  });

  it("should display a brick", () => {
    const dragRef = jest.fn();
    mockUseDrag.mockReturnValueOnce([{ isDragging: false }, dragRef]);
    const mockOnDraggingChange = jest.fn();
    const wrapper = mount(
      <BrickItem
        brick={{
          type: "brick",
          id: "my.awesome-brick",
          title: "awesome-brick",
          description: "My awesome brick",
        }}
        onDraggingChange={mockOnDraggingChange}
      />
    );
    expect(wrapper.find(".brickItem").hasClass("brick")).toBe(true);
    expect(wrapper.find(".brickItem").prop("title")).toBe("My awesome brick");
    expect(wrapper.find(BuildFilled).length).toBe(1);
    expect(wrapper.find(".brickName").text()).toBe("awesome-brick");
    expect(mockUseDrag).toBeCalledWith(
      expect.objectContaining({
        item: {
          type: BuilderDataTransferType.NODE_TO_ADD,
          brickType: undefined,
          brick: "my.awesome-brick",
        },
      })
    );
    expect(mockOnDraggingChange).toBeCalledWith(false);
  });

  it("should display a provider", () => {
    const dragRef = jest.fn();
    mockUseDrag.mockReturnValueOnce([{ isDragging: false }, dragRef]);
    const wrapper = shallow(
      <BrickItem
        brick={{
          type: "provider",
          id: "my.awesome-provider",
          title: "awesome-provider",
        }}
      />
    );
    expect(wrapper.find(".brickItem").hasClass("provider")).toBe(true);
    expect(wrapper.find(".brickItem").prop("title")).toBe("awesome-provider");
    expect(wrapper.find(DatabaseFilled).length).toBe(1);
    expect(wrapper.find(".brickName").text()).toBe("awesome-provider");
    expect(mockUseDrag).toBeCalledWith(
      expect.objectContaining({
        item: {
          type: BuilderDataTransferType.NODE_TO_ADD,
          brickType: "provider",
          brick: "my.awesome-provider",
        },
      })
    );
  });

  it("should display a legacy template", () => {
    const dragRef = jest.fn();
    mockUseDrag.mockReturnValueOnce([{ isDragging: false }, dragRef]);
    const wrapper = shallow(
      <BrickItem
        brick={{
          type: "template",
          id: "my.awesome-template",
          title: "awesome-template",
        }}
      />
    );
    expect(wrapper.find(".brickItem").hasClass("template")).toBe(true);
    expect(wrapper.find(GoldenFilled).length).toBe(1);
    expect(wrapper.find(".brickName").text()).toBe("awesome-template");
    expect(mockUseDrag).toBeCalledWith(
      expect.objectContaining({
        item: {
          type: BuilderDataTransferType.NODE_TO_ADD,
          brickType: "template",
          brick: "my.awesome-template",
        },
      })
    );
  });

  it("should display a custom template", () => {
    const dragRef = jest.fn();
    mockUseDrag.mockReturnValueOnce([{ isDragging: false }, dragRef]);
    const wrapper = shallow(
      <BrickItem
        brick={{
          type: "customTemplate",
          id: "my.awesome-custom-template",
          title: "awesome-custom-template",
        }}
      />
    );
    expect(wrapper.find(".brickItem").hasClass("customTemplate")).toBe(true);
    expect(wrapper.find(CopyFilled).length).toBe(1);
    expect(wrapper.find(".brickName").text()).toBe("awesome-custom-template");
    expect(mockUseDrag).toBeCalledWith(
      expect.objectContaining({
        item: {
          type: BuilderDataTransferType.NODE_TO_ADD,
          brickType: undefined,
          brick: "my.awesome-custom-template",
        },
      })
    );
  });

  it("should display a snippet", () => {
    const dragRef = jest.fn();
    mockUseDrag.mockReturnValueOnce([{ isDragging: false }, dragRef]);
    const wrapper = shallow(
      <BrickItem
        brick={{
          type: "snippet",
          id: "my.snippet",
          title: "My Snippet",
          bricks: [
            {
              brick: "easy-view",
            },
          ],
          thumbnail: "test.svg",
        }}
      />
    );
    expect(wrapper.find(".brickItem").hasClass("snippet")).toBe(true);
    expect(wrapper.find(".brickIcon img").prop("src")).toBe("test.svg");
    expect(wrapper.find(NumberOutlined).length).toBe(0);
    expect(wrapper.find(".brickName").text()).toBe("My Snippet");
    expect(mockUseDrag).toBeCalledWith(
      expect.objectContaining({
        item: {
          type: BuilderDataTransferType.SNIPPET_TO_APPLY,
          bricks: [
            {
              brick: "easy-view",
            },
          ],
        },
      })
    );
  });

  it("should display a snippet without thumbnail", () => {
    const dragRef = jest.fn();
    mockUseDrag.mockReturnValueOnce([{ isDragging: false }, dragRef]);
    const wrapper = shallow(
      <BrickItem
        brick={{
          type: "snippet",
          id: "my.snippet",
          title: "My Snippet",
          bricks: [
            {
              brick: "easy-view",
            },
          ],
        }}
      />
    );
    expect(wrapper.find(".brickItem").hasClass("snippet")).toBe(true);
    expect(wrapper.find(NumberOutlined).length).toBe(1);
    expect(wrapper.find(".brickIcon img").length).toBe(0);
  });

  it("should render icon", () => {
    const dragRef = jest.fn();
    mockUseDrag.mockReturnValueOnce([{ isDragging: false }, dragRef]);
    const wrapper = shallow(
      <BrickItem
        brick={{
          category: "form-input",
          icon: {
            lib: "fa",
            icon: "abacus",
          },
          type: "brick",
          id: "my.awesome-brick",
          title: "awesome-brick",
        }}
      />
    );
    expect(wrapper.find(GeneralIcon).prop("icon")).toEqual({
      icon: "abacus",
      lib: "fa",
    });
  });

  it("should show thumbnail while layerType was widget", () => {
    const dragRef = jest.fn();
    mockUseDrag.mockReturnValueOnce([{ isDragging: false }, dragRef]);
    const wrapper = shallow(
      <BrickItem
        brick={{
          type: "brick",
          id: "widget-project.my-widget",
          title: "my-widget",
          thumbnail: "xxx.png",
        }}
        layerType={LayerType.WIDGET}
      />
    );

    expect(wrapper.find(".brickIcon img").prop("src")).toBe("xxx.png");
  });

  it("should show BuildFilled while layType was widget and thumbnail was null", () => {
    const dragRef = jest.fn();
    mockUseDrag.mockReturnValueOnce([{ isDragging: false }, dragRef]);
    const wrapper = shallow(
      <BrickItem
        brick={{
          type: "brick",
          id: "widget-project.my-widget",
          title: "my-widget",
          thumbnail: null,
        }}
        layerType={LayerType.WIDGET}
      />
    );

    expect(wrapper.find(BuildFilled).length).toBe(1);
  });
});
Example #4
Source File: BrickItem.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
export function BrickItem({
  brick,
  onDraggingChange,
  layerType,
}: BrickItemProps): React.ReactElement {
  let brickType: string;
  switch (brick.type) {
    case "provider":
    case "template":
      brickType = brick.type;
    // `customTemplate` will be treated as `brick`.
  }

  const transferItem =
    brick.type === "snippet"
      ? {
          type: BuilderDataTransferType.SNIPPET_TO_APPLY,
          bricks: brick.bricks,
        }
      : {
          type: BuilderDataTransferType.NODE_TO_ADD,
          brickType,
          brick: brick.id,
        };

  const [{ isDragging }, dragRef] = useDrag({
    item: transferItem,
    options: {
      dropEffect: "copy",
    },
    collect: /* istanbul ignore next */ (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  });

  useEffect(() => {
    onDraggingChange?.(isDragging);
  }, [isDragging, onDraggingChange]);

  let icon: JSX.Element;

  if (brick.icon) {
    icon = <GeneralIcon icon={brick.icon} />;
  } else if (layerType === "widget") {
    icon = brick.thumbnail ? (
      <img
        style={{
          width: "auto",
          height: "100%",
        }}
        src={brick.thumbnail}
      />
    ) : (
      <BuildFilled />
    );
  } else {
    switch (brick.type) {
      case "provider":
        icon = <DatabaseFilled />;
        break;
      case "template":
        icon = <GoldenFilled />;
        break;
      case "customTemplate":
        icon = (
          <CopyFilled
            className={classNames({
              [styles.thumbnailType]: layerType !== LayerType.BRICK,
            })}
          />
        );
        break;
      case "snippet":
        icon = brick.thumbnail ? (
          <img src={brick.thumbnail} />
        ) : (
          <NumberOutlined
            className={classNames({
              [styles.thumbnailType]: layerType !== LayerType.BRICK,
            })}
          />
        );
        break;
      default:
        icon = <BuildFilled />;
    }
  }

  return (
    <div
      className={`${styles.brickItem} ${styles[brick.type]} ${
        styles[`layer-${layerType ?? LayerType.BRICK}`]
      }`}
      title={brick.description || brick.title}
      ref={dragRef}
    >
      <span className={styles.brickIcon}>{icon}</span>
      <span className={styles.brickName}>{brick.title}</span>
    </div>
  );
}
Example #5
Source File: StoryboardTreeNode.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
export function StoryboardTreeNode({
  nodeUid,
  mountPoint,
  level,
}: StoryboardTreeNodeProps): React.ReactElement {
  const node = useBuilderNode({ nodeUid });
  const { highlightNodes } = useBuilderUIContext();
  const hoverNodeUid = useHoverNodeUid();
  const mountPoints = useBuilderNodeMountPoints({
    nodeUid,
    doNotExpandTemplates: true,
  });
  const parentNode = useBuilderParentNode(nodeUid);
  const siblingGroups = useBuilderGroupedChildNodes({
    nodeUid: parentNode.$$uid,
    doNotExpandTemplates: true,
  });
  const manager = useBuilderDataManager();
  const canDrop = useCanDrop();
  const contextMenuStatus = useBuilderContextMenuStatus();
  const outlineApplicable = node.brick === "basic-bricks.easy-view";
  const outlineEnabled = useOutlineEnabled(node.instanceId, !outlineApplicable);

  const handleClick = useCallback(() => {
    manager.nodeClick(node);
  }, [manager, node]);

  const hover = useMemo(
    () => hoverNodeUid === nodeUid,
    [hoverNodeUid, nodeUid]
  );

  const [{ isDragging }, dragRef, draggingPreviewRef] = useDrag({
    item: {
      type: StoryboardTreeTransferType.NODE,
      nodeUid,
      nodeId: node.id,
      nodeInstanceId: node.instanceId,
      nodeType: node.type,
    },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  });

  const [{ isDraggingOverCurrent }, dropRef] = useDrop({
    accept: StoryboardTreeTransferType.NODE,
    canDrop: (item: DraggingNodeItem) =>
      canDrop(item.nodeUid, nodeUid) &&
      (Number(isRouteNode(node)) ^
        Number(isRouteNode({ type: item.nodeType } as any))) ===
        0,
    collect: (monitor) => ({
      isDraggingOverCurrent: monitor.isOver() && monitor.canDrop(),
    }),
    drop: (item, monitor) => {
      if (!monitor.didDrop()) {
        let droppingIndex = -1;
        for (const group of siblingGroups) {
          droppingIndex = group.childNodes.findIndex(
            (n) => n.$$uid === nodeUid
          );
          if (droppingIndex > -1) {
            // When dropping a node on another node,
            // we say it drops *under* the target node.
            // So add `droppingIndex` by 1.
            droppingIndex += 1;
            break;
          }
        }
        handleDropOnNode({
          draggingItem: item,
          droppingMountPoint: mountPoint,
          droppingParentNode: parentNode,
          droppingSiblingGroups: siblingGroups,
          droppingIndex,
          manager,
        });
      }
    },
  });

  const handleContextMenu = useCallback(
    (event: React.MouseEvent) => {
      event.preventDefault();
      manager.contextMenuChange({
        active: true,
        node,
        x: event.clientX,
        y: event.clientY,
      });
    },
    [manager, node]
  );

  let icon: JSX.Element;
  let displayType = DisplayType.DEFAULT;

  if (node.type === "provider" || node.bg) {
    displayType = DisplayType.PROVIDER;
    icon = <DatabaseFilled />;
  } else if (node.portal) {
    displayType = DisplayType.PORTAL;
    icon = <MessageFilled />;
  } else if (isRouteNode(node)) {
    displayType = DisplayType.ROUTE;
    icon = <BranchesOutlined />;
  }

  const handleMouseEnter = useCallback((): void => {
    const prevUid = manager.getHoverNodeUid();
    if (prevUid !== node.$$uid) {
      manager.setHoverNodeUid(node.$$uid);
    }
  }, [manager, node]);

  const handleMouseLeave = useCallback((): void => {
    const prevUid = manager.getHoverNodeUid();
    if (prevUid === node.$$uid) {
      manager.setHoverNodeUid(undefined);
    }
  }, [manager, node]);

  const handleOutlineToggle = useCallback(
    (event: React.MouseEvent) => {
      event.stopPropagation();
      manager.toggleOutline(node.instanceId);
    },
    [manager, node]
  );

  return (
    <li
      className={classNames(
        styles.treeNode,
        {
          [styles.dragging]: isDragging,
          [styles.draggingNodeOverCurrent]: isDraggingOverCurrent,
        },
        styles[displayType]
      )}
      ref={draggingPreviewRef}
    >
      <div
        className={classNames(styles.nodeNameWrapper, {
          [styles.highlightNode]: highlightNodes.has(nodeUid),
          [styles.nodeNameWrapperHover]:
            hover ||
            (contextMenuStatus.active &&
              contextMenuStatus.node.$$uid === nodeUid),
        })}
        style={{
          paddingLeft: level * treeViewPaddingUnit,
        }}
        onClick={handleClick}
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
        onContextMenu={handleContextMenu}
        ref={(node) => dragRef(dropRef(node))}
      >
        {icon && <div className={styles.icon}>{icon}</div>}
        <div className={styles.nodeName} title={node.alias}>
          {node.alias}
        </div>
        {outlineApplicable && (
          <div
            className={classNames(styles.outlineToggle, {
              [styles.outlineEnabled]: outlineEnabled,
            })}
            onClick={handleOutlineToggle}
          >
            grid
          </div>
        )}
      </div>
      {mountPoints.length > 0 && (
        <ul className={styles.mountPointList}>
          {mountPoints.map((childMountPoint) => (
            <StoryboardTreeMountPoint
              level={level + 1}
              key={childMountPoint}
              nodeUid={nodeUid}
              mountPoint={childMountPoint}
            />
          ))}
        </ul>
      )}
      <div
        className={styles.dropCursor}
        style={{
          left: level * treeViewPaddingUnit,
        }}
      />
    </li>
  );
}
Example #6
Source File: DivisionsTable.tsx    From condo with MIT License 4 votes vote down vote up
export default function DivisionTable (props: BuildingTableProps) {
    const intl = useIntl()

    const CreateLabel = intl.formatMessage({ id: 'pages.condo.division.index.CreateDivisionButtonLabel' })
    const SearchPlaceholder = intl.formatMessage({ id: 'filters.FullSearch' })
    const PageTitleMsg = intl.formatMessage({ id: 'pages.condo.property.id.PageTitle' })
    const ServerErrorMsg = intl.formatMessage({ id: 'ServerError' })
    const NotImplementedYetMessage = intl.formatMessage({ id: 'NotImplementedYet' })
    const DownloadExcelLabel = intl.formatMessage({ id: 'pages.condo.property.id.DownloadExcelLabel' })
    const EmptyListLabel = intl.formatMessage({ id: 'pages.condo.division.index.EmptyList.header' })
    const EmptyListMessage = intl.formatMessage({ id: 'pages.condo.division.index.EmptyList.text' })
    const CreateDivision = intl.formatMessage({ id: 'pages.condo.division.index.CreateDivisionButtonLabel' })

    const { role, searchDivisionsQuery, tableColumns, sortBy } = props

    const { isSmall } = useLayoutContext()
    const router = useRouter()
    const { filters, offset } = parseQuery(router.query)
    const currentPageIndex = getPageIndexFromOffset(offset, PROPERTY_PAGE_SIZE)

    const { loading, error, objs: divisions, count: total } = Division.useObjects({
        sortBy: sortBy as SortDivisionsBy[],
        where: { ...searchDivisionsQuery },
        skip: (currentPageIndex - 1) * PROPERTY_PAGE_SIZE,
        first: PROPERTY_PAGE_SIZE,
    }, {
        fetchPolicy: 'network-only',
        onCompleted: () => {
            props.onSearch && props.onSearch(divisions)
        },
    })

    const handleRowAction = (record) => {
        return {
            onClick: () => {
                router.push(`/division/${record.id}/`)
            },
        }
    }

    const [search, handleSearchChange] = useSearch<IFilters>(loading)
    const isNoDivisionsData = !divisions.length && isEmpty(filters) && !loading

    if (error) {
        return <LoadingOrErrorPage title={PageTitleMsg} loading={loading} error={error ? ServerErrorMsg : null}/>
    }

    return isNoDivisionsData
        ? <EmptyListView
            label={EmptyListLabel}
            message={EmptyListMessage}
            createRoute="/division/create"
            createLabel={CreateDivision}/>
        : (
            <Row align={'middle'} gutter={ROW_VERTICAL_GUTTERS}>
                <Col span={24}>
                    <TableFiltersContainer>
                        <Row justify="space-between" gutter={ROW_VERTICAL_GUTTERS}>
                            <Col xs={24} lg={6}>
                                <Input
                                    placeholder={SearchPlaceholder}
                                    onChange={(e) => {
                                        handleSearchChange(e.target.value)
                                    }}
                                    value={search}
                                />
                            </Col>
                            <Col lg={6} offset={1} hidden={isSmall}>
                                <Tooltip title={NotImplementedYetMessage}>
                                    <Typography.Text
                                        style={{
                                            opacity: 70,
                                            color: colors.sberGrey[4],
                                        }}
                                    >
                                        <Button
                                            type={'inlineLink'}
                                            icon={<DatabaseFilled/>}
                                            target="_blank"
                                            rel="noreferrer">{DownloadExcelLabel}
                                        </Button>
                                    </Typography.Text>
                                </Tooltip>
                            </Col>
                            <Col xs={24} lg={4} offset={isSmall ? 0 : 7}>
                                {
                                    role?.canManageDivisions && (
                                        <Row justify={isSmall ? 'start' : 'end'}>
                                            <Button type="sberPrimary" onClick={() => router.push('/division/create')}>
                                                {CreateLabel}
                                            </Button>
                                        </Row>
                                    )
                                }
                            </Col>
                        </Row>
                    </TableFiltersContainer>
                </Col>
                <Col span={24}>
                    <Table
                        scroll={getTableScrollConfig(isSmall)}
                        totalRows={total}
                        loading={loading}
                        dataSource={divisions}
                        onRow={handleRowAction}
                        columns={tableColumns}
                        pageSize={PROPERTY_PAGE_SIZE}
                        applyQuery={(queryParams) => {
                            queryParams['tab'] = router.query['tab']
                            const newQuery = qs.stringify({ ...queryParams }, {
                                arrayFormat: 'comma',
                                skipNulls: true,
                                addQueryPrefix: true,
                            })
                            return router.push(router.route + newQuery)
                        }}
                    />
                </Col>
            </Row>
        )
}
Example #7
Source File: BuildingsTable.tsx    From condo with MIT License 4 votes vote down vote up
export default function BuildingsTable (props: BuildingTableProps) {
    const intl = useIntl()

    const ExportAsExcel = intl.formatMessage({ id: 'ExportAsExcel' })
    const CreateLabel = intl.formatMessage({ id: 'pages.condo.property.index.CreatePropertyButtonLabel' })
    const SearchPlaceholder = intl.formatMessage({ id: 'filters.FullSearch' })
    const PageTitleMsg = intl.formatMessage({ id: 'pages.condo.property.id.PageTitle' })
    const ServerErrorMsg = intl.formatMessage({ id: 'ServerError' })
    const PropertiesMessage = intl.formatMessage({ id: 'menu.Property' })
    const DownloadExcelLabel = intl.formatMessage({ id: 'pages.condo.property.id.DownloadExcelLabel' })
    const PropertyTitle = intl.formatMessage({ id: 'pages.condo.property.ImportTitle' })
    const EmptyListLabel = intl.formatMessage({ id: 'pages.condo.property.index.EmptyList.header' })
    const EmptyListMessage = intl.formatMessage({ id: 'pages.condo.property.index.EmptyList.text' })
    const CreateProperty = intl.formatMessage({ id: 'pages.condo.property.index.CreatePropertyButtonLabel' })

    const { role, searchPropertiesQuery, tableColumns, sortBy } = props

    const { isSmall } = useLayoutContext()
    const router = useRouter()
    const { filters, offset } = parseQuery(router.query)
    const currentPageIndex = getPageIndexFromOffset(offset, PROPERTY_PAGE_SIZE)

    const { loading, error, refetch, objs: properties, count: total } = Property.useObjects({
        sortBy,
        where: { ...searchPropertiesQuery },
        skip: (currentPageIndex - 1) * PROPERTY_PAGE_SIZE,
        first: PROPERTY_PAGE_SIZE,
    }, {
        fetchPolicy: 'network-only',
        onCompleted: () => {
            props.onSearch && props.onSearch(properties)
        },
    })

    const handleRowAction = (record) => {
        return {
            onClick: () => {
                router.push(`/property/${record.id}/`)
            },
        }
    }

    const [downloadLink, setDownloadLink] = useState(null)
    const [exportToExcel, { loading: isXlsLoading }] = useLazyQuery(
        EXPORT_PROPERTIES_TO_EXCEL,
        {
            onError: error => {
                const message = get(error, ['graphQLErrors', 0, 'extensions', 'messageForUser']) || error.message
                notification.error({ message })
            },
            onCompleted: data => {
                setDownloadLink(data.result.linkToFile)
            },
        },
    )

    const [columns, propertyNormalizer, propertyValidator, propertyCreator] = useImporterFunctions()

    const [search, handleSearchChange] = useSearch<IFilters>(loading)
    const isNoBuildingsData = isEmpty(properties) && isEmpty(filters) && !loading

    const canManageProperties = get(role, 'canManageProperties', false)

    function onExportToExcelButtonClicked () {
        exportToExcel({
            variables: {
                data: {
                    where: { ...searchPropertiesQuery },
                    sortBy,
                },
            },
        })
    }

    if (error) {
        return <LoadingOrErrorPage title={PageTitleMsg} loading={loading} error={error ? ServerErrorMsg : null}/>
    }

    return (
        <>
            <EmptyListView
                label={EmptyListLabel}
                message={EmptyListMessage}
                button={(
                    <ImportWrapper
                        objectsName={PropertiesMessage}
                        accessCheck={canManageProperties}
                        onFinish={refetch}
                        columns={columns}
                        rowNormalizer={propertyNormalizer}
                        rowValidator={propertyValidator}
                        domainTranslate={PropertyTitle}
                        objectCreator={propertyCreator}
                    >
                        <Button
                            type={'sberPrimary'}
                            icon={<DiffOutlined/>}
                            secondary
                        />
                    </ImportWrapper>
                )}
                createRoute="/property/create"
                createLabel={CreateProperty}
                containerStyle={{ display: isNoBuildingsData ? 'flex' : 'none' }}
            />
            <Row justify={'space-between'} gutter={ROW_VERTICAL_GUTTERS} hidden={isNoBuildingsData}>
                <Col span={24}>
                    <TableFiltersContainer>
                        <Row justify="space-between" gutter={ROW_VERTICAL_GUTTERS}>
                            <Col xs={24} lg={12}>
                                <Row align={'middle'} gutter={ROW_BIG_HORIZONTAL_GUTTERS}>
                                    <Col xs={24} lg={13}>
                                        <Input
                                            placeholder={SearchPlaceholder}
                                            onChange={(e) => {
                                                handleSearchChange(e.target.value)
                                            }}
                                            value={search}
                                            allowClear={true}
                                        />
                                    </Col>
                                    <Col hidden={isSmall}>
                                        {
                                            downloadLink
                                                ? (
                                                    <Button
                                                        type={'inlineLink'}
                                                        icon={<DatabaseFilled/>}
                                                        loading={isXlsLoading}
                                                        target="_blank"
                                                        href={downloadLink}
                                                        rel="noreferrer">
                                                        {DownloadExcelLabel}
                                                    </Button>
                                                )
                                                : (
                                                    <Button
                                                        type={'inlineLink'}
                                                        icon={<DatabaseFilled/>}
                                                        loading={isXlsLoading}
                                                        onClick={onExportToExcelButtonClicked}>
                                                        {ExportAsExcel}
                                                    </Button>
                                                )
                                        }
                                    </Col>
                                </Row>
                            </Col>
                            <Col xs={24} lg={6}>
                                <Row justify={'end'} gutter={ROW_SMALL_HORIZONTAL_GUTTERS}>
                                    <Col hidden={isSmall}>
                                        {
                                            canManageProperties && (
                                                <ImportWrapper
                                                    objectsName={PropertiesMessage}
                                                    accessCheck={canManageProperties}
                                                    onFinish={refetch}
                                                    columns={columns}
                                                    rowNormalizer={propertyNormalizer}
                                                    rowValidator={propertyValidator}
                                                    domainTranslate={PropertyTitle}
                                                    objectCreator={propertyCreator}
                                                >
                                                    <Button
                                                        type={'sberPrimary'}
                                                        icon={<DiffOutlined/>}
                                                        secondary
                                                    />
                                                </ImportWrapper>
                                            )
                                        }
                                    </Col>
                                    <Col>
                                        {
                                            canManageProperties
                                                ? (
                                                    <Button type="sberPrimary" onClick={() => router.push('/property/create')}>
                                                        {CreateLabel}
                                                    </Button>
                                                )
                                                : null
                                        }
                                    </Col>
                                </Row>
                            </Col>
                        </Row>
                    </TableFiltersContainer>
                </Col>
                <Col span={24}>
                    <Table
                        scroll={getTableScrollConfig(isSmall)}
                        totalRows={total}
                        loading={loading}
                        dataSource={properties}
                        onRow={handleRowAction}
                        columns={tableColumns}
                        pageSize={PROPERTY_PAGE_SIZE}
                    />
                </Col>
            </Row>
        </>
    )
}