Merge branch 'develop' into feature/version-hostory-redesign

This commit is contained in:
Artem Tarasov 2020-11-17 11:48:55 +03:00
commit efacc50ac4
14 changed files with 452 additions and 447 deletions

View File

@ -9,7 +9,7 @@
"ConnectionStrings": {
"default": {
"name": "default",
"connectionString": "Server=172.18.0.3;Port=3306;Database=onlyoffice;User ID=onlyoffice_user;Password=onlyoffice_pass;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none",
"connectionString": "Server=172.18.0.5;Port=3306;Database=onlyoffice;User ID=onlyoffice_user;Password=onlyoffice_pass;Pooling=true;Character Set=utf8;AutoEnlist=false;SSL Mode=none",
"providerName": "MySql.Data.MySqlClient"
}
},

View File

@ -16,10 +16,12 @@ import find from "lodash/find";
import result from "lodash/result";
import { withTranslation } from "react-i18next";
import { withRouter } from "react-router";
import { constants, FilterInput, store, Loaders } from "asc-web-common";
import { constants, FilterInput, store, Loaders, utils } from "asc-web-common";
import isEqual from "lodash/isEqual";
import { isMobileOnly } from "react-device-detect";
const { withLayoutSize } = utils;
const {
getCurrentUser,
getSettingsCustomNames,
@ -287,20 +289,22 @@ class SectionFilterContent extends React.Component {
this.props.selectedFolderId !== nextProps.selectedFolderId ||
this.state.isReady !== nextState.isReady ||
this.props.viewAs !== nextProps.viewAs ||
this.props.firstLoad !== nextProps.firstLoad
this.props.firstLoad !== nextProps.firstLoad ||
this.props.sectionWidth !== nextProps.sectionWidth
);
}
render() {
console.log("Filter render");
const selectedFilterData = this.getSelectedFilterData();
const { t, language, firstLoad } = this.props;
const { t, language, firstLoad, sectionWidth } = this.props;
const filterColumnCount =
window.innerWidth < 500 ? {} : { filterColumnCount: 3 };
return firstLoad ? (
<Loaders.Filter />
) : (
<FilterInput
sectionWidth={sectionWidth}
getFilterData={this.getData}
getSortData={this.getSortData}
selectedFilterData={selectedFilterData}
@ -338,4 +342,4 @@ export default connect(mapStateToProps, {
fetchFiles,
setViewAs,
setIsLoading,
})(withRouter(withTranslation()(SectionFilterContent)));
})(withRouter(withLayoutSize(withTranslation()(SectionFilterContent))));

View File

@ -19,7 +19,6 @@
<PackageReference Include="AppLimit.CloudComputing.SharpBox" Version="1.1.0.451" />
<PackageReference Include="Box.V2.Core" Version="3.24.0" />
<PackageReference Include="DocuSign.eSign.dll" Version="4.4.1" />
<PackageReference Include="DotNetZip" Version="1.13.8" />
<PackageReference Include="Dropbox.Api" Version="4.10.0" />
<PackageReference Include="Google.Apis.Drive.v3" Version="1.49.0.2111" />
<PackageReference Include="Grpc.Tools" Version="2.32.0">
@ -29,6 +28,7 @@
<PackageReference Include="Microsoft.OneDriveSDK" Version="2.0.7.5" />
<PackageReference Include="Microsoft.SharePoint.Client" Version="14.0.4762.1000" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.4" />
<PackageReference Include="SharpCompress" Version="0.26.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.1" />
</ItemGroup>

View File

