diff --git a/packages/asc-web-components/table-container/TableHeader.js b/packages/asc-web-components/table-container/TableHeader.js index f2ba984836..6fdc7b12d8 100644 --- a/packages/asc-web-components/table-container/TableHeader.js +++ b/packages/asc-web-components/table-container/TableHeader.js @@ -14,6 +14,7 @@ import TableGroupMenu from "./TableGroupMenu"; const minColumnSize = 150; const settingsSize = 24; +const containerMargin = 25; class TableHeader extends React.Component { constructor(props) { @@ -131,6 +132,8 @@ class TableHeader extends React.Component { .filter((x) => x.key !== this.props.columns[columnIndex - 1].key) .filter((x) => !x.defaultSize); + const defaultSize = this.props.columns[columnIndex - 1]?.defaultSize; + let index = this.props.columns.length; while (index !== 0) { index--; @@ -140,7 +143,9 @@ class TableHeader extends React.Component { if (isFind) { const someItemById = document.getElementById("column_" + (index + 1)); - const columnSize = someItemById.clientWidth - minColumnSize; + const columnSize = + someItemById.clientWidth - + (defaultSize ? defaultSize : minColumnSize); if (columnSize >= minColumnSize) { return (gridTemplateColumns[index + 1] = columnSize + "px"); @@ -211,7 +216,6 @@ class TableHeader extends React.Component { : document.getElementById("table-container"); const minSize = size.tablet; - const containerMargin = 25; if ( !container || @@ -227,8 +231,7 @@ class TableHeader extends React.Component { : container.style.gridTemplateColumns.split(" "); const containerWidth = +container.clientWidth; - const newContainerWidth = - containerWidth - this.getSubstring(checkboxSize) - 80 - settingsSize; // TODO: 80 + const newContainerWidth = containerWidth - this.getSubstring(checkboxSize); const oldWidth = tableContainer .map((column) => this.getSubstring(column)) @@ -242,7 +245,6 @@ class TableHeader extends React.Component { const isSingleTable = enableColumns.length > 0; let str = ""; - let disableColumnWidth = 0; if (tableContainer.length > 1) { const gridTemplateColumns = []; @@ -255,6 +257,7 @@ class TableHeader extends React.Component { index == 0 || index == tableContainer.length - 1 || (column ? column.dataset.enable === "true" : item !== "0px"); + const defaultSize = column && column.dataset.defaultSize; const isActiveNow = item === "0px" && enable; if (isActiveNow && column) activeColumnIndex = index; @@ -265,21 +268,18 @@ class TableHeader extends React.Component { this.getSubstring(gridTemplateColumns[1]) + this.getSubstring(item) + "px"; - } else if ( - item !== `${settingsSize}px` && - item !== checkboxSize && - item !== "80px" - ) { + } else if (item !== `${settingsSize}px` && item !== checkboxSize) { const percent = (this.getSubstring(item) / oldWidth) * 100; if (index == 1) { - const newItemWidth = - (containerWidth * percent) / 100 + disableColumnWidth + "px"; + const newItemWidth = (containerWidth * percent) / 100 + "px"; gridTemplateColumns.push(newItemWidth); } else { const newItemWidth = percent === 0 - ? `${minColumnSize}px` + ? defaultSize + ? `${defaultSize}px` + : `${minColumnSize}px` : (containerWidth * percent) / 100 + "px"; gridTemplateColumns.push(newItemWidth); @@ -295,8 +295,14 @@ class TableHeader extends React.Component { str = gridTemplateColumns.join(" "); } else { + const defaultSize = this.props.columns.find((col) => col.defaultSize) + ?.defaultSize; + const column = - (newContainerWidth * (isSingleTable ? 60 : 100)) / 100 + "px"; + (newContainerWidth * (isSingleTable ? 60 : 100)) / 100 - + (defaultSize || 0) - + containerMargin + + "px"; const percent = 40 / enableColumns.length; const otherColumns = (newContainerWidth * percent) / 100 + "px"; @@ -387,6 +393,7 @@ class TableHeader extends React.Component { sorted={sorted} sortBy={sortBy} resizable={resizable} + defaultSize={column.defaultSize} onMouseDown={this.onMouseDown} /> ); diff --git a/packages/asc-web-components/table-container/TableHeaderCell.js b/packages/asc-web-components/table-container/TableHeaderCell.js index a79a8a61bd..1389d84f98 100644 --- a/packages/asc-web-components/table-container/TableHeaderCell.js +++ b/packages/asc-web-components/table-container/TableHeaderCell.js @@ -12,6 +12,7 @@ const TableHeaderCell = ({ resizable, sortBy, sorted, + defaultSize, }) => { const { title, enable, active, minWidth } = column; @@ -35,6 +36,7 @@ const TableHeaderCell = ({ id={`column_${index + 1}`} data-enable={enable} data-min-width={minWidth} + data-default-size={defaultSize} onClick={onClick} >
@@ -73,6 +75,7 @@ TableHeaderCell.propTypes = { resizable: PropTypes.bool, sorted: PropTypes.bool, sortBy: PropTypes.string, + defaultSize: PropTypes.number, }; export default TableHeaderCell; diff --git a/products/ASC.Files/Client/src/HOCs/withContent.js b/products/ASC.Files/Client/src/HOCs/withContent.js index 4141012c3d..56724880f2 100644 --- a/products/ASC.Files/Client/src/HOCs/withContent.js +++ b/products/ASC.Files/Client/src/HOCs/withContent.js @@ -233,8 +233,17 @@ export default function withContent(WrappedContent) { onFilesClick, viewAs, element, + isDesktop, } = this.props; - const { id, fileExst, updated, createdBy, access, fileStatus } = item; + const { + id, + fileExst, + updated, + createdBy, + access, + fileStatus, + href, + } = item; const titleWithoutExt = getTitleWithoutExst(item); @@ -259,6 +268,10 @@ export default function withContent(WrappedContent) { ? { noHover: true } : { onClick: onFilesClick }; + if (!isDesktop && !isTrashFolder) { + linkStyles.href = item.href; + } + const newItems = item.new || fileStatus === 2; const showNew = !!newItems; diff --git a/products/ASC.Files/Client/src/components/Article/Body/TreeFolders.js b/products/ASC.Files/Client/src/components/Article/Body/TreeFolders.js index 09af6f6e9c..3d9bf6d76a 100644 --- a/products/ASC.Files/Client/src/components/Article/Body/TreeFolders.js +++ b/products/ASC.Files/Client/src/components/Article/Body/TreeFolders.js @@ -122,10 +122,10 @@ class TreeFolders extends React.Component { iconUrl = "/static/images/cloud.services.onedrive.react.svg"; break; case "kDrive": - iconUrl = "/static/images/catalog.folder.react.svg"; + iconUrl = "/static/images/cloud.services.kdrive.react.svg"; break; case "Yandex": - iconUrl = "/static/images/catalog.folder.react.svg"; + iconUrl = "/static/images/cloud.services.yandex.react.svg"; break; case "NextCloud": iconUrl = "/static/images/cloud.services.nextcloud.react.svg"; @@ -134,7 +134,7 @@ class TreeFolders extends React.Component { iconUrl = "/static/images/catalog.folder.react.svg"; break; case "WebDav": - iconUrl = "/static/images/catalog.folder.react.svg"; + iconUrl = "/static/images/cloud.services.webdav.react.svg"; break; default: break; diff --git a/products/ASC.Files/Client/src/pages/Home/Section/Body/RowsView/FilesRowContent.js b/products/ASC.Files/Client/src/pages/Home/Section/Body/RowsView/FilesRowContent.js index 316da0b9d3..acbeec583f 100644 --- a/products/ASC.Files/Client/src/pages/Home/Section/Body/RowsView/FilesRowContent.js +++ b/products/ASC.Files/Client/src/pages/Home/Section/Body/RowsView/FilesRowContent.js @@ -59,7 +59,6 @@ const FilesRowContent = ({ updatedDate, fileOwner, linkStyles, - //onFilesClick, badgesComponent, isAdmin, }) => { @@ -90,7 +89,6 @@ const FilesRowContent = ({ fontWeight="600" fontSize="15px" target="_blank" - href={item.href} {...linkStyles} color="#333" isTextOverflow={true} diff --git a/products/ASC.Files/Client/src/pages/Home/Section/Body/TableView/sub-components/FileNameCell.js b/products/ASC.Files/Client/src/pages/Home/Section/Body/TableView/sub-components/FileNameCell.js index bb8c55d288..1434f4a1d2 100644 --- a/products/ASC.Files/Client/src/pages/Home/Section/Body/TableView/sub-components/FileNameCell.js +++ b/products/ASC.Files/Client/src/pages/Home/Section/Body/TableView/sub-components/FileNameCell.js @@ -10,7 +10,6 @@ const FileNameCell = ({ item, titleWithoutExt, linkStyles }) => { title={titleWithoutExt} fontWeight="600" fontSize="13px" - href={item.href} {...linkStyles} color="#333" isTextOverflow diff --git a/products/ASC.Files/Client/src/pages/Home/Section/Body/TilesView/FilesTileContent.js b/products/ASC.Files/Client/src/pages/Home/Section/Body/TilesView/FilesTileContent.js index 1ee4986a8f..39128fd3d8 100644 --- a/products/ASC.Files/Client/src/pages/Home/Section/Body/TilesView/FilesTileContent.js +++ b/products/ASC.Files/Client/src/pages/Home/Section/Body/TilesView/FilesTileContent.js @@ -77,7 +77,6 @@ const FilesTileContent = ({ item, titleWithoutExt, linkStyles, - onFilesClick, badgesComponent, }) => { const { fileExst } = item; @@ -97,7 +96,6 @@ const FilesTileContent = ({ fontWeight="600" fontSize="14px" target="_blank" - href={item.href} {...linkStyles} color="#333" isTextOverflow diff --git a/products/ASC.Files/Client/src/store/FilesStore.js b/products/ASC.Files/Client/src/store/FilesStore.js index 8e6e910841..499e4ff712 100644 --- a/products/ASC.Files/Client/src/store/FilesStore.js +++ b/products/ASC.Files/Client/src/store/FilesStore.js @@ -339,7 +339,7 @@ class FilesStore { if (!requestCounter) return; requestCounter--; - if (folderId === "@my" && !this.isInit) { + if (folderId === "@my" /* && !this.isInit */) { setTimeout(() => { return request(); }, 5000); diff --git a/products/ASC.Files/Core/Model/BatchModel.cs b/products/ASC.Files/Core/Model/BatchModel.cs index 0232ade5f1..453811461f 100644 --- a/products/ASC.Files/Core/Model/BatchModel.cs +++ b/products/ASC.Files/Core/Model/BatchModel.cs @@ -1,15 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using System.Text.Json; -using System.Threading.Tasks; using ASC.Api.Collections; using ASC.Web.Files.Services.WCFService.FileOperations; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc.ModelBinding; - namespace ASC.Files.Model { public class BaseBatchModel @@ -37,88 +31,6 @@ namespace ASC.Files.Model public bool DeleteAfter { get; set; } public bool Immediately { get; set; } } - - - public class DeleteBatchModelBinder : BaseBatchModelBinder - { - public override Task BindModelAsync(ModelBindingContext bindingContext) - { - base.BindModelAsync(bindingContext); - if (bindingContext == null) - { - throw new ArgumentNullException(nameof(bindingContext)); - } - - var baseResult = bindingContext.Result.Model as BaseBatchModel; - - var result = new DeleteBatchModel(); - - result.FileIds = baseResult.FileIds; - result.FolderIds = baseResult.FolderIds; - - var modelName = nameof(result.DeleteAfter); - var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); - - if (valueProviderResult != ValueProviderResult.None) - { - bindingContext.ModelState.SetModelValue(modelName, valueProviderResult); - if (bool.TryParse(valueProviderResult.FirstValue, out var deleteAfter)) - { - result.DeleteAfter = deleteAfter; - } - } - - modelName = nameof(result.Immediately); - valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); - - if (valueProviderResult != ValueProviderResult.None) - { - bindingContext.ModelState.SetModelValue(modelName, valueProviderResult); - if (bool.TryParse(valueProviderResult.FirstValue, out var immediately)) - { - result.Immediately = immediately; - } - } - - bindingContext.Result = ModelBindingResult.Success(result); - - return Task.CompletedTask; - } - } - - public class BaseBatchModelBinder : IModelBinder - { - public virtual Task BindModelAsync(ModelBindingContext bindingContext) - { - if (bindingContext == null) - { - throw new ArgumentNullException(nameof(bindingContext)); - } - - var result = new BaseBatchModel(); - - result.FileIds = ParseQuery(bindingContext, nameof(result.FileIds)); - result.FolderIds = ParseQuery(bindingContext, nameof(result.FolderIds)); - - bindingContext.Result = ModelBindingResult.Success(result); - - return Task.CompletedTask; - } - - internal List ParseQuery(ModelBindingContext bindingContext, string modelName) - { - var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); - - if (valueProviderResult != ValueProviderResult.None) - { - bindingContext.ModelState.SetModelValue(modelName, valueProviderResult); - - return valueProviderResult.Select(BatchModel.ParseQueryParam).ToList(); - } - - return new List(); - } - } public class DeleteModel { @@ -130,74 +42,6 @@ namespace ASC.Files.Model { public JsonElement DestFolderId { get; set; } public FileConflictResolveType ConflictResolveType { get; set; } - public bool DeleteAfter { get; set; } - - public static BatchModel FromQuery(HttpContext httpContext) - { - var result = new BatchModel(); - var query = httpContext.Request.Query; - - var destId = query["DestFolderId"]; - if (destId.Any()) - { - result.DestFolderId = ParseQueryParam(destId.First()); - } - - var conflictResolveType = query["ConflictResolveType"]; - if (conflictResolveType.Any()) - { - if (Enum.TryParse(conflictResolveType.First(), out var crf)) - { - result.ConflictResolveType = crf; - } - } - - var deleteAfter = query["DeleteAfter"]; - if (deleteAfter.Any()) - { - if (bool.TryParse(deleteAfter.First(), out var d)) - { - result.DeleteAfter = d; - } - } - - var fileIdsQuery = query["FileIds"]; - if (fileIdsQuery.Any()) - { - var fileIds = new List(); - - foreach (var f in fileIdsQuery) - { - fileIds.Add(ParseQueryParam(f)); - } - - result.FileIds = fileIds; - } - - var folderIdsQuery = query["FolderIds"]; - if (folderIdsQuery.Any()) - { - var folderIds = new List(); - - foreach (var f in folderIdsQuery) - { - folderIds.Add(ParseQueryParam(f)); - } - - result.FolderIds = folderIds; - } - - return result; - } - - public static JsonElement ParseQueryParam(string data) - { - if (int.TryParse(data, out _)) - { - return JsonSerializer.Deserialize(data); - } - - return JsonSerializer.Deserialize($"\"{data}\""); - } + public bool DeleteAfter { get; set; } } } diff --git a/products/ASC.Files/Core/Model/Binders.cs b/products/ASC.Files/Core/Model/Binders.cs new file mode 100644 index 0000000000..a0e908b1c2 --- /dev/null +++ b/products/ASC.Files/Core/Model/Binders.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Threading.Tasks; + +using ASC.Web.Files.Services.WCFService.FileOperations; + +using Microsoft.AspNetCore.Mvc.ModelBinding; + +namespace ASC.Files.Model +{ + public class BaseBatchModelBinder : IModelBinder + { + public virtual Task BindModelAsync(ModelBindingContext bindingContext) + { + if (bindingContext == null) + { + throw new ArgumentNullException(nameof(bindingContext)); + } + + var result = new BaseBatchModel(); + + result.FileIds = ParseQuery(bindingContext, nameof(result.FileIds)); + result.FolderIds = ParseQuery(bindingContext, nameof(result.FolderIds)); + + bindingContext.Result = ModelBindingResult.Success(result); + + return Task.CompletedTask; + } + + internal List ParseQuery(ModelBindingContext bindingContext, string modelName) + { + var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); + + if (valueProviderResult != ValueProviderResult.None) + { + bindingContext.ModelState.SetModelValue(modelName, valueProviderResult); + + return valueProviderResult.Select(ParseQueryParam).ToList(); + } + + return new List(); + } + + public static JsonElement ParseQueryParam(string data) + { + if (int.TryParse(data, out _)) + { + return JsonSerializer.Deserialize(data); + } + + return JsonSerializer.Deserialize($"\"{data}\""); + } + } + + public class DeleteBatchModelBinder : BaseBatchModelBinder + { + public override Task BindModelAsync(ModelBindingContext bindingContext) + { + base.BindModelAsync(bindingContext); + if (bindingContext == null) + { + throw new ArgumentNullException(nameof(bindingContext)); + } + + var baseResult = bindingContext.Result.Model as BaseBatchModel; + + var result = new DeleteBatchModel(); + + result.FileIds = baseResult.FileIds; + result.FolderIds = baseResult.FolderIds; + + var modelName = nameof(result.DeleteAfter); + var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); + + if (valueProviderResult != ValueProviderResult.None) + { + bindingContext.ModelState.SetModelValue(modelName, valueProviderResult); + if (bool.TryParse(valueProviderResult.FirstValue, out var deleteAfter)) + { + result.DeleteAfter = deleteAfter; + } + } + + modelName = nameof(result.Immediately); + valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); + + if (valueProviderResult != ValueProviderResult.None) + { + bindingContext.ModelState.SetModelValue(modelName, valueProviderResult); + if (bool.TryParse(valueProviderResult.FirstValue, out var immediately)) + { + result.Immediately = immediately; + } + } + + bindingContext.Result = ModelBindingResult.Success(result); + + return Task.CompletedTask; + } + } + + public class BatchModelBinder : BaseBatchModelBinder + { + public override Task BindModelAsync(ModelBindingContext bindingContext) + { + base.BindModelAsync(bindingContext); + if (bindingContext == null) + { + throw new ArgumentNullException(nameof(bindingContext)); + } + + var baseResult = bindingContext.Result.Model as BaseBatchModel; + + var result = new BatchModel(); + + result.FileIds = baseResult.FileIds; + result.FolderIds = baseResult.FolderIds; + + var modelName = nameof(result.DeleteAfter); + var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); + + if (valueProviderResult != ValueProviderResult.None) + { + bindingContext.ModelState.SetModelValue(modelName, valueProviderResult); + if (bool.TryParse(valueProviderResult.FirstValue, out var deleteAfter)) + { + result.DeleteAfter = deleteAfter; + } + } + + modelName = nameof(result.ConflictResolveType); + valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); + + if (valueProviderResult != ValueProviderResult.None) + { + bindingContext.ModelState.SetModelValue(modelName, valueProviderResult); + if (Enum.TryParse(valueProviderResult.FirstValue, out var conflictResolveType)) + { + result.ConflictResolveType = conflictResolveType; + } + } + + modelName = nameof(result.DestFolderId); + valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); + + if (valueProviderResult != ValueProviderResult.None) + { + bindingContext.ModelState.SetModelValue(modelName, valueProviderResult); + result.DestFolderId = BaseBatchModelBinder.ParseQueryParam(valueProviderResult.FirstValue); + } + + bindingContext.Result = ModelBindingResult.Success(result); + + return Task.CompletedTask; + } + } +} diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index 2e3a8c13f4..78ed9900c9 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -1237,9 +1237,9 @@ namespace ASC.Api.Documents /// File ID list /// Conflicts file ids [Read("fileops/move")] - public IEnumerable MoveOrCopyBatchCheck() + public IEnumerable MoveOrCopyBatchCheck([ModelBinder(BinderType = typeof(BatchModelBinder))] BatchModel batchModel) { - return FilesControllerHelperString.MoveOrCopyBatchCheck(BatchModel.FromQuery(HttpContext)); + return FilesControllerHelperString.MoveOrCopyBatchCheck(batchModel); } /// @@ -1261,7 +1261,7 @@ namespace ASC.Api.Documents [Update("fileops/move")] [Consumes("application/x-www-form-urlencoded")] - public IEnumerable MoveBatchItemsFromForm([FromForm] BatchModel batchModel) + public IEnumerable MoveBatchItemsFromForm([FromForm][ModelBinder(BinderType = typeof(BatchModelBinder))] BatchModel batchModel) { return FilesControllerHelperString.MoveBatchItems(batchModel); } @@ -1285,7 +1285,7 @@ namespace ASC.Api.Documents [Update("fileops/copy")] [Consumes("application/x-www-form-urlencoded")] - public IEnumerable CopyBatchItemsFromForm([FromForm] BatchModel batchModel) + public IEnumerable CopyBatchItemsFromForm([FromForm][ModelBinder(BinderType = typeof(BatchModelBinder))] BatchModel batchModel) { return FilesControllerHelperString.CopyBatchItems(batchModel); } diff --git a/public/images/cloud.services.kdrive.react.svg b/public/images/cloud.services.kdrive.react.svg new file mode 100644 index 0000000000..503b279d03 --- /dev/null +++ b/public/images/cloud.services.kdrive.react.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/images/cloud.services.webdav.react.svg b/public/images/cloud.services.webdav.react.svg new file mode 100644 index 0000000000..29a483bf19 --- /dev/null +++ b/public/images/cloud.services.webdav.react.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/cloud.services.yandex.react.svg b/public/images/cloud.services.yandex.react.svg new file mode 100644 index 0000000000..b411a8175b --- /dev/null +++ b/public/images/cloud.services.yandex.react.svg @@ -0,0 +1,3 @@ + + +