Merge branch 'feature/files' of github.com:ONLYOFFICE/AppServer into feature/files
This commit is contained in:
commit
42b9698a7f
@ -3,7 +3,11 @@ import { connect } from "react-redux";
|
||||
import { utils, toastr } from "asc-web-components";
|
||||
import { getRootFolders } from "../../../store/files/selectors";
|
||||
import TreeFolders from "./TreeFolders";
|
||||
import { setFilter, fetchFiles, setRootFolders } from "../../../store/files/actions";
|
||||
import {
|
||||
setFilter,
|
||||
fetchFiles,
|
||||
setRootFolders
|
||||
} from "../../../store/files/actions";
|
||||
import store from "../../../store/store";
|
||||
import { api, history } from "asc-web-common";
|
||||
const { files } = api;
|
||||
@ -79,16 +83,16 @@ function mapStateToProps(state) {
|
||||
const { rootFolders, selectedFolder, filter } = state.files;
|
||||
const currentFolderId = selectedFolder.id.toString();
|
||||
const fakeNewDocuments = 8;
|
||||
const parentId = selectedFolder.parentId;
|
||||
|
||||
return {
|
||||
data: getRootFolders(rootFolders),
|
||||
selectedKeys: selectedFolder ? [currentFolderId] : [""],
|
||||
fakeNewDocuments,
|
||||
currentModule: currentFolderId,
|
||||
filter,
|
||||
parentId
|
||||
filter
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, { setFilter, setRootFolders })(ArticleBodyContent);
|
||||
export default connect(mapStateToProps, { setFilter, setRootFolders })(
|
||||
ArticleBodyContent
|
||||
);
|
||||
|
@ -0,0 +1,54 @@
|
||||
import i18n from "i18next";
|
||||
import Backend from "i18next-xhr-backend";
|
||||
import config from "../../../../package.json";
|
||||
import { constants } from 'asc-web-common';
|
||||
const { LANGUAGE } = constants;
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
newInstance
|
||||
.use(Backend)
|
||||
.init({
|
||||
lng: localStorage.getItem(LANGUAGE) || 'en',
|
||||
fallbackLng: "en",
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: true
|
||||
},
|
||||
backend: {
|
||||
loadPath: `${config.homepage}/locales/EmptyTrashDialog/{{lng}}/{{ns}}.json`
|
||||
}
|
||||
});
|
||||
} else if (process.env.NODE_ENV === "development") {
|
||||
|
||||
const resources = {
|
||||
en: {
|
||||
translation: require("./locales/en/translation.json")
|
||||
},
|
||||
ru: {
|
||||
translation: require("./locales/ru/translation.json")
|
||||
},
|
||||
};
|
||||
|
||||
newInstance.init({
|
||||
resources: resources,
|
||||
lng: localStorage.getItem(LANGUAGE) || 'en',
|
||||
fallbackLng: "en",
|
||||
debug: true,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default newInstance;
|
@ -0,0 +1,76 @@
|
||||
import React, { useCallback, useState } from "react";
|
||||
import ModalDialogContainer from "../ModalDialogContainer";
|
||||
import { toastr, ModalDialog, Button, Text } from "asc-web-components";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import i18n from "./i18n";
|
||||
import { api, utils } from "asc-web-common";
|
||||
|
||||
const { files } = api;
|
||||
const { changeLanguage } = utils;
|
||||
|
||||
const EmptyTrashDialogComponent = props => {
|
||||
const { onClose, visible, t } = props;
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
changeLanguage(i18n);
|
||||
|
||||
const onEmptyTrash = useCallback(() => {
|
||||
setIsLoading(true);
|
||||
files
|
||||
.emptyTrash()
|
||||
.then(res => {
|
||||
toastr.success("Success empty recycle bin");
|
||||
}) //toastr.success("It was successfully deleted 24 from 24"); + progressBar
|
||||
.catch(err => toastr.error(err))
|
||||
.finally(() => {
|
||||
setIsLoading(false);
|
||||
onClose();
|
||||
});
|
||||
}, [onClose]);
|
||||
|
||||
return (
|
||||
<ModalDialogContainer>
|
||||
<ModalDialog
|
||||
visible={visible}
|
||||
onClose={onClose}
|
||||
headerContent={t("ConfirmationTitle")}
|
||||
bodyContent={
|
||||
<>
|
||||
<Text>{t("EmptyTrashDialogQuestion")}</Text>
|
||||
<Text>{t("EmptyTrashDialogMessage")}</Text>
|
||||
</>
|
||||
}
|
||||
footerContent={
|
||||
<>
|
||||
<Button
|
||||
key="OkButton"
|
||||
label={t("OKButton")}
|
||||
size="medium"
|
||||
primary
|
||||
onClick={onEmptyTrash}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<Button
|
||||
className="button-dialog"
|
||||
key="CancelButton"
|
||||
label={t("CancelButton")}
|
||||
size="medium"
|
||||
onClick={onClose}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</ModalDialogContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const ModalDialogContainerTranslated = withTranslation()(
|
||||
EmptyTrashDialogComponent
|
||||
);
|
||||
|
||||
const EmptyTrashDialog = props => (
|
||||
<ModalDialogContainerTranslated i18n={i18n} {...props} />
|
||||
);
|
||||
|
||||
export default EmptyTrashDialog;
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"OKButton": "OK",
|
||||
"CancelButton": "Cancel",
|
||||
"ConfirmationTitle": "Confirmation",
|
||||
|
||||
"EmptyTrashDialogQuestion": "Are you sure you want to empty the recycle bin?",
|
||||
"EmptyTrashDialogMessage": "Note: This action can not be undone. Note: removal from your account can not be undone."
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"OKButton": "ОК",
|
||||
"CancelButton": "Отмена",
|
||||
"ConfirmationTitle": "Подтверждение удаления",
|
||||
|
||||
"EmptyTrashDialogQuestion": "Вы уверены, что хотите очистить корзину?",
|
||||
"EmptyTrashDialogMessage": "Замечание: Это действие не может быть отменено. Внимание: удаление из Вашего аккаунта будет нельзя отменить."
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
const ModalDialogContainer = styled.div`
|
||||
.flex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.text-dialog {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.input-dialog {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.button-dialog {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.warning-text {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.textarea-dialog {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.link-dialog {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.error-label {
|
||||
position: absolute;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.field-body {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.toggle-content-dialog {
|
||||
.heading-toggle-content {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.modal-dialog-content {
|
||||
padding: 8px 16px;
|
||||
border: 1px solid lightgray;
|
||||
|
||||
.modal-dialog-checkbox:not(:last-child) {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default ModalDialogContainer;
|
@ -0,0 +1,3 @@
|
||||
import EmptyTrashDialog from "./EmptyTrashDialog";
|
||||
|
||||
export { EmptyTrashDialog };
|
@ -1,4 +1,4 @@
|
||||
import React, { useCallback } from "react";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import styled, { css } from "styled-components";
|
||||
import { withRouter } from "react-router";
|
||||
import {
|
||||
@ -16,7 +16,7 @@ import {
|
||||
IconButton,
|
||||
toastr
|
||||
} from "asc-web-components";
|
||||
import { fetchFolder } from "../../../../../store/files/actions";
|
||||
import { EmptyTrashDialog } from '../../../../dialogs';import { fetchFolder } from "../../../../../store/files/actions";
|
||||
import { default as filesStore } from "../../../../../store/store";
|
||||
|
||||
const { isAdmin } = store.auth.selectors;
|
||||
@ -103,7 +103,8 @@ const SectionHeaderContent = props => {
|
||||
isHeaderVisible,
|
||||
isHeaderChecked,
|
||||
isHeaderIndeterminate,
|
||||
selection } = props;
|
||||
selection,
|
||||
isRecycleBinFolder } = props;
|
||||
|
||||
const createDocument = useCallback(
|
||||
() => onCreate('docx'),
|
||||
@ -208,6 +209,9 @@ const SectionHeaderContent = props => {
|
||||
() => toastr.info("deleteAction click"),
|
||||
[]
|
||||
);
|
||||
|
||||
const [showEmptyTrashDialog, setEmptyTrashDialog] = useState(false);
|
||||
const onCloseEmptyTrashDialog = useCallback(() => setEmptyTrashDialog(!showEmptyTrashDialog), [showEmptyTrashDialog]);
|
||||
|
||||
const getContextOptionsFolder = useCallback(() => {
|
||||
return [
|
||||
@ -332,6 +336,12 @@ const SectionHeaderContent = props => {
|
||||
}
|
||||
];
|
||||
|
||||
isRecycleBinFolder &&
|
||||
menuItems.push({
|
||||
label: t("EmptyRecycleBin"),
|
||||
onClick: onCloseEmptyTrashDialog
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledContainer isHeaderVisible={isHeaderVisible}>
|
||||
{isHeaderVisible ? (
|
||||
@ -397,17 +407,26 @@ const SectionHeaderContent = props => {
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{true &&
|
||||
<EmptyTrashDialog
|
||||
visible={showEmptyTrashDialog}
|
||||
onClose={onCloseEmptyTrashDialog}
|
||||
/>
|
||||
}
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const { selectedFolder, selection, rootFolders } = state.files;
|
||||
return {
|
||||
folder: state.files.selectedFolder.parentId !== 0,
|
||||
folder: selectedFolder.parentId !== 0,
|
||||
isAdmin: isAdmin(state.auth.user),
|
||||
parentId: state.files.selectedFolder.parentId,
|
||||
selection: state.files.selection,
|
||||
title: state.files.selectedFolder.title
|
||||
isRecycleBinFolder: rootFolders.trash.id === selectedFolder.id,
|
||||
parentId: selectedFolder.parentId,
|
||||
selection,
|
||||
title: selectedFolder.title,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -51,5 +51,6 @@
|
||||
"More": "More",
|
||||
"CloseButton": "Close",
|
||||
"All": "All",
|
||||
"Files": "Files"
|
||||
"Files": "Files",
|
||||
"EmptyRecycleBin": "Empty Recycle Bin"
|
||||
}
|
@ -51,5 +51,6 @@
|
||||
"More": "Больше",
|
||||
"CloseButton": "Закрыть",
|
||||
"All": "Все",
|
||||
"Files": "Файлы"
|
||||
"Files": "Файлы",
|
||||
"EmptyRecycleBin": "Очистить корзину"
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { FilterInput } from "asc-web-components";
|
||||
import { fetchPeople } from "../../../../../store/people/actions";
|
||||
import find from "lodash/find";
|
||||
import result from "lodash/result";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { withRouter } from "react-router";
|
||||
import { getFilterByLocation } from "../../../../../helpers/converters";
|
||||
import { store } from 'asc-web-common';
|
||||
import { store, FilterInput } from 'asc-web-common';
|
||||
const { isAdmin } = store.auth.selectors;
|
||||
|
||||
const getEmployeeStatus = filterValues => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "asc-web-common",
|
||||
"version": "1.0.123",
|
||||
"version": "1.0.124",
|
||||
"description": "Ascensio System SIA common components and solutions library",
|
||||
"license": "AGPL-3.0",
|
||||
"files": [
|
||||
|
@ -269,4 +269,8 @@ export function deleteFile(fileId, deleteAfter, immediately) {
|
||||
};
|
||||
|
||||
return request(options);
|
||||
}
|
||||
}
|
||||
|
||||
export function emptyTrash() {
|
||||
return request({ method: "put", url: "/files/fileops/emptytrash" });
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "asc-web-components",
|
||||
"version": "1.0.373",
|
||||
"version": "1.0.374",
|
||||
"description": "Ascensio System SIA component library",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "dist/asc-web-components.js",
|
||||
|
@ -1,46 +0,0 @@
|
||||
# FilterInput
|
||||
|
||||
Used to filter tables
|
||||
|
||||
### Usage
|
||||
|
||||
```js
|
||||
import { FilterInput } from "asc-web-components";
|
||||
```
|
||||
|
||||
```jsx
|
||||
<FilterInput
|
||||
getFilterData={() => [
|
||||
{
|
||||
key: "filter-example",
|
||||
group: "filter-example",
|
||||
label: "example group",
|
||||
isHeader: true
|
||||
},
|
||||
{ key: "0", group: "filter-example", label: "Test" }
|
||||
]}
|
||||
getSortData={() => [
|
||||
{ key: "name", label: "Name", default: true },
|
||||
{ key: "surname", label: "Surname", default: true }
|
||||
]}
|
||||
onFilter={result => {
|
||||
console.log(result);
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Props | Type | Required | Values | Default | Description |
|
||||
| -------------------- | :------------: | :------: | :-----------------------------: | :-----: | ------------------------------------------------------------------------------------------------------ |
|
||||
| `className` | `string` | - | - | - | Accepts class |
|
||||
| `id` | `string` | - | - | - | Used as HTML `id` property |
|
||||
| `id` | `string` | - | - | - | Accepts id |
|
||||
| `isDisabled` | `bool` | - | - | `false` | Indicates that the field cannot be used (e.g not authorised, or changes not saved) |
|
||||
| `onChange` | `func` | - | - | - | Called with the new value. Required when input is not read only. Parent should pass it back as `value` |
|
||||
| `placeholder` | `string` | - | - | - | Placeholder text for the input |
|
||||
| `scale` | `bool` | - | - | - | Indicates the input field has scale |
|
||||
| `selectedFilterData` | `object` | - | - | - | Selected filter data |
|
||||
| `size` | `string` | | `base`, `middle`, `big`, `huge` | `base` | Supported size of the input fields. |
|
||||
| `style` | `obj`, `array` | - | - | - | Accepts css style |
|
||||
| `value` | `string` | - | - | - | Value of the input |
|
@ -1,32 +0,0 @@
|
||||
import React from "react";
|
||||
import IconButton from '../icon-button';
|
||||
import styled from 'styled-components';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const StyledCloseButton = styled.div`
|
||||
margin-left: 7px;
|
||||
margin-top: -1px;
|
||||
`;
|
||||
const CloseButton = props => {
|
||||
//console.log("CloseButton render");
|
||||
return (
|
||||
<StyledCloseButton className={props.className}>
|
||||
<IconButton
|
||||
color={"#A3A9AE"}
|
||||
hoverColor={"#A3A9AE"}
|
||||
clickColor={"#A3A9AE"}
|
||||
size={10}
|
||||
iconName={'CrossIcon'}
|
||||
isFill={true}
|
||||
isDisabled={props.isDisabled}
|
||||
onClick={!props.isDisabled ? props.onClick : undefined}
|
||||
/>
|
||||
</StyledCloseButton>
|
||||
);
|
||||
};
|
||||
CloseButton.propTypes = {
|
||||
isDisabled: PropTypes.bool,
|
||||
onClick: PropTypes.func,
|
||||
className: PropTypes.string
|
||||
}
|
||||
export default CloseButton
|
@ -1,311 +0,0 @@
|
||||
import React from 'react';
|
||||
import styled, { css } from 'styled-components';
|
||||
import FilterButton from './filter-button';
|
||||
import HideFilter from './hide-filter';
|
||||
import throttle from 'lodash/throttle';
|
||||
import ComboBox from '../combobox';
|
||||
import CloseButton from './close-button';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const StyledFilterBlock = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const StyledFilterItem = styled.div`
|
||||
display: ${props => props.block ? 'flex' : 'inline-block'};
|
||||
margin-bottom: ${props => props.block ? '8px' : '0'};
|
||||
position: relative;
|
||||
height: 100%;
|
||||
margin-right: 2px;
|
||||
border: 1px solid #ECEEF1;
|
||||
border-radius: 3px;
|
||||
background-color: #F8F9F9;
|
||||
padding-right: 22px;
|
||||
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
line-height: 15px;
|
||||
box-sizing: border-box;
|
||||
color: #555F65;
|
||||
|
||||
&:last-child{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledFilterItemContent = styled.div`
|
||||
display: flex;
|
||||
padding: 5px 4px 2px 7px;
|
||||
width: 100%;
|
||||
user-select: none;
|
||||
color: #333;
|
||||
${props =>
|
||||
props.isOpen && !props.isDisabled &&
|
||||
css`
|
||||
background: #ECEEF1;
|
||||
`}
|
||||
${props =>
|
||||
!props.isDisabled &&
|
||||
css`
|
||||
&:active{
|
||||
background: #ECEEF1;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
const StyledCloseButtonBlock = styled.div`
|
||||
display: flex;
|
||||
cursor: ${props =>
|
||||
props.isDisabled || !props.isClickable ? "default" : "pointer"};
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 25px;
|
||||
border-left: 1px solid #ECEEF1;
|
||||
right: 0;
|
||||
top: 0;
|
||||
background-color: #F8F9F9;
|
||||
${props =>
|
||||
!props.isDisabled &&
|
||||
css`
|
||||
&:active{
|
||||
background: #ECEEF1;
|
||||
svg path:first-child {
|
||||
fill: #A3A9AE;
|
||||
}
|
||||
}
|
||||
`}
|
||||
`;
|
||||
const StyledComboBox = styled(ComboBox)`
|
||||
display: inline-block;
|
||||
background: transparent;
|
||||
max-width: 185px;
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
margin-top: -2px;
|
||||
> div:first-child{
|
||||
width: auto;
|
||||
padding-left: 4px;
|
||||
}
|
||||
> div:last-child{
|
||||
max-width: 220px;
|
||||
}
|
||||
.combo-button-label {
|
||||
color: #333;
|
||||
}
|
||||
`;
|
||||
const StyledFilterName = styled.span`
|
||||
line-height: 18px;
|
||||
margin-left: 5px;
|
||||
`;
|
||||
|
||||
class FilterItem extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
id: this.props.id,
|
||||
isOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
onSelect = (option) => {
|
||||
this.props.onSelectFilterItem(null, {
|
||||
key: option.group + "_" + option.key,
|
||||
label: option.label,
|
||||
group: option.group,
|
||||
inSubgroup: !!option.inSubgroup
|
||||
});
|
||||
}
|
||||
onClick = () => {
|
||||
!this.props.isDisabled && this.props.onClose(this.props.id);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<StyledFilterItem key={this.state.id} id={this.state.id} block={this.props.block} opened={this.props.opened} >
|
||||
<StyledFilterItemContent isDisabled={this.props.isDisabled} isOpen={this.state.isOpen}>
|
||||
{this.props.groupLabel}:
|
||||
{this.props.groupItems.length > 1 ?
|
||||
<StyledComboBox
|
||||
options={this.props.groupItems}
|
||||
isDisabled={this.props.isDisabled}
|
||||
onSelect={this.onSelect}
|
||||
selectedOption={{
|
||||
key: this.state.id,
|
||||
label: this.props.label
|
||||
}}
|
||||
size='content'
|
||||
scaled={false}
|
||||
noBorder={true}
|
||||
opened={this.props.opened}
|
||||
directionX='left'
|
||||
toggleAction={(e, isOpen) => {
|
||||
this.setState({
|
||||
isOpen: isOpen
|
||||
})
|
||||
}}
|
||||
dropDownMaxHeight={200}
|
||||
></StyledComboBox>
|
||||
: <StyledFilterName>{this.props.label}</StyledFilterName>
|
||||
}
|
||||
</StyledFilterItemContent>
|
||||
|
||||
|
||||
<StyledCloseButtonBlock onClick={this.onClick} isDisabled={this.props.isDisabled} isClickable={true}>
|
||||
<CloseButton
|
||||
isDisabled={this.props.isDisabled}
|
||||
onClick={this.onClick}
|
||||
/>
|
||||
</StyledCloseButtonBlock>
|
||||
</StyledFilterItem>
|
||||
);
|
||||
}
|
||||
}
|
||||
FilterItem.propTypes = {
|
||||
id: PropTypes.string,
|
||||
opened: PropTypes.bool,
|
||||
isDisabled: PropTypes.bool,
|
||||
block: PropTypes.bool,
|
||||
groupItems: PropTypes.array,
|
||||
label: PropTypes.string,
|
||||
groupLabel: PropTypes.string,
|
||||
onClose: PropTypes.func,
|
||||
onSelectFilterItem: PropTypes.func
|
||||
}
|
||||
|
||||
class FilterBlock extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
hideFilterItems: this.props.hideFilterItems || [],
|
||||
openFilterItems: this.props.openFilterItems || []
|
||||
};
|
||||
|
||||
this.throttledRender = throttle(this.onRender, 100);
|
||||
|
||||
}
|
||||
onDeleteFilterItem = (key) => {
|
||||
this.props.onDeleteFilterItem(key);
|
||||
}
|
||||
getFilterItems = () => {
|
||||
const _this = this;
|
||||
let result = [];
|
||||
let openItems = [];
|
||||
let hideItems = [];
|
||||
if (this.state.openFilterItems.length > 0) {
|
||||
openItems = this.state.openFilterItems.map(function (item) {
|
||||
return <FilterItem
|
||||
block={false}
|
||||
isDisabled={_this.props.isDisabled}
|
||||
key={item.key}
|
||||
groupItems={_this.props.getFilterData().filter(function (t) {
|
||||
return (t.group == item.group && t.group != t.key);
|
||||
})}
|
||||
onSelectFilterItem={_this.props.onClickFilterItem}
|
||||
id={item.key}
|
||||
groupLabel={item.groupLabel}
|
||||
label={item.label}
|
||||
opened={item.key.indexOf('_-1') == -1 ? false : true}
|
||||
onClose={_this.onDeleteFilterItem}>
|
||||
</FilterItem>
|
||||
});
|
||||
}
|
||||
if (this.state.hideFilterItems.length > 0) {
|
||||
var open = false;
|
||||
var hideFilterItemsList = this.state.hideFilterItems.map(function (item) {
|
||||
open = item.key.indexOf('_-1') == -1 ? false : true
|
||||
return <FilterItem
|
||||
block={true}
|
||||
isDisabled={_this.props.isDisabled}
|
||||
key={item.key}
|
||||
groupItems={_this.props.getFilterData().filter(function (t) {
|
||||
return (t.group == item.group && t.group != t.key);
|
||||
})}
|
||||
onSelectFilterItem={_this.props.onClickFilterItem}
|
||||
id={item.key}
|
||||
groupLabel={item.groupLabel}
|
||||
opened={item.key.indexOf('_-1') == -1 ? false : true}
|
||||
label={item.label}
|
||||
onClose={_this.onDeleteFilterItem}>
|
||||
</FilterItem>
|
||||
})
|
||||
hideItems.push(
|
||||
<HideFilter key="hide-filter" count={this.state.hideFilterItems.length} isDisabled={this.props.isDisabled} open={open}>
|
||||
{
|
||||
hideFilterItemsList
|
||||
}
|
||||
</HideFilter>
|
||||
);
|
||||
}
|
||||
result = hideItems.concat(openItems);
|
||||
return result;
|
||||
}
|
||||
getData = () => {
|
||||
const _this = this;
|
||||
const d = this.props.getFilterData();
|
||||
let result = [];
|
||||
d.forEach(element => {
|
||||
if (!element.inSubgroup) {
|
||||
element.onClick = !element.isSeparator && !element.isHeader && !element.disabled ? ((e) => _this.props.onClickFilterItem(e, element)) : undefined;
|
||||
element.key = element.group != element.key ? element.group + "_" + element.key : element.key;
|
||||
if (element.subgroup != undefined) {
|
||||
if (d.findIndex(x => x.group === element.subgroup) == -1) element.disabled = true;
|
||||
}
|
||||
result.push(element);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
componentDidUpdate() {
|
||||
this.throttledRender();
|
||||
}
|
||||
onRender = () => {
|
||||
this.props.onRender();
|
||||
}
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
|
||||
if (!isEqual(this.props, nextProps)) {
|
||||
if (!isEqual(this.props.hideFilterItems, nextProps.hideFilterItems) || !isEqual(this.props.openFilterItems, nextProps.openFilterItems)) {
|
||||
this.setState({
|
||||
hideFilterItems: nextProps.hideFilterItems,
|
||||
openFilterItems: nextProps.openFilterItems
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (this.props.isResizeUpdate) {
|
||||
return true;
|
||||
}
|
||||
return !isEqual(this.state, nextState);
|
||||
}
|
||||
render() {
|
||||
const _this = this;
|
||||
const filterItems = this.getFilterItems();
|
||||
const filterData = this.props.getFilterData();
|
||||
return (
|
||||
<>
|
||||
<StyledFilterBlock ref={this.filterWrapper} id='filter-items-container'>
|
||||
{filterItems}
|
||||
</StyledFilterBlock>
|
||||
{filterData.length > 0 && <FilterButton id='filter-button' iconSize={this.props.iconSize} getData={_this.getData} isDisabled={this.props.isDisabled} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
FilterBlock.propTypes = {
|
||||
iconSize: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
isDisabled: PropTypes.bool,
|
||||
isResizeUpdate: PropTypes.bool,
|
||||
hideFilterItems: PropTypes.array,
|
||||
openFilterItems: PropTypes.array,
|
||||
onRender: PropTypes.func,
|
||||
onDeleteFilterItem: PropTypes.func,
|
||||
getFilterData: PropTypes.func
|
||||
}
|
||||
|
||||
export default FilterBlock;
|
@ -1,30 +0,0 @@
|
||||
import React from "react";
|
||||
import ContextMenuButton from '../context-menu-button';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class FilterButton extends React.PureComponent {
|
||||
render() {
|
||||
//console.log('render FilterButton)
|
||||
return (
|
||||
<ContextMenuButton
|
||||
id={this.props.id}
|
||||
title='Actions'
|
||||
iconName='RectangleFilterIcon'
|
||||
iconOpenName='RectangleFilterClickIcon'
|
||||
color='#A3A9AE'
|
||||
size={this.props.iconSize}
|
||||
isDisabled={this.props.isDisabled}
|
||||
getData={this.props.getData}
|
||||
directionY='bottom'
|
||||
className='filter-button'
|
||||
></ContextMenuButton>
|
||||
)
|
||||
}
|
||||
}
|
||||
FilterButton.propTypes = {
|
||||
id: PropTypes.string,
|
||||
iconSize: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
isDisabled: PropTypes.bool,
|
||||
getData: PropTypes.func
|
||||
}
|
||||
export default FilterButton
|
@ -1,110 +0,0 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { StringValue } from 'react-values';
|
||||
import { withKnobs, boolean, text, select } from '@storybook/addon-knobs/react';
|
||||
import withReadme from 'storybook-readme/with-readme';
|
||||
import Readme from './README.md';
|
||||
import FilterInput from '.';
|
||||
import Button from '../button';
|
||||
import Section from '../../../.storybook/decorators/section';
|
||||
|
||||
const sizeOptions = ['base', 'middle', 'big', 'huge'];
|
||||
|
||||
function getData() {
|
||||
return [
|
||||
{ key: 'filter-status', group: 'filter-status', label: 'Status', isHeader: true },
|
||||
{ key: '0', group: 'filter-status', label: 'Active' },
|
||||
{ key: '1', group: 'filter-status', label: 'Disabled' },
|
||||
{ key: 'filter-type', group: 'filter-type', label: 'Type', isHeader: true },
|
||||
{ key: '0', group: 'filter-type', label: 'Folders' },
|
||||
{ key: '1', group: 'filter-type', label: 'Employee' },
|
||||
{ key: 'filter-test', group: 'filter-test', label: 'Test', isHeader: true },
|
||||
{ key: '0', group: 'filter-test', label: 'test1' },
|
||||
{ key: '1', group: 'filter-test', label: 'test2' },
|
||||
{ key: 'filter-other', group: 'filter-other', label: 'Other', isHeader: true },
|
||||
{ key: '0', group: 'filter-other', subgroup: 'filter-groups', defaultSelectLabel: 'Select', label: 'Groups' },
|
||||
{ key: '0', inSubgroup: true, group: 'filter-groups', label: 'Administration'},
|
||||
{ key: '1', inSubgroup: true, group: 'filter-groups', label: 'Public Relations'}
|
||||
];
|
||||
}
|
||||
function getSortData() {
|
||||
return [
|
||||
{key: 'name', label: 'Name', default: true},
|
||||
{key: 'surname', label: 'Surname', default: true}
|
||||
];
|
||||
}
|
||||
|
||||
class FilterStory extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selectedFilterData: {
|
||||
inputValue: "text",
|
||||
filterValues: [
|
||||
{key: "1", group: "filter-status"}
|
||||
]
|
||||
}
|
||||
};
|
||||
this.buttonClick = this.buttonClick.bind(this);
|
||||
}
|
||||
buttonClick(){
|
||||
this.setState({
|
||||
selectedFilterData: {
|
||||
filterValues: [
|
||||
{key: "-1", group: "filter-groups"}
|
||||
],
|
||||
sortDirection: "asc",
|
||||
sortId: "surname",
|
||||
inputValue: "text 123"
|
||||
}
|
||||
});
|
||||
}
|
||||
render(){
|
||||
return(
|
||||
<Section>
|
||||
<StringValue
|
||||
onChange={e => {
|
||||
action('onChange')(e);
|
||||
}
|
||||
}
|
||||
>
|
||||
{({ value, set }) => (
|
||||
<Section>
|
||||
<div style={{marginBottom: '20px'}}>
|
||||
<Button
|
||||
label="Change props"
|
||||
onClick={this.buttonClick}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<FilterInput
|
||||
id={text('id', '')}
|
||||
isDisabled={boolean('isDisabled', false)}
|
||||
size={select('size', sizeOptions, 'base')}
|
||||
scale={boolean('scale', false)}
|
||||
getFilterData={getData}
|
||||
getSortData={getSortData}
|
||||
placeholder={text('placeholder', 'Search')}
|
||||
onFilter={(result) => {console.log(result)}}
|
||||
value={value}
|
||||
selectedFilterData={this.state.selectedFilterData}
|
||||
onChange={e => {
|
||||
set(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Section>
|
||||
)}
|
||||
</StringValue>
|
||||
</Section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
storiesOf('Components|Filter', module)
|
||||
.addDecorator(withKnobs)
|
||||
.addDecorator(withReadme(Readme))
|
||||
.add('base', () => (
|
||||
<FilterStory/>
|
||||
));
|
@ -1,56 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import FilterInput from '.';
|
||||
|
||||
describe('<FilterInput />', () => {
|
||||
it('renders without error', () => {
|
||||
const wrapper = mount(
|
||||
<FilterInput
|
||||
getFilterData={() => [{ key: 'filter-example', group: 'filter-example', label: 'example group', isHeader: true }, { key: '0', group: 'filter-example', label: 'Test' }]}
|
||||
getSortData={() => [{ key: 'name', label: 'Name' }, { key: 'surname', label: 'Surname' }]}
|
||||
onFilter={jest.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper).toExist();
|
||||
});
|
||||
|
||||
it('accepts id', () => {
|
||||
const wrapper = mount(
|
||||
<FilterInput
|
||||
getFilterData={() => [{ key: 'filter-example', group: 'filter-example', label: 'example group', isHeader: true }, { key: '0', group: 'filter-example', label: 'Test' }]}
|
||||
getSortData={() => [{ key: 'name', label: 'Name' }, { key: 'surname', label: 'Surname' }]}
|
||||
onFilter={jest.fn()}
|
||||
id="testId"
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper.prop('id')).toEqual('testId');
|
||||
});
|
||||
|
||||
it('accepts className', () => {
|
||||
const wrapper = mount(
|
||||
<FilterInput
|
||||
getFilterData={() => [{ key: 'filter-example', group: 'filter-example', label: 'example group', isHeader: true }, { key: '0', group: 'filter-example', label: 'Test' }]}
|
||||
getSortData={() => [{ key: 'name', label: 'Name' }, { key: 'surname', label: 'Surname' }]}
|
||||
onFilter={jest.fn()}
|
||||
className="test"
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper.prop('className')).toEqual('test');
|
||||
});
|
||||
|
||||
it('accepts style', () => {
|
||||
const wrapper = mount(
|
||||
<FilterInput
|
||||
getFilterData={() => [{ key: 'filter-example', group: 'filter-example', label: 'example group', isHeader: true }, { key: '0', group: 'filter-example', label: 'Test' }]}
|
||||
getSortData={() => [{ key: 'name', label: 'Name' }, { key: 'surname', label: 'Surname' }]}
|
||||
onFilter={jest.fn()}
|
||||
style={{ color: 'red' }}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper.getDOMNode().style).toHaveProperty('color', 'red');
|
||||
});
|
||||
});
|
@ -1,130 +0,0 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { Icons } from "../icons";
|
||||
import DropDown from "../drop-down";
|
||||
import { handleAnyClick } from "../../utils/event";
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const Caret = styled.div`
|
||||
width: 7px;
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
transform: ${props => (props.isOpen ? "rotate(180deg)" : "rotate(0)")};
|
||||
top: ${props => (props.isOpen ? "2px" : "0")};
|
||||
`;
|
||||
|
||||
const StyledHideFilterButton = styled.div`
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
height: 100%;
|
||||
border: 1px solid #eceef1;
|
||||
border-radius: 3px;
|
||||
background-color: #f8f9f9;
|
||||
padding: 0 20px 0 9px;
|
||||
margin-right: 2px;
|
||||
cursor: ${props => (props.isDisabled ? "default" : "pointer")};
|
||||
font-family: Open Sans;
|
||||
font-style: normal;
|
||||
|
||||
:hover {
|
||||
border-color: ${props => (props.isDisabled ? "#ECEEF1" : "#A3A9AE")};
|
||||
}
|
||||
:active {
|
||||
background-color: ${props => (props.isDisabled ? "#F8F9F9" : "#ECEEF1")};
|
||||
}
|
||||
`;
|
||||
const StyledHideFilter = styled.div`
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
`;
|
||||
const DropDownStyle = styled.div`
|
||||
.drop-down {
|
||||
padding: 16px;
|
||||
}
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
class HideFilter extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.ref = React.createRef();
|
||||
this.dropDownRef = React.createRef();
|
||||
this.state = {
|
||||
popoverOpen: this.props.open
|
||||
};
|
||||
}
|
||||
|
||||
onClick = (state, e) => {
|
||||
if (!state && e && this.dropDownRef.current.contains(e.target)) {
|
||||
return;
|
||||
}
|
||||
if (!this.props.isDisabled) {
|
||||
this.setState({
|
||||
popoverOpen: state
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleClick = e => {
|
||||
this.state.popoverOpen &&
|
||||
!this.dropDownRef.current.firstElementChild.contains(e.target) &&
|
||||
this.onClick(false);
|
||||
};
|
||||
|
||||
componentWillUnmount() {
|
||||
handleAnyClick(false, this.handleClick);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevState) {
|
||||
if (this.state.popoverOpen !== prevState.popoverOpen) {
|
||||
handleAnyClick(this.state.popoverOpen, this.handleClick);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
//console.log("HideFilter render");
|
||||
return (
|
||||
<StyledHideFilter
|
||||
onClick={this.onClick.bind(this, !this.state.popoverOpen)}
|
||||
ref={this.ref}
|
||||
>
|
||||
<StyledHideFilterButton
|
||||
id="PopoverLegacy"
|
||||
isDisabled={this.props.isDisabled}
|
||||
>
|
||||
{this.props.count}
|
||||
<Caret isOpen={this.state.popoverOpen}>
|
||||
<Icons.ExpanderDownIcon
|
||||
size="scale"
|
||||
isfill={true}
|
||||
color="#A3A9AE"
|
||||
/>
|
||||
</Caret>
|
||||
</StyledHideFilterButton>
|
||||
|
||||
<DropDownStyle ref={this.dropDownRef}>
|
||||
<DropDown
|
||||
className="drop-down"
|
||||
manualY="8px"
|
||||
open={this.state.popoverOpen}
|
||||
clickOutsideAction={this.handleClick}
|
||||
>
|
||||
{this.props.children}
|
||||
</DropDown>
|
||||
</DropDownStyle>
|
||||
</StyledHideFilter>
|
||||
);
|
||||
}
|
||||
}
|
||||
HideFilter.propTypes = {
|
||||
children: PropTypes.any,
|
||||
open: PropTypes.bool,
|
||||
isDisabled: PropTypes.bool,
|
||||
count: PropTypes.number
|
||||
}
|
||||
export default HideFilter;
|
@ -1,555 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import SearchInput from '../search-input';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import throttle from 'lodash/throttle';
|
||||
import FilterBlock from './filter-block';
|
||||
import SortComboBox from './sort-combobox';
|
||||
import { mobile } from '../../utils/device';
|
||||
import map from 'lodash/map';
|
||||
import clone from 'lodash/clone';
|
||||
|
||||
const StyledFilterInput = styled.div`
|
||||
width: 100%;
|
||||
min-width: 255px;
|
||||
&:after {
|
||||
content: " ";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
`;
|
||||
const StyledSearchInput = styled.div`
|
||||
display: block;
|
||||
float: left;
|
||||
width: calc(100% - 140px);
|
||||
@media ${mobile} {
|
||||
width: calc(100% - 58px);
|
||||
}
|
||||
|
||||
.search-input-block {
|
||||
& > input {
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
const StyledFilterBlock = styled.div`
|
||||
display: flex;
|
||||
|
||||
.filter-button {
|
||||
|
||||
svg {
|
||||
path:not(:first-child) {
|
||||
stroke: #A3A9AE;
|
||||
}
|
||||
}
|
||||
|
||||
stroke: #A3A9AE;
|
||||
div:active {
|
||||
svg path:first-child {
|
||||
fill: #ECEEF1;
|
||||
stroke: #A3A9AE;
|
||||
}
|
||||
}
|
||||
div:first-child:hover {
|
||||
svg path:not(:first-child) {
|
||||
stroke: #A3A9AE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
`;
|
||||
const cloneObjectsArray = function (props) {
|
||||
return map(props, clone);
|
||||
}
|
||||
const convertToInternalData = function (fullDataArray, inputDataArray) {
|
||||
const filterItems = [];
|
||||
for (let i = 0; i < inputDataArray.length; i++) {
|
||||
let filterValue = fullDataArray.find(x => ((x.key === inputDataArray[i].key.replace(inputDataArray[i].group + "_", '')) && x.group === inputDataArray[i].group && !x.inSubgroup));
|
||||
if (filterValue) {
|
||||
inputDataArray[i].key = inputDataArray[i].group + "_" + inputDataArray[i].key;
|
||||
inputDataArray[i].label = filterValue.label;
|
||||
inputDataArray[i].groupLabel = !fullDataArray.inSubgroup ? fullDataArray.find(x => (x.group === inputDataArray[i].group)).label : inputDataArray[i].groupLabel;
|
||||
filterItems.push(inputDataArray[i]);
|
||||
} else {
|
||||
filterValue = fullDataArray.find(x => ((x.key === inputDataArray[i].key.replace(inputDataArray[i].group + "_", '')) && x.group === inputDataArray[i].group && x.inSubgroup));
|
||||
if (filterValue) {
|
||||
inputDataArray[i].key = inputDataArray[i].group + "_" + inputDataArray[i].key;
|
||||
inputDataArray[i].label = filterValue.label;
|
||||
inputDataArray[i].groupLabel = fullDataArray.find(x => (x.subgroup === inputDataArray[i].group)).label;
|
||||
filterItems.push(inputDataArray[i]);
|
||||
} else {
|
||||
filterValue = fullDataArray.find(x => ((x.subgroup === inputDataArray[i].group)));
|
||||
if (filterValue) {
|
||||
const subgroupItems = fullDataArray.filter(t => t.group === filterValue.subgroup);
|
||||
if (subgroupItems.length > 1) {
|
||||
inputDataArray[i].key = inputDataArray[i].group + "_-1";
|
||||
inputDataArray[i].label = filterValue.defaultSelectLabel;
|
||||
inputDataArray[i].groupLabel = fullDataArray.find(x => (x.subgroup === inputDataArray[i].group)).label;
|
||||
filterItems.push(inputDataArray[i]);
|
||||
} else if (subgroupItems.length === 1) {
|
||||
|
||||
const selectFilterItem = {
|
||||
key: subgroupItems[0].group + "_" + subgroupItems[0].key,
|
||||
group: subgroupItems[0].group,
|
||||
label: subgroupItems[0].label,
|
||||
groupLabel: fullDataArray.find(x => x.subgroup === subgroupItems[0].group).label,
|
||||
inSubgroup: true
|
||||
};
|
||||
filterItems.push(selectFilterItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return filterItems;
|
||||
}
|
||||
|
||||
class FilterInput extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.isResizeUpdate = false;
|
||||
this.minWidth = 190;
|
||||
|
||||
function getDefaultFilterData() {
|
||||
const filterData = props.getFilterData();
|
||||
const filterItems = [];
|
||||
const selectedFilterData = cloneObjectsArray(props.selectedFilterData.filterValues);
|
||||
selectedFilterData.forEach(defaultFilterValue => {
|
||||
const filterValue = filterData.find(x => ((x.key === defaultFilterValue.key.replace(defaultFilterValue.group + "_", '')) && x.group === defaultFilterValue.group));
|
||||
let groupLabel = '';
|
||||
|
||||
const groupFilterItem = filterData.find(x => (x.key === defaultFilterValue.group));
|
||||
if (groupFilterItem != undefined) {
|
||||
groupLabel = groupFilterItem.label;
|
||||
} else {
|
||||
const subgroupFilterItem = filterData.find(x => (x.subgroup === defaultFilterValue.group))
|
||||
if (subgroupFilterItem != undefined) {
|
||||
groupLabel = subgroupFilterItem.label;
|
||||
}
|
||||
}
|
||||
|
||||
if (filterValue != undefined) {
|
||||
defaultFilterValue.key = defaultFilterValue.group + "_" + defaultFilterValue.key;
|
||||
defaultFilterValue.label = filterValue.label;
|
||||
defaultFilterValue.groupLabel = groupLabel;
|
||||
filterItems.push(defaultFilterValue);
|
||||
}
|
||||
});
|
||||
return filterItems;
|
||||
}
|
||||
|
||||
this.state = {
|
||||
sortDirection: props.selectedFilterData.sortDirection === "desc" ? true : false,
|
||||
sortId: props.getSortData().findIndex(x => x.key === props.selectedFilterData.sortId) != -1 ? props.selectedFilterData.sortId : props.getSortData().length > 0 ? props.getSortData()[0].key : "",
|
||||
searchText: props.selectedFilterData.inputValue || props.value,
|
||||
|
||||
filterValues: props.selectedFilterData ? getDefaultFilterData() : [],
|
||||
openFilterItems: [],
|
||||
hideFilterItems: []
|
||||
};
|
||||
|
||||
this.searchWrapper = React.createRef();
|
||||
this.filterWrapper = React.createRef();
|
||||
|
||||
this.onClickSortItem = this.onClickSortItem.bind(this);
|
||||
this.onSortDirectionClick = this.onSortDirectionClick.bind(this);
|
||||
this.onChangeSortDirection = this.onChangeSortDirection.bind(this);
|
||||
this.onSearch = this.onSearch.bind(this);
|
||||
this.onChangeFilter = this.onChangeFilter.bind(this);
|
||||
|
||||
this.onSearchChanged = this.onSearchChanged.bind(this);
|
||||
|
||||
this.getDefaultSelectedIndex = this.getDefaultSelectedIndex.bind(this);
|
||||
|
||||
this.updateFilter = this.updateFilter.bind(this);
|
||||
this.onClickFilterItem = this.onClickFilterItem.bind(this);
|
||||
this.getFilterData = this.getFilterData.bind(this);
|
||||
this.onFilterRender = this.onFilterRender.bind(this);
|
||||
this.onDeleteFilterItem = this.onDeleteFilterItem.bind(this);
|
||||
this.clearFilter = this.clearFilter.bind(this);
|
||||
|
||||
this.throttledResize = throttle(this.resize, 300);
|
||||
|
||||
}
|
||||
resize = () => {
|
||||
this.isResizeUpdate = true;
|
||||
this.setState({
|
||||
filterValues: this.state.filterValues,
|
||||
openFilterItems: this.state.filterValues,
|
||||
hideFilterItems: []
|
||||
})
|
||||
}
|
||||
onChangeSortDirection(key) {
|
||||
this.onFilter(this.state.filterValues, this.state.sortId, key ? "desc" : "asc");
|
||||
this.setState({ sortDirection: !!key });
|
||||
}
|
||||
getDefaultSelectedIndex() {
|
||||
const sortData = this.props.getSortData();
|
||||
if (sortData.length > 0) {
|
||||
const defaultIndex = sortData.findIndex(x => x.key === this.state.sortId);
|
||||
return defaultIndex != -1 ? defaultIndex : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
onClickSortItem(key) {
|
||||
this.setState({ sortId: key });
|
||||
this.onFilter(this.state.filterValues, key, this.state.sortDirection ? "desc" : "asc");
|
||||
}
|
||||
onSortDirectionClick() {
|
||||
|
||||
this.onFilter(this.state.filterValues, this.state.sortId, !this.state.sortDirection ? "desc" : "asc");
|
||||
this.setState({ sortDirection: !this.state.sortDirection });
|
||||
}
|
||||
onSearchChanged(value) {
|
||||
this.setState({ searchText: value });
|
||||
this.onFilter(this.state.filterValues, this.state.sortId, this.state.sortDirection ? "desc" : "asc", value);
|
||||
}
|
||||
onSearch(result) {
|
||||
this.onFilter(result.filterValues, this.state.sortId, this.state.sortDirection ? "desc" : "asc");
|
||||
}
|
||||
getFilterData() {
|
||||
const _this = this;
|
||||
const d = this.props.getFilterData();
|
||||
const result = [];
|
||||
d.forEach(element => {
|
||||
if (!element.inSubgroup) {
|
||||
element.onClick = !element.isSeparator && !element.isHeader && !element.disabled ? ((e) => _this.props.onClickFilterItem(e, element)) : undefined;
|
||||
element.key = element.group != element.key ? element.group + "_" + element.key : element.key;
|
||||
if (element.subgroup != undefined) {
|
||||
if (d.findIndex(x => x.group === element.subgroup) === -1) element.disabled = true;
|
||||
}
|
||||
result.push(element);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
clearFilter() {
|
||||
this.setState({
|
||||
searchText: '',
|
||||
filterValues: [],
|
||||
openFilterItems: [],
|
||||
hideFilterItems: []
|
||||
});
|
||||
this.onFilter([], this.state.sortId, this.state.sortDirection ? "desc" : "asc", '');
|
||||
}
|
||||
updateFilter(inputFilterItems) {
|
||||
const currentFilterItems = inputFilterItems || cloneObjectsArray(this.state.filterValues);
|
||||
const fullWidth = this.searchWrapper.current.getBoundingClientRect().width;
|
||||
const filterWidth = this.filterWrapper.current.getBoundingClientRect().width;
|
||||
const filterArr = Array.from(Array.from(this.filterWrapper.current.children).find(x => x.id === 'filter-items-container').children);
|
||||
const searchFilterButton = Array.from(this.filterWrapper.current.children).find(x => x.id != 'filter-items-container');
|
||||
|
||||
const filterButton = searchFilterButton ? Array.from(searchFilterButton.children)[0] : null;
|
||||
|
||||
if (fullWidth <= this.minWidth && fullWidth > 0) {
|
||||
this.setState({
|
||||
openFilterItems: [],
|
||||
hideFilterItems: cloneObjectsArray(currentFilterItems)
|
||||
});
|
||||
} else if (filterWidth > fullWidth / 2) {
|
||||
let newOpenFilterItems = cloneObjectsArray(currentFilterItems);
|
||||
let newHideFilterItems = [];
|
||||
|
||||
let elementsWidth = 0;
|
||||
Array.from(filterArr).forEach(element => {
|
||||
elementsWidth = elementsWidth + element.getBoundingClientRect().width;
|
||||
});
|
||||
|
||||
if ( filterButton !== null && (elementsWidth >= (fullWidth / 3) - filterButton.getBoundingClientRect().width)) {
|
||||
for (let i = 0; i < filterArr.length; i++) {
|
||||
if (elementsWidth > (fullWidth / 3) - filterButton.getBoundingClientRect().width) {
|
||||
elementsWidth = elementsWidth - filterArr[i].getBoundingClientRect().width;
|
||||
const hiddenItem = currentFilterItems.find(x => x.key === filterArr[i].getAttribute('id'));
|
||||
if (hiddenItem) newHideFilterItems.push(hiddenItem);
|
||||
newOpenFilterItems.splice(newOpenFilterItems.findIndex(x => x.key === filterArr[i].getAttribute('id')), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
openFilterItems: newOpenFilterItems,
|
||||
hideFilterItems: newHideFilterItems
|
||||
});
|
||||
|
||||
} else {
|
||||
this.setState({
|
||||
openFilterItems: currentFilterItems.slice(),
|
||||
hideFilterItems: []
|
||||
});
|
||||
}
|
||||
}
|
||||
onDeleteFilterItem(key) {
|
||||
const currentFilterItems = this.state.filterValues.slice();
|
||||
const indexFilterItem = currentFilterItems.findIndex(x => x.key === key);
|
||||
if (indexFilterItem != -1) {
|
||||
currentFilterItems.splice(indexFilterItem, 1);
|
||||
}
|
||||
this.setState({
|
||||
filterValues: currentFilterItems,
|
||||
openFilterItems: currentFilterItems,
|
||||
hideFilterItems: []
|
||||
});
|
||||
let filterValues = cloneObjectsArray(currentFilterItems);
|
||||
filterValues = filterValues.map(function (item) {
|
||||
item.key = item.key.replace(item.group + "_", '');
|
||||
return item;
|
||||
})
|
||||
this.onFilter(filterValues.filter(item => item.key != '-1'), this.state.sortId, this.state.sortDirection ? "desc" : "asc");
|
||||
}
|
||||
onFilter(filterValues, sortId, sortDirection, searchText) {
|
||||
let cloneFilterValues = cloneObjectsArray(filterValues);
|
||||
cloneFilterValues = cloneFilterValues.map(function (item) {
|
||||
item.key = item.key.replace(item.group + "_", '');
|
||||
return item;
|
||||
})
|
||||
this.props.onFilter({
|
||||
inputValue: searchText != undefined ? searchText : this.state.searchText,
|
||||
filterValues: cloneFilterValues.filter(item => item.key != '-1'),
|
||||
sortId: sortId,
|
||||
sortDirection: sortDirection
|
||||
});
|
||||
}
|
||||
onChangeFilter(result) {
|
||||
this.setState({
|
||||
searchText: result.inputValue,
|
||||
filterValues: result.filterValues,
|
||||
});
|
||||
this.onFilter(result.filterValues, this.state.sortId, this.state.sortDirection ? "desc" : "asc", result.inputValue);
|
||||
}
|
||||
onFilterRender() {
|
||||
if (this.isResizeUpdate) {
|
||||
this.isResizeUpdate = false;
|
||||
}
|
||||
|
||||
if (this.searchWrapper.current && this.filterWrapper.current) {
|
||||
const fullWidth = this.searchWrapper.current.getBoundingClientRect().width;
|
||||
const filterWidth = this.filterWrapper.current.getBoundingClientRect().width;
|
||||
if (fullWidth <= this.minWidth || filterWidth > fullWidth / 2) this.updateFilter();
|
||||
}
|
||||
}
|
||||
onClickFilterItem(event, filterItem) {
|
||||
const currentFilterItems = cloneObjectsArray(this.state.filterValues);
|
||||
|
||||
if (filterItem.subgroup) {
|
||||
const indexFilterItem = currentFilterItems.findIndex(x => x.group === filterItem.subgroup);
|
||||
if (indexFilterItem != -1) {
|
||||
currentFilterItems.splice(indexFilterItem, 1);
|
||||
}
|
||||
const subgroupItems = this.props.getFilterData().filter(t => t.group === filterItem.subgroup);
|
||||
if (subgroupItems.length > 1) {
|
||||
const selectFilterItem = {
|
||||
key: filterItem.subgroup + "_-1",
|
||||
group: filterItem.subgroup,
|
||||
label: filterItem.defaultSelectLabel,
|
||||
groupLabel: filterItem.label,
|
||||
inSubgroup: true
|
||||
};
|
||||
if (indexFilterItem != -1)
|
||||
currentFilterItems.splice(indexFilterItem, 0, selectFilterItem);
|
||||
else
|
||||
currentFilterItems.push(selectFilterItem);
|
||||
this.setState({
|
||||
filterValues: currentFilterItems,
|
||||
openFilterItems: currentFilterItems,
|
||||
hideFilterItems: []
|
||||
});
|
||||
} else if (subgroupItems.length === 1) {
|
||||
|
||||
const selectFilterItem = {
|
||||
key: subgroupItems[0].group + "_" + subgroupItems[0].key,
|
||||
group: subgroupItems[0].group,
|
||||
label: subgroupItems[0].label,
|
||||
groupLabel: this.props.getFilterData().find(x => x.subgroup === subgroupItems[0].group).label,
|
||||
inSubgroup: true
|
||||
};
|
||||
if (indexFilterItem != -1)
|
||||
currentFilterItems.splice(indexFilterItem, 0, selectFilterItem);
|
||||
else
|
||||
currentFilterItems.push(selectFilterItem);
|
||||
|
||||
const clone = cloneObjectsArray(currentFilterItems.filter(item => item.key != '-1'));
|
||||
clone.map(function (item) {
|
||||
item.key = item.key.replace(item.group + "_", '');
|
||||
return item;
|
||||
})
|
||||
this.onFilter(clone.filter(item => item.key != '-1'), this.state.sortId, this.state.sortDirection ? "desc" : "asc");
|
||||
this.setState({
|
||||
filterValues: currentFilterItems,
|
||||
openFilterItems: currentFilterItems,
|
||||
hideFilterItems: []
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const filterItems = this.getFilterData();
|
||||
|
||||
const indexFilterItem = currentFilterItems.findIndex(x => x.group === filterItem.group);
|
||||
if (indexFilterItem != -1) {
|
||||
currentFilterItems.splice(indexFilterItem, 1);
|
||||
}
|
||||
|
||||
const selectFilterItem = {
|
||||
key: filterItem.key,
|
||||
group: filterItem.group,
|
||||
label: filterItem.label,
|
||||
groupLabel: filterItem.inSubgroup ? filterItems.find(x => x.subgroup === filterItem.group).label : filterItems.find(x => x.key === filterItem.group).label
|
||||
};
|
||||
if (indexFilterItem != -1)
|
||||
currentFilterItems.splice(indexFilterItem, 0, selectFilterItem);
|
||||
else
|
||||
currentFilterItems.push(selectFilterItem);
|
||||
this.setState({
|
||||
filterValues: currentFilterItems,
|
||||
openFilterItems: currentFilterItems,
|
||||
hideFilterItems: []
|
||||
});
|
||||
|
||||
const clone = cloneObjectsArray(currentFilterItems.filter(item => item.key != '-1'));
|
||||
clone.map(function (item) {
|
||||
item.key = item.key.replace(item.group + "_", '');
|
||||
return item;
|
||||
})
|
||||
this.onFilter(clone.filter(item => item.key != '-1'), this.state.sortId, this.state.sortDirection ? "desc" : "asc");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('resize', this.throttledResize);
|
||||
if (this.state.filterValues.length > 0) this.updateFilter();
|
||||
}
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('resize', this.throttledResize);
|
||||
}
|
||||
componentDidUpdate(prevProps){
|
||||
if(this.props.needForUpdate && this.props.needForUpdate(prevProps, this.props)){
|
||||
let internalFilterData = convertToInternalData(this.props.getFilterData(), cloneObjectsArray(this.props.selectedFilterData.filterValues));
|
||||
this.updateFilter(internalFilterData);
|
||||
}
|
||||
}
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
if (!isEqual(this.props.selectedFilterData, nextProps.selectedFilterData)) {
|
||||
let internalFilterData = cloneObjectsArray(this.state.filterValues);
|
||||
if (nextProps.selectedFilterData.filterValues) {
|
||||
internalFilterData = convertToInternalData(this.props.getFilterData(), cloneObjectsArray(nextProps.selectedFilterData.filterValues));
|
||||
this.updateFilter(internalFilterData);
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
sortDirection: nextProps.selectedFilterData.sortDirection === "desc" ? true : false,
|
||||
sortId: this.props.getSortData().findIndex(x => x.key === nextProps.selectedFilterData.sortId) != -1 ? nextProps.selectedFilterData.sortId : "",
|
||||
filterValues: internalFilterData,
|
||||
searchText: nextProps.selectedFilterData.inputValue || this.props.value
|
||||
}
|
||||
);
|
||||
return true;
|
||||
}
|
||||
if (this.props.id != nextProps.id ||
|
||||
this.props.isDisabled != nextProps.isDisabled ||
|
||||
this.props.size != nextProps.size ||
|
||||
this.props.placeholder != nextProps.placeholder ||
|
||||
this.props.value != nextProps.value)
|
||||
|
||||
return true;
|
||||
if (this.isResizeUpdate) {
|
||||
return true;
|
||||
}
|
||||
return !isEqual(this.state, nextState);
|
||||
}
|
||||
render() {
|
||||
//console.log("FilterInput render");
|
||||
let iconSize = 33;
|
||||
switch (this.props.size) {
|
||||
case 'base':
|
||||
iconSize = 33;
|
||||
break;
|
||||
case 'middle':
|
||||
case 'big':
|
||||
case 'huge':
|
||||
iconSize = 41;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (
|
||||
<StyledFilterInput className={this.props.className} id={this.props.id} style={this.props.style}>
|
||||
<StyledSearchInput ref={this.searchWrapper}>
|
||||
<SearchInput
|
||||
id={this.props.id}
|
||||
isDisabled={this.props.isDisabled}
|
||||
size={this.props.size}
|
||||
scale={this.props.scale}
|
||||
isNeedFilter={true}
|
||||
getFilterData={this.props.getFilterData}
|
||||
placeholder={this.props.placeholder}
|
||||
onSearchClick={this.onSearch}
|
||||
onChangeFilter={this.onChangeFilter}
|
||||
value={this.state.searchText}
|
||||
selectedFilterData={this.state.filterValues}
|
||||
showClearButton={this.state.filterValues.length > 0}
|
||||
onClearSearch={this.clearFilter}
|
||||
onChange={this.onSearchChanged}
|
||||
>
|
||||
<StyledFilterBlock ref={this.filterWrapper}>
|
||||
<FilterBlock
|
||||
openFilterItems={this.state.openFilterItems}
|
||||
hideFilterItems={this.state.hideFilterItems}
|
||||
iconSize={iconSize}
|
||||
getFilterData={this.props.getFilterData}
|
||||
onClickFilterItem={this.onClickFilterItem}
|
||||
onDeleteFilterItem={this.onDeleteFilterItem}
|
||||
isResizeUpdate={this.isResizeUpdate}
|
||||
onRender={this.onFilterRender}
|
||||
isDisabled={this.props.isDisabled}
|
||||
/>
|
||||
</StyledFilterBlock>
|
||||
|
||||
</SearchInput>
|
||||
</StyledSearchInput>
|
||||
|
||||
<SortComboBox
|
||||
options={this.props.getSortData()}
|
||||
isDisabled={this.props.isDisabled}
|
||||
onChangeSortId={this.onClickSortItem}
|
||||
onChangeSortDirection={this.onChangeSortDirection}
|
||||
selectedOption={this.props.getSortData().length > 0 ? this.props.getSortData().find(x => x.key === this.state.sortId) : {}}
|
||||
onButtonClick={this.onSortDirectionClick}
|
||||
sortDirection={+this.state.sortDirection}
|
||||
directionAscLabel={this.props.directionAscLabel}
|
||||
directionDescLabel={this.props.directionDescLabel}
|
||||
/>
|
||||
</StyledFilterInput>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FilterInput.protoTypes = {
|
||||
size: PropTypes.oneOf(['base', 'middle', 'big', 'huge']),
|
||||
autoRefresh: PropTypes.bool,
|
||||
selectedFilterData: PropTypes.object,
|
||||
directionAscLabel: PropTypes.string,
|
||||
directionDescLabel: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
id: PropTypes.string,
|
||||
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
||||
needForUpdate: PropTypes.bool
|
||||
};
|
||||
|
||||
FilterInput.defaultProps = {
|
||||
autoRefresh: true,
|
||||
selectedFilterData: {
|
||||
sortDirection: false,
|
||||
sortId: '',
|
||||
filterValues: [],
|
||||
searchText: ''
|
||||
},
|
||||
size: 'base',
|
||||
needForUpdate: false,
|
||||
directionAscLabel: 'A-Z',
|
||||
directionDescLabel: 'Z-A'
|
||||
};
|
||||
|
||||
export default FilterInput;
|
@ -1,166 +0,0 @@
|
||||
import React from 'react';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import ComboBox from '../combobox'
|
||||
import IconButton from '../icon-button';
|
||||
import DropDownItem from '../drop-down-item';
|
||||
import RadioButtonGroup from '../radio-button-group'
|
||||
import styled from 'styled-components';
|
||||
import PropTypes from 'prop-types';
|
||||
import { mobile } from '../../utils/device'
|
||||
|
||||
const StyledIconButton = styled.div`
|
||||
transform: ${state => !state.sortDirection ? 'scale(1, -1)' : 'scale(1)'};
|
||||
`;
|
||||
const StyledComboBox = styled(ComboBox)`
|
||||
display: block;
|
||||
float: left;
|
||||
width: 132px;
|
||||
margin-left: 8px;
|
||||
|
||||
@media ${mobile} {
|
||||
width: 50px;
|
||||
.optionalBlock ~ div:first-child{
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
|
||||
.combo-button-label {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
class SortComboBox extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
sortDirection: this.props.sortDirection
|
||||
}
|
||||
|
||||
this.combobox = React.createRef();
|
||||
|
||||
this.onChangeSortId = this.onChangeSortId.bind(this);
|
||||
this.onChangeSortDirection = this.onChangeSortDirection.bind(this);
|
||||
this.onButtonClick = this.onButtonClick.bind(this);
|
||||
|
||||
}
|
||||
onButtonClick() {
|
||||
typeof this.props.onChangeSortDirection === 'function' && this.props.onChangeSortDirection(+(this.state.sortDirection === 0 ? 1 : 0));
|
||||
this.setState({
|
||||
sortDirection: this.state.sortDirection === 0 ? 1 : 0
|
||||
});
|
||||
}
|
||||
|
||||
onChangeSortId(e) {
|
||||
typeof this.props.onChangeSortId === 'function' && this.props.onChangeSortId(e.target.value);
|
||||
}
|
||||
onChangeSortDirection(e) {
|
||||
this.setState({
|
||||
sortDirection: +e.target.value
|
||||
});
|
||||
typeof this.props.onChangeSortDirection === 'function' && this.props.onChangeSortDirection(+e.target.value);
|
||||
}
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
//TODO
|
||||
/*const comboboxText = this.combobox.current.ref.current.children[0].children[1];
|
||||
if(comboboxText.scrollWidth > Math.round(comboboxText.getBoundingClientRect().width)){
|
||||
comboboxText.style.opacity = "0";
|
||||
}else{
|
||||
comboboxText.style.opacity = "1";
|
||||
}*/
|
||||
if (this.props.sortDirection !== nextProps.sortDirection) {
|
||||
this.setState({
|
||||
sortDirection: nextProps.sortDirection
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return (!isEqual(this.props, nextProps) || !isEqual(this.state, nextState));
|
||||
}
|
||||
render() {
|
||||
let sortArray = this.props.options.map(function (item) {
|
||||
item.value = item.key
|
||||
return item;
|
||||
});
|
||||
let sortDirectionArray = [
|
||||
{ value: '0', label: this.props.directionAscLabel },
|
||||
{ value: '1', label: this.props.directionDescLabel }
|
||||
];
|
||||
|
||||
const isMobile = window.innerWidth > 375; //TODO: Make some better
|
||||
|
||||
const advancedOptions = (
|
||||
<>
|
||||
<DropDownItem noHover >
|
||||
<RadioButtonGroup
|
||||
orientation='vertical'
|
||||
onClick={this.onChangeSortDirection}
|
||||
isDisabled={this.props.isDisabled}
|
||||
selected={this.state.sortDirection.toString()}
|
||||
spacing='0px'
|
||||
name={'direction'}
|
||||
options={sortDirectionArray}
|
||||
fontWeight ={600}
|
||||
/>
|
||||
</DropDownItem>
|
||||
<DropDownItem isSeparator />
|
||||
<DropDownItem noHover >
|
||||
<RadioButtonGroup
|
||||
orientation='vertical'
|
||||
onClick={this.onChangeSortId}
|
||||
isDisabled={this.props.isDisabled}
|
||||
selected={this.props.selectedOption.key}
|
||||
spacing='0px'
|
||||
name={'sort'}
|
||||
options={sortArray}
|
||||
fontWeight ={600}
|
||||
/>
|
||||
</DropDownItem>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<StyledComboBox
|
||||
ref={this.combobox}
|
||||
options={[]}
|
||||
advancedOptions={advancedOptions}
|
||||
isDisabled={this.props.isDisabled}
|
||||
selectedOption={this.props.selectedOption}
|
||||
scaled={true}
|
||||
scaledOptions={isMobile}
|
||||
size="content"
|
||||
directionX="right"
|
||||
>
|
||||
<StyledIconButton sortDirection={!!this.state.sortDirection}>
|
||||
<IconButton
|
||||
color={"#A3A9AE"}
|
||||
hoverColor={"#333"}
|
||||
clickColor={"#333"}
|
||||
size={10}
|
||||
iconName={'ZASortingIcon'}
|
||||
isFill={true}
|
||||
isDisabled={this.props.isDisabled}
|
||||
onClick={this.onButtonClick}
|
||||
/>
|
||||
</StyledIconButton>
|
||||
</StyledComboBox>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SortComboBox.propTypes = {
|
||||
isDisabled: PropTypes.bool,
|
||||
sortDirection: PropTypes.number,
|
||||
onChangeSortId: PropTypes.func,
|
||||
onChangeSortDirection: PropTypes.func,
|
||||
onButtonClick: PropTypes.func,
|
||||
directionAscLabel: PropTypes.string,
|
||||
directionDescLabel: PropTypes.string
|
||||
}
|
||||
|
||||
SortComboBox.defaultProps = {
|
||||
isDisabled: false,
|
||||
sortDirection: 0
|
||||
}
|
||||
|
||||
|
||||
export default SortComboBox;
|
@ -16,7 +16,6 @@ export { default as DropDownItem } from './components/drop-down-item'
|
||||
export { default as EmailInput } from './components/email-input'
|
||||
export { default as EmptyScreenContainer} from './components/empty-screen-container'
|
||||
export { default as FieldContainer } from './components/field-container'
|
||||
export { default as FilterInput } from './components/filter-input'
|
||||
export { default as GroupButton } from './components/group-button'
|
||||
export { default as GroupButtonsMenu } from './components/group-buttons-menu'
|
||||
export { default as Heading } from './components/heading'
|
||||
|
Loading…
Reference in New Issue
Block a user