@ -45,11 +45,13 @@ using ASC.Web.Files.Helpers;
using ASC.Web.Files.Utils;
using ASC.Web.Studio.Core;
using Ionic.Zip;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;
using Microsoft.Extensions.Primitives;
using SharpCompress.Common;
using SharpCompress.Writers;
using SharpCompress.Writers.Zip;
namespace ASC.Web.Files.Services.WCFService.FileOperations
{
internal class FileDownloadOperationData<T> : FileOperationData<T>
@ -84,13 +86,13 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
using var scope = ThirdPartyOperation.CreateScope();
var scopeClass = scope.ServiceProvider.GetService<FileDownloadOperationScope>();
var (globalStore, filesLinkUtility, _, _, _) = scopeClass;
using var stream = TempStream.Create();
using (var zip = new ZipOutputStream(stream, true)
{
CompressionLevel = Ionic.Zlib.CompressionLevel.Level3,
AlternateEncodingUsage = ZipOption.AsNecessary,
AlternateEncoding = Encoding.UTF8,
})
using var stream = TempStream.Create();
var writerOptions = new ZipWriterOptions(CompressionType.Deflate);
writerOptions.ArchiveEncoding.Default = Encoding.UTF8;
writerOptions.DeflateCompressionLevel = SharpCompress.Compressors.Deflate.CompressionLevel.Level3;
using (var zip = WriterFactory.Open(stream, ArchiveType.Zip, writerOptions))
{
(ThirdPartyOperation as FileDownloadOperation<string>).CompressToZip(zip, stream, scope);
(DaoOperation as FileDownloadOperation<int>).CompressToZip(zip, stream, scope);
@ -125,19 +127,16 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
get { return FileOperationType.Download; }
}
public bool Compress { get; }
public FileDownloadOperation(IServiceProvider serviceProvider, FileDownloadOperationData<T> fileDownloadOperationData, bool compress = true)
public FileDownloadOperation(IServiceProvider serviceProvider, FileDownloadOperationData<T> fileDownloadOperationData)
: base(serviceProvider, fileDownloadOperationData)
{
files = fileDownloadOperationData.FilesDownload;
headers = fileDownloadOperationData.Headers;
Compress = compress;
}
protected override void Do(IServiceScope scope)
{
if (!Compress && !Files.Any() && !Folders.Any()) return;
if (!Files.Any() && !Folders.Any()) return;
entriesPathId = GetEntriesPathId(scope);
if (entriesPathId == null || entriesPathId.Count == 0)
@ -150,36 +149,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
throw new DirectoryNotFoundException(FilesCommonResource.ErrorMassage_FolderNotFound);
}
var scopeClass = scope.ServiceProvider.GetService<FileDownloadOperationScope>();
var (globalStore, filesLinkUtility, _, _, _) = scopeClass;
ReplaceLongPath(entriesPathId);
if (Compress)
{
using var stream = TempStream.Create();
using var zip = new ZipOutputStream(stream, true)
{
CompressionLevel = Ionic.Zlib.CompressionLevel.Level3,
AlternateEncodingUsage = ZipOption.AsNecessary,
AlternateEncoding = Encoding.UTF8
};
CompressToZip(zip, stream, scope);
if (stream != null)
{
stream.Position = 0;
const string fileName = FileConstant.DownloadTitle + ".zip";
var store = globalStore.GetStore();
store.Save(
FileConstant.StorageDomainTmp,
string.Format(@"{0}\{1}", ((IAccount)Thread.CurrentPrincipal.Identity).ID, fileName),
stream,
"application/zip",
"attachment; filename=\"" + fileName + "\"");
Status = string.Format("{0}?{1}=bulk", filesLinkUtility.FileHandlerPath, FilesLinkUtility.Action);
}
}
}
private ItemNameValueCollection<T> ExecPathFromFile(IServiceScope scope, File<T> file, string path)
@ -260,7 +230,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
return entriesPathId;
}
internal void CompressToZip(ZipOutputStream zip, Stream stream, IServiceScope scope)
internal void CompressToZip(IWriter zip, Stream stream, IServiceScope scope)
{
if (entriesPathId == null) return;
var scopeClass = scope.ServiceProvider.GetService<FileDownloadOperationScope>();
@ -325,17 +295,17 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
}
}
zip.PutNextEntry(newtitle);
if (!entryId.Equals(default(T)) && file != null)
{
{
Stream readStream = null;
try
{
if (fileConverter.EnableConvert(file, convertToExt))
{
//Take from converter
using var readStream = fileConverter.Exec(file, convertToExt);
readStream.CopyTo(zip);
readStream = fileConverter.Exec(file, convertToExt);
if (!string.IsNullOrEmpty(convertToExt))
{
filesMessageService.Send(file, headers, MessageAction.FileDownloadedAs, file.Title, convertToExt);
@ -347,15 +317,24 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
}
else
{
using var readStream = FileDao.GetFileStream(file);
readStream.CopyTo(zip);
readStream = FileDao.GetFileStream(file);
filesMessageService.Send(file, headers, MessageAction.FileDownloaded, file.Title);
}
}
zip.Write(newtitle, readStream);
}
catch (Exception ex)
{
Error = ex.Message;
Logger.Error(Error, ex);
}
finally
{
if (readStream != null)
{
readStream.Close();
readStream.Dispose();
}
}
}
counter++;

View File

@ -122,8 +122,8 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
throw new InvalidOperationException(FilesCommonResource.ErrorMassage_ManyDownloads);
}
var op1 = new FileDownloadOperation<int>(ServiceProvider, new FileDownloadOperationData<int>(folders.Where(r => r.Key.ValueKind == JsonValueKind.Number).ToDictionary(r => r.Key.GetInt32(), r => r.Value), files.Where(r => r.Key.ValueKind == JsonValueKind.Number).ToDictionary(r => r.Key.GetInt32(), r => r.Value), tenant, headers), false);
var op2 = new FileDownloadOperation<string>(ServiceProvider, new FileDownloadOperationData<string>(folders.Where(r => r.Key.ValueKind == JsonValueKind.String).ToDictionary(r => r.Key.GetString(), r => r.Value), files.Where(r => r.Key.ValueKind == JsonValueKind.String).ToDictionary(r => r.Key.GetString(), r => r.Value), tenant, headers), false);
var op1 = new FileDownloadOperation<int>(ServiceProvider, new FileDownloadOperationData<int>(folders.Where(r => r.Key.ValueKind == JsonValueKind.Number).ToDictionary(r => r.Key.GetInt32(), r => r.Value), files.Where(r => r.Key.ValueKind == JsonValueKind.Number).ToDictionary(r => r.Key.GetInt32(), r => r.Value), tenant, headers));
var op2 = new FileDownloadOperation<string>(ServiceProvider, new FileDownloadOperationData<string>(folders.Where(r => r.Key.ValueKind == JsonValueKind.String).ToDictionary(r => r.Key.GetString(), r => r.Value), files.Where(r => r.Key.ValueKind == JsonValueKind.String).ToDictionary(r => r.Key.GetString(), r => r.Value), tenant, headers));
var op = new FileDownloadOperation(ServiceProvider, op2, op1);
return QueueTask(userId, op);

View File

@ -19,26 +19,6 @@
<DebugType>none</DebugType>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AppLimit.CloudComputing.SharpBox" Version="1.1.0.451" />
<PackageReference Include="Box.V2.Core" Version="3.24.0" />
<PackageReference Include="DocuSign.eSign.dll" Version="4.4.1" />
<PackageReference Include="DotNetZip" Version="1.13.8" />
<PackageReference Include="Dropbox.Api" Version="4.10.0" />
<PackageReference Include="Google.Apis.Drive.v3" Version="1.49.0.2111" />
<PackageReference Include="Grpc.Tools" Version="2.32.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.OneDriveSDK" Version="2.0.7.5" />
<PackageReference Include="Microsoft.SharePoint.Client" Version="14.0.4762.1000" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.4" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\ASC.Api.Core\ASC.Api.Core.csproj" />
<ProjectReference Include="..\..\..\common\ASC.Common\ASC.Common.csproj" />

View File

@ -6,7 +6,7 @@ import result from "lodash/result";
import { withTranslation } from "react-i18next";
import { withRouter } from "react-router";
import { getFilterByLocation } from "../../../../../helpers/converters";
import { store, FilterInput, Loaders } from "asc-web-common";
import { store, FilterInput, Loaders, utils } from "asc-web-common";
import { isMobileOnly } from "react-device-detect";
import { getFilter, getGroups } from "../../../../../store/people/selectors";
const {
@ -17,6 +17,8 @@ const {
getIsLoaded,
} = store.auth.selectors;
const { withLayoutSize } = utils;
const getEmployeeStatus = (filterValues) => {
const employeeStatus = result(
find(filterValues, (value) => {
@ -248,9 +250,10 @@ class SectionFilterContent extends React.Component {
render() {
const selectedFilterData = this.getSelectedFilterData();
const { t, language, isLoaded } = this.props;
const { t, language, isLoaded, sectionWidth } = this.props;
return isLoaded ? (
<FilterInput
sectionWidth={sectionWidth}
getFilterData={this.getData}
getSortData={this.getSortData}
selectedFilterData={selectedFilterData}
@ -282,5 +285,5 @@ function mapStateToProps(state) {
}
export default connect(mapStateToProps, { fetchPeople })(
withRouter(withTranslation()(SectionFilterContent))
withRouter(withLayoutSize(withTranslation()(SectionFilterContent)))
);

View File

@ -1,6 +1,6 @@
{
"name": "asc-web-common",
"version": "1.0.279",
"version": "1.0.275",
"description": "Ascensio System SIA common components and solutions library",
"license": "AGPL-3.0",
"files": [

View File

@ -2,7 +2,6 @@ import React from "react";
import PropTypes from "prop-types";
import { SearchInput } from "asc-web-components";
import isEqual from "lodash/isEqual";
import throttle from "lodash/throttle";
import FilterBlock from "./sub-components/FilterBlock";
import SortComboBox from "./sub-components/SortComboBox";
import ViewSelector from "./sub-components/ViewSelector";
@ -81,203 +80,122 @@ const convertToInternalData = function (fullDataArray, inputDataArray) {
return filterItems;
};
const minWidth = 170;
const filterItemPadding = 60;
const maxFilterItemWidth = 260;
const itemsContainerWidth = 40;
const sectionPaddings = 48;
class FilterInput extends React.Component {
constructor(props) {
super(props);
this.isResizeUpdate = false;
this.minWidth = 190;
const { selectedFilterData, getSortData, value } = props;
const { sortDirection, sortId, inputValue } = selectedFilterData;
const sortData = getSortData();
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;
}
let filterValues = props.selectedFilterData ? getDefaultFilterData() : [];
filterValues = [
...filterValues,
...this.convertSelectorToInternalData(
props.getFilterData(),
cloneObjectsArray(props.selectedFilterData.filterValues)
),
];
const filterValues = selectedFilterData ? this.getDefaultFilterData() : [];
this.state = {
sortDirection:
props.selectedFilterData.sortDirection === "desc" ? true : false,
sortDirection: 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
sortData.findIndex((x) => x.key === sortId) != -1
? sortId
: sortData.length > 0
? sortData[0].key
: "",
searchText: props.selectedFilterData.inputValue || props.value,
searchText: inputValue || value,
filterValues,
openFilterItems: [],
hideFilterItems: [],
hiddenFilterItems: [],
needUpdateFilter: false,
};
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.onClickViewSelector = this.onClickViewSelector.bind(this);
this.throttledResize = throttle(this.resize, 300);
this.rectComboBoxRef = React.createRef();
}
componentDidMount() {
window.addEventListener("resize", this.throttledResize);
if (this.state.filterValues.length > 0) this.updateFilter();
}
componentWillUnmount() {
window.removeEventListener("resize", this.throttledResize);
}
componentDidUpdate(prevProps, prevState) {
const { selectedFilterData, sectionWidth, getSortData } = this.props;
const { filterValues, searchText } = this.state;
const { sortDirection, sortId, inputValue } = selectedFilterData;
if (
this.props.needForUpdate &&
this.props.needForUpdate(prevProps, this.props)
) {
let internalFilterData = convertToInternalData(
this.props.getFilterData(),
cloneObjectsArray(this.props.selectedFilterData.filterValues)
cloneObjectsArray(selectedFilterData.filterValues)
);
this.updateFilter(internalFilterData);
}
if (sectionWidth !== prevProps.sectionWidth) {
this.updateFilter();
}
if (
(!isEqual(selectedFilterData.filterValues, filterValues) ||
inputValue !== searchText) &&
sectionWidth !== prevProps.sectionWidth
) {
const sortData = getSortData();
const filterValues = this.getDefaultFilterData();
this.setState({
sortDirection: sortDirection === "desc" ? true : false,
sortId:
sortData.findIndex((x) => x.key === sortId) != -1
? sortId
: sortData.length > 0
? sortData[0].key
: "",
filterValues: filterValues,
searchText: selectedFilterData.inputValue || "",
});
this.updateFilter(filterValues);
}
if (
!isEqual(
prevProps.selectedFilterData.filterValues,
selectedFilterData.filterValues
) &&
selectedFilterData.filterValues &&
(selectedFilterData.filterValues.length === 0 ||
(selectedFilterData.filterValues.length === 1 &&
selectedFilterData.filterValues[0].key === "null")) &&
!selectedFilterData.inputValue
) {
this.clearFilter();
}
}
shouldComponentUpdate(nextProps, nextState) {
const {
selectedFilterData,
getFilterData,
getSortData,
value,
id,
isDisabled,
size,
placeholder,
sectionWidth,
} = this.props;
if (!isEqual(selectedFilterData, nextProps.selectedFilterData)) {
let internalFilterData = cloneObjectsArray(this.state.filterValues);
if (nextProps.selectedFilterData.filterValues) {
internalFilterData = convertToInternalData(
getFilterData(),
cloneObjectsArray(nextProps.selectedFilterData.filterValues)
);
let internalFilterDataSelectors = this.convertSelectorToInternalData(
getFilterData(),
cloneObjectsArray(nextProps.selectedFilterData.filterValues)
);
internalFilterData = internalFilterData.concat(
internalFilterDataSelectors
);
this.updateFilter(internalFilterData);
}
this.setState({
sortDirection:
nextProps.selectedFilterData.sortDirection === "desc" ? true : false,
sortId:
getSortData().findIndex(
(x) => x.key === nextProps.selectedFilterData.sortId
) != -1
? nextProps.selectedFilterData.sortId
: "",
filterValues: internalFilterData,
searchText: nextProps.selectedFilterData.inputValue || value,
});
if (
!isEqual(selectedFilterData, nextProps.selectedFilterData) ||
this.props.viewAs !== nextProps.viewAs ||
this.props.widthProp !== nextProps.widthProp ||
sectionWidth !== nextProps.sectionWidth
) {
return true;
}
if (this.props.viewAs !== nextProps.viewAs) {
return true;
}
if (this.props.isReady !== nextProps.isReady) {
let internalFilterData = cloneObjectsArray(this.state.filterValues);
internalFilterData = convertToInternalData(
getFilterData(),
cloneObjectsArray(nextProps.selectedFilterData.filterValues)
);
let internalFilterDataSelectors = this.convertSelectorToInternalData(
getFilterData(),
cloneObjectsArray(nextProps.selectedFilterData.filterValues)
);
internalFilterData = internalFilterData.concat(
internalFilterDataSelectors
);
this.updateFilter(internalFilterData);
this.setState({
sortDirection:
nextProps.selectedFilterData.sortDirection === "desc" ? true : false,
sortId:
getSortData().findIndex(
(x) => x.key === nextProps.selectedFilterData.sortId
) != -1
? nextProps.selectedFilterData.sortId
: "",
filterValues: internalFilterData,
searchText: nextProps.selectedFilterData.inputValue || value,
});
// return true;
}
if (
id != nextProps.id ||
isDisabled != nextProps.isDisabled ||
@ -286,96 +204,41 @@ class FilterInput extends React.Component {
value != nextProps.value
)
return true;
if (this.isResizeUpdate) {
return true;
}
return !isEqual(this.state, nextState);
}
convertSelectorToInternalData = (filterData, filterValues) => {
const resultValues = [];
filterValues.forEach((item) => {
const isSelector = item.group.includes("filter-author");
if (isSelector) {
const typeSelector = item.key.includes("user")
? "user"
: item.key.includes("group")
? "group"
: null;
const hasUnderscore = item.key.indexOf("_") !== -1;
const key = hasUnderscore
? item.key.slice(0, item.key.indexOf("_"))
: item.key;
const finded = filterData.find(
(x) => x.key === key && x.group === item.group
);
if (!finded) return;
const convertedItem = {
key: item.group + "_" + item.key,
label: finded.label,
group: item.group,
groupLabel: finded.label,
typeSelector,
groupsCaption: finded.groupsCaption,
defaultOptionLabel: finded.defaultOptionLabel,
defaultOption: finded.defaultOption,
defaultSelectLabel: finded.defaultSelectLabel,
selectedItem: finded.selectedItem,
};
resultValues.push(convertedItem);
}
});
return resultValues;
};
resize = () => {
this.isResizeUpdate = true;
this.setState({
filterValues: this.state.filterValues,
openFilterItems: this.state.filterValues,
hideFilterItems: [],
});
};
onChangeSortDirection(key) {
onChangeSortDirection = (key) => {
this.onFilter(
this.state.filterValues,
this.state.sortId,
key ? "desc" : "asc"
);
this.setState({ sortDirection: !!key });
}
onClickViewSelector(item) {
};
onClickViewSelector = (item) => {
const itemId = (item.target && item.target.dataset.for) || item;
const viewAs = itemId.indexOf("row") === -1 ? "tile" : "row";
this.props.onChangeViewAs(viewAs);
}
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) {
};
onClickSortItem = (key) => {
this.setState({ sortId: key });
this.onFilter(
this.state.filterValues,
key,
this.state.sortDirection ? "desc" : "asc"
);
}
onSortDirectionClick() {
};
onSortDirectionClick = () => {
this.onFilter(
this.state.filterValues,
this.state.sortId,
!this.state.sortDirection ? "desc" : "asc"
);
this.setState({ sortDirection: !this.state.sortDirection });
}
onSearchChanged(value) {
};
onSearchChanged = (value) => {
this.setState({ searchText: value });
this.onFilter(
this.state.filterValues,
@ -383,23 +246,93 @@ class FilterInput extends React.Component {
this.state.sortDirection ? "desc" : "asc",
value
);
}
onSearch(result) {
};
onSearch = (result) => {
this.onFilter(
result.filterValues,
this.state.sortId,
this.state.sortDirection ? "desc" : "asc"
);
}
getFilterData() {
const _this = this;
};
getDefaultFilterData = () => {
const { getFilterData, selectedFilterData } = this.props;
const filterData = getFilterData();
const filterItems = [];
const filterValues = cloneObjectsArray(selectedFilterData.filterValues);
for (let item of filterValues) {
const filterValue = filterData.find(
(x) => x.key === item.key && x.group === item.group
);
if (!filterValue) {
const isSelector = item.group.includes("filter-author");
if (isSelector) {
const typeSelector = item.key.includes("user")
? "user"
: item.key.includes("group")
? "group"
: null;
const underlined = item.key.indexOf("_") !== -1;
const key = underlined
? item.key.slice(0, item.key.indexOf("_"))
: item.key;
const filesFilterValue = filterData.find(
(x) => x.key === key && x.group === item.group
);
if (filesFilterValue) {
const convertedItem = {
key: item.group + "_" + item.key,
label: filesFilterValue.label,
group: item.group,
groupLabel: filesFilterValue.label,
typeSelector,
groupsCaption: filesFilterValue.groupsCaption,
defaultOptionLabel: filesFilterValue.defaultOptionLabel,
defaultOption: filesFilterValue.defaultOption,
defaultSelectLabel: filesFilterValue.defaultSelectLabel,
selectedItem: filesFilterValue.selectedItem,
};
filterItems.push(convertedItem);
}
}
}
let groupLabel = "";
const groupFilterItem = filterData.find((x) => x.key === item.group);
if (groupFilterItem) {
groupLabel = groupFilterItem.label;
} else {
const subgroupFilterItem = filterData.find(
(x) => x.subgroup === item.group
);
if (subgroupFilterItem) {
groupLabel = subgroupFilterItem.label;
}
}
if (filterValue) {
item.key = item.group + "_" + item.key;
item.label = filterValue.selectedItem
? filterValue.selectedItem.label
: filterValue.label;
item.groupLabel = groupLabel;
filterItems.push(item);
}
}
return filterItems;
};
getFilterData = () => {
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)
? () => this.onClickFilterItem(element)
: undefined;
element.key =
element.group != element.key
@ -413,13 +346,13 @@ class FilterInput extends React.Component {
}
});
return result;
}
clearFilter() {
};
clearFilter = () => {
this.setState({
searchText: "",
filterValues: [],
openFilterItems: [],
hideFilterItems: [],
hiddenFilterItems: [],
});
this.onFilter(
[],
@ -427,77 +360,135 @@ class FilterInput extends React.Component {
this.state.sortDirection ? "desc" : "asc",
""
);
}
updateFilter(inputFilterItems) {
const currentFilterItems =
inputFilterItems || cloneObjectsArray(this.state.filterValues);
};
getTextWidth = (text, font) => {
var canvas =
this.getTextWidth.canvas ||
(this.getTextWidth.canvas = document.createElement("canvas"));
var context = canvas.getContext("2d");
context.font = font;
var metrics = context.measureText(text);
return metrics.width;
};
calcHiddenItemWidth = (item) => {
if (!item) return;
let label = this.getItemLabel(item);
const itemWidth =
this.getTextWidth(
item.groupLabel + " " + label,
"bolder 13px sans-serif"
) + filterItemPadding;
return itemWidth;
};
addItems = (searchWidth) => {
const { hiddenFilterItems } = this.state;
if (hiddenFilterItems.length === 0) return 0;
let newSearchWidth = searchWidth;
let numberOfHiddenItems = hiddenFilterItems.length;
for (let i = 0; i < hiddenFilterItems.length; i++) {
let hiddenItemWidth = this.calcHiddenItemWidth(hiddenFilterItems[i]);
if (hiddenItemWidth > maxFilterItemWidth)
hiddenItemWidth = maxFilterItemWidth;
newSearchWidth = newSearchWidth - hiddenItemWidth;
if (newSearchWidth >= minWidth) {
numberOfHiddenItems--;
} else {
break;
}
}
return numberOfHiddenItems;
};
hideItems = (searchWidth, currentFilterItems) => {
const { hiddenFilterItems } = this.state;
let newSearchWidth = searchWidth;
let numberOfHiddenItems = hiddenFilterItems.length;
for (let i = currentFilterItems.length - 1; i >= 0; i--) {
if (currentFilterItems[i].id === "styled-hide-filter") continue;
const filterItemWidth = currentFilterItems[i].getBoundingClientRect()
.width;
newSearchWidth = newSearchWidth + filterItemWidth;
numberOfHiddenItems++;
if (numberOfHiddenItems === 1) newSearchWidth - itemsContainerWidth; // subtract the width of hidden block
if (newSearchWidth > minWidth) break;
}
return numberOfHiddenItems;
};
calcHiddenItems = (searchWidth, currentFilterItems) => {
const { hiddenFilterItems } = this.state;
if (!searchWidth || currentFilterItems.length === 0)
return hiddenFilterItems.length;
const numberOfHiddenItems =
searchWidth < minWidth
? this.hideItems(searchWidth, currentFilterItems)
: this.addItems(searchWidth);
return numberOfHiddenItems;
};
updateFilter = (inputFilterItems) => {
const { sectionWidth } = this.props;
const currentFilterItems = inputFilterItems
? cloneObjectsArray(inputFilterItems)
: cloneObjectsArray(this.state.filterValues);
const fullWidth = this.searchWrapper.current.getBoundingClientRect().width;
const filterWidth = this.filterWrapper.current.getBoundingClientRect()
.width;
const comboBoxWidth = this.rectComboBoxRef.current.getBoundingClientRect()
.width;
const searchWidth = sectionWidth
? sectionWidth - filterWidth - comboBoxWidth - sectionPaddings
: fullWidth - filterWidth;
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) {
const numberOfHiddenItems = this.calcHiddenItems(searchWidth, filterArr);
if (searchWidth !== 0 && currentFilterItems.length > 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: [],
openFilterItems: numberOfHiddenItems
? currentFilterItems.slice(
0,
currentFilterItems.length - numberOfHiddenItems
)
: currentFilterItems.slice(),
hiddenFilterItems: numberOfHiddenItems
? currentFilterItems.slice(-numberOfHiddenItems)
: [],
});
}
}
onDeleteFilterItem(key) {
};
getItemLabel = (item) => {
let label = "";
if (item.selectedItem) {
label = item.selectedItem.label
? item.selectedItem.label
: item.defaultSelectLabel;
} else {
label = item.label;
}
return label;
};
onDeleteFilterItem = (key) => {
const currentFilterItems = this.state.filterValues.slice();
const indexFilterItem = currentFilterItems.findIndex((x) => x.key === key);
if (indexFilterItem != -1) {
@ -506,7 +497,7 @@ class FilterInput extends React.Component {
this.setState({
filterValues: currentFilterItems,
openFilterItems: currentFilterItems,
hideFilterItems: [],
hiddenFilterItems: [],
});
let filterValues = cloneObjectsArray(currentFilterItems);
filterValues = filterValues.map(function (item) {
@ -518,8 +509,8 @@ class FilterInput extends React.Component {
this.state.sortId,
this.state.sortDirection ? "desc" : "asc"
);
}
onFilter(filterValues, sortId, sortDirection, searchText) {
};
onFilter = (filterValues, sortId, sortDirection, searchText) => {
let cloneFilterValues = cloneObjectsArray(filterValues);
cloneFilterValues = cloneFilterValues.map(function (item) {
item.key = item.key.replace(item.group + "_", "");
@ -531,8 +522,8 @@ class FilterInput extends React.Component {
sortId: sortId,
sortDirection: sortDirection,
});
}
onChangeFilter(result) {
};
onChangeFilter = (result) => {
this.setState({
searchText: result.inputValue,
filterValues: result.filterValues,
@ -543,24 +534,21 @@ class FilterInput extends React.Component {
this.state.sortDirection ? "desc" : "asc",
result.inputValue
);
}
onFilterRender() {
if (this.isResizeUpdate) {
this.isResizeUpdate = false;
}
};
onFilterRender = () => {
this.setState({
needUpdateFilter: 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) {
this.updateFilter();
};
onClickFilterItem = (event, filterItem) => {
const currentFilterItems = cloneObjectsArray(this.state.filterValues);
this.setState({
needUpdateFilter: true,
});
if (filterItem.isSelector) {
const indexFilterItem = currentFilterItems.findIndex(
(x) => x.group === filterItem.group
@ -601,7 +589,7 @@ class FilterInput extends React.Component {
this.setState({
filterValues: currentFilterItems,
openFilterItems: currentFilterItems,
hideFilterItems: [],
hiddenFilterItems: [],
});
if (selectFilterItem.selectedItem.key) {
@ -647,7 +635,7 @@ class FilterInput extends React.Component {
this.setState({
filterValues: currentFilterItems,
openFilterItems: currentFilterItems,
hideFilterItems: [],
hiddenFilterItems: [],
});
} else if (subgroupItems.length === 1) {
const selectFilterItem = {
@ -678,7 +666,7 @@ class FilterInput extends React.Component {
this.setState({
filterValues: currentFilterItems,
openFilterItems: currentFilterItems,
hideFilterItems: [],
hiddenFilterItems: [],
});
}
} else {
@ -705,7 +693,7 @@ class FilterInput extends React.Component {
this.setState({
filterValues: currentFilterItems,
openFilterItems: currentFilterItems,
hideFilterItems: [],
hiddenFilterItems: [],
});
const clone = cloneObjectsArray(
@ -721,7 +709,7 @@ class FilterInput extends React.Component {
this.state.sortDirection ? "desc" : "asc"
);
}
}
};
render() {
/* eslint-disable react/prop-types */
@ -741,6 +729,7 @@ class FilterInput extends React.Component {
viewAs,
contextMenuHeader,
isMobile,
sectionWidth,
} = this.props;
/* eslint-enable react/prop-types */
@ -748,12 +737,13 @@ class FilterInput extends React.Component {
searchText,
filterValues,
openFilterItems,
hideFilterItems,
hiddenFilterItems,
sortId,
sortDirection,
} = this.state;
// console.log("filter input render, openFilterItems", openFilterItems, 'hideFilterItems', hideFilterItems);
const smallSectionWidth = sectionWidth ? sectionWidth < 900 : false;
let iconSize = 30;
switch (size) {
case "base":
@ -769,13 +759,14 @@ class FilterInput extends React.Component {
}
return (
<StyledFilterInput
smallSectionWidth={smallSectionWidth}
isMobile={isMobile}
viewAs={viewAs}
className={className}
id={id}
style={style}
>
<div className="styled-search-input" ref={this.searchWrapper}>
<div className="styled-search-input test" ref={this.searchWrapper}>
<SearchInput
id={id}
isDisabled={isDisabled}
@ -796,37 +787,38 @@ class FilterInput extends React.Component {
<FilterBlock
contextMenuHeader={contextMenuHeader}
openFilterItems={openFilterItems}
hideFilterItems={hideFilterItems}
hiddenFilterItems={hiddenFilterItems}
iconSize={iconSize}
getFilterData={getFilterData}
onClickFilterItem={this.onClickFilterItem}
onDeleteFilterItem={this.onDeleteFilterItem}
isResizeUpdate={this.isResizeUpdate}
onRender={this.onFilterRender}
onFilterRender={this.onFilterRender}
isDisabled={isDisabled}
columnCount={filterColumnCount}
needUpdateFilter={this.state.needUpdateFilter}
/>
</div>
</SearchInput>
</div>
<SortComboBox
options={getSortData()}
isDisabled={isDisabled}
onChangeSortId={this.onClickSortItem}
onChangeView={this.onClickViewSelector}
onChangeSortDirection={this.onChangeSortDirection}
selectedOption={
getSortData().length > 0
? getSortData().find((x) => x.key === sortId)
: {}
}
onButtonClick={this.onSortDirectionClick}
viewAs={viewAs}
sortDirection={+sortDirection}
directionAscLabel={directionAscLabel}
directionDescLabel={directionDescLabel}
/>
<div ref={this.rectComboBoxRef}>
<SortComboBox
options={getSortData()}
isDisabled={isDisabled}
onChangeSortId={this.onClickSortItem}
onChangeView={this.onClickViewSelector}
onChangeSortDirection={this.onChangeSortDirection}
selectedOption={
getSortData().length > 0
? getSortData().find((x) => x.key === sortId)
: {}
}
onButtonClick={this.onSortDirectionClick}
viewAs={viewAs}
sortDirection={+sortDirection}
directionAscLabel={directionAscLabel}
directionDescLabel={directionDescLabel}
/>
</div>
{viewAs && (
<ViewSelector
isDisabled={isDisabled}
@ -853,6 +845,9 @@ FilterInput.protoTypes = {
filterColumnCount: PropTypes.number,
onChangeViewAs: PropTypes.func,
contextMenuHeader: PropTypes.string,
sectionWidth: PropTypes.number,
getSortData: PropTypes.func,
value: PropTypes.string,
};
FilterInput.defaultProps = {

View File

@ -107,7 +107,7 @@ const StyledFilterInput = styled.div`
margin-left: 8px;
${(props) =>
props.isMobile &&
(props.isMobile || props.smallSectionWidth) &&
`
width: 50px;
.optionalBlock ~ div:first-child{

View File

@ -39,6 +39,7 @@ class FilterItem extends React.Component {
isOpen: false,
isOpenSelector: !isOpenSelector,
selectedOption,
needUpdate: false,
};
}
@ -48,7 +49,6 @@ class FilterItem extends React.Component {
if (
selectedItem &&
selectedItem.key !== this.state.selectedOption.key &&
selectedItem.key !== this.state.selectedOption.key &&
selectedItem.key !== prevProps.selectedItem.key
) {
const selectedOption = selectedItem.key
@ -67,6 +67,11 @@ class FilterItem extends React.Component {
selectedOption,
});
}
if (this.state.needUpdate) {
this.props.onFilterRender();
this.setNeedUpdate(false);
}
}
onSelect = (option) => {
@ -85,6 +90,12 @@ class FilterItem extends React.Component {
toggleCombobox = (e, isOpen) => this.setState({ isOpen });
setNeedUpdate = (needUpdate) => {
this.setState({
needUpdate,
});
};
onCancelSelector = (e) => {
if (
this.state.isOpenSelector &&
@ -260,47 +271,64 @@ class FilterBlock extends React.Component {
constructor(props) {
super(props);
const { hideFilterItems, openFilterItems } = props;
const { hiddenFilterItems, openFilterItems } = props;
this.state = {
hideFilterItems: hideFilterItems || [],
hiddenFilterItems: hiddenFilterItems || [],
openFilterItems: openFilterItems || [],
needUpdate: false,
};
this.throttledRender = throttle(this.onRender, 100);
}
componentDidUpdate() {
this.throttledRender();
componentDidMount() {
this.setNeedUpdate(true);
}
componentDidUpdate(prevProps, prevState) {
const { needUpdate } = this.state;
const { needUpdateFilter } = this.props;
if (
(needUpdate || needUpdateFilter) &&
(!isEqual(prevState.openFilterItems, this.state.openFilterItems) ||
!isEqual(prevState.hiddenFilterItems, this.state.hiddenFilterItems))
) {
this.props.onFilterRender();
this.setNeedUpdate(false);
}
}
shouldComponentUpdate(nextProps, nextState) {
const { hideFilterItems, openFilterItems } = nextProps;
const { hiddenFilterItems, openFilterItems } = nextProps;
if (!isEqual(this.props, nextProps)) {
if (
!isEqual(this.props.hideFilterItems, hideFilterItems) ||
!isEqual(this.props.hiddenFilterItems, hiddenFilterItems) ||
!isEqual(this.props.openFilterItems, openFilterItems)
) {
this.setState({
hideFilterItems,
hiddenFilterItems,
openFilterItems,
});
return false;
}
return true;
}
if (this.props.isResizeUpdate) {
return true;
}
return !isEqual(this.state, nextState);
}
onDeleteFilterItem = (key) => {
this.props.onDeleteFilterItem(key);
this.setNeedUpdate(true);
};
setNeedUpdate = (needUpdate) => {
this.setState({
needUpdate,
});
};
getFilterItems = () => {
const { openFilterItems, hideFilterItems } = this.state;
const { openFilterItems, hiddenFilterItems } = this.state;
const _this = this;
let result = [];
let openItems = [];
@ -339,13 +367,14 @@ class FilterBlock extends React.Component {
defaultOption={defaultOption}
defaultSelectLabel={defaultSelectLabel}
selectedItem={selectedItem}
onFilterRender={_this.props.onFilterRender}
></FilterItem>
);
});
}
if (hideFilterItems.length > 0) {
if (hiddenFilterItems.length > 0) {
let open = false;
let hideFilterItemsList = hideFilterItems.map(function (item) {
let hideFilterItemsList = hiddenFilterItems.map(function (item) {
const {
key,
group,
@ -379,13 +408,14 @@ class FilterBlock extends React.Component {
defaultOption={defaultOption}
defaultSelectLabel={defaultSelectLabel}
selectedItem={selectedItem}
onFilterRender={_this.props.onFilterRender}
></FilterItem>
);
});
hideItems.push(
<HideFilter
key="hide-filter"
count={hideFilterItems.length}
count={hiddenFilterItems.length}
isDisabled={this.props.isDisabled}
open={open}
>
@ -420,9 +450,6 @@ class FilterBlock extends React.Component {
return result;
};
onRender = () => {
this.props.onRender();
};
render() {
const _this = this;
const filterItems = this.getFilterItems();
@ -453,10 +480,9 @@ class FilterBlock extends React.Component {
}
FilterBlock.propTypes = {
getFilterData: PropTypes.func,
hideFilterItems: PropTypes.array,
hiddenFilterItems: PropTypes.array,
iconSize: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
isDisabled: PropTypes.bool,
isResizeUpdate: PropTypes.bool,
onDeleteFilterItem: PropTypes.func,
onRender: PropTypes.func,
openFilterItems: PropTypes.array,

View File

@ -39,6 +39,7 @@ class HideFilter extends React.Component {
className="styled-hide-filter"
onClick={this.onClick.bind(this, !popoverOpen)}
ref={this.ref}
id="styled-hide-filter"
>
<StyledHideFilterButton id="PopoverLegacy" isDisabled={isDisabled}>
{count}

View File

@ -107,3 +107,5 @@ export function showLoader() {
document.body.classList.add("loading");
}, 1000);
}
export { withLayoutSize } from "./withLayoutSize";

View File

@ -0,0 +1,15 @@
import * as React from "react";
import { utils } from "asc-web-components";
const { Consumer } = utils.context;
export function withLayoutSize(Component) {
return function LayoutSizeComponent(props) {
return (
<Consumer>
{(context) => {
return <Component {...props} {...context} />;
}}
</Consumer>
);
};
}