DevExtreme v24.1 is now available.

Explore our newest features/capabilities and share your thoughts with us.

Your search did not match any results.

React File Manager - Entity Framework ORM

The FileManager component allows you to manage file system items that use the Entity Framework ORM to link to a database. You can use the Remote File System Provider to connect to the file system on the client side. To process the component's HTTP requests on the server, create your own file system provider, which implements the IFileSystemItemLoader and IFileSystemItemEditor interfaces.

Backend API
import React, { useCallback, useState } from 'react'; import FileManager, { Permissions, ItemView, Details, Column, FileManagerTypes, } from 'devextreme-react/file-manager'; import RemoteFileSystemProvider from 'devextreme/file_management/remote_provider'; const remoteProvider = new RemoteFileSystemProvider({ endpointUrl: 'https://js.devexpress.com/Demos/Mvc/api/file-manager-db', }); const allowedFileExtensions = []; export default function App() { const [currentPath, setCurrentPath] = useState('Documents/Reports'); const onCurrentDirectoryChanged = useCallback((e: FileManagerTypes.CurrentDirectoryChangedEvent) => { setCurrentPath(e.component.option('currentPath')); }, []); return ( <FileManager currentPath={currentPath} fileSystemProvider={remoteProvider} allowedFileExtensions={allowedFileExtensions} height={550} onCurrentDirectoryChanged={onCurrentDirectoryChanged}> <Permissions create={true} copy={true} move={true} delete={true} rename={true}> </Permissions> <ItemView> <Details> <Column dataField="thumbnail"></Column> <Column dataField="name"></Column> <Column dataField="dateModified" caption="Modified"></Column> <Column dataField="created" caption="Created" dataType="date"></Column> <Column dataField="modifiedBy" caption="Modified By" visibleIndex={2}></Column> </Details> </ItemView> </FileManager> ); }
import React, { useCallback, useState } from 'react'; import FileManager, { Permissions, ItemView, Details, Column, } from 'devextreme-react/file-manager'; import RemoteFileSystemProvider from 'devextreme/file_management/remote_provider'; const remoteProvider = new RemoteFileSystemProvider({ endpointUrl: 'https://js.devexpress.com/Demos/Mvc/api/file-manager-db', }); const allowedFileExtensions = []; export default function App() { const [currentPath, setCurrentPath] = useState('Documents/Reports'); const onCurrentDirectoryChanged = useCallback((e) => { setCurrentPath(e.component.option('currentPath')); }, []); return ( <FileManager currentPath={currentPath} fileSystemProvider={remoteProvider} allowedFileExtensions={allowedFileExtensions} height={550} onCurrentDirectoryChanged={onCurrentDirectoryChanged} > <Permissions create={true} copy={true} move={true} delete={true} rename={true} ></Permissions> <ItemView> <Details> <Column dataField="thumbnail"></Column> <Column dataField="name"></Column> <Column dataField="dateModified" caption="Modified" ></Column> <Column dataField="created" caption="Created" dataType="date" ></Column> <Column dataField="modifiedBy" caption="Modified By" visibleIndex={2} ></Column> </Details> </ItemView> </FileManager> ); }
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.tsx'; ReactDOM.render( <App />, document.getElementById('app'), );
window.exports = window.exports || {}; window.config = { transpiler: 'ts', typescriptOptions: { module: 'system', emitDecoratorMetadata: true, experimentalDecorators: true, jsx: 'react', }, meta: { 'react': { 'esModule': true, }, 'typescript': { 'exports': 'ts', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, }, paths: { 'npm:': 'https://unpkg.com/', }, defaultExtension: 'js', map: { 'ts': 'npm:plugin-typescript@4.2.4/lib/plugin.js', 'typescript': 'npm:typescript@4.2.4/lib/typescript.js', 'react': 'npm:react@17.0.2/umd/react.development.js', 'react-dom': 'npm:react-dom@17.0.2/umd/react-dom.development.js', 'prop-types': 'npm:prop-types@15.8.1/prop-types.js', 'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js', 'luxon': 'npm:luxon@1.28.1/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign@1.1.0', 'devextreme': 'npm:devextreme@24.1.7/cjs', 'devextreme-react': 'npm:devextreme-react@24.1.7/cjs', 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.13/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.56/dist/dx-gantt.js', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.13', 'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js', 'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js', 'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js', 'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js', 'inferno-hydrate': 'npm:inferno-hydrate@7.4.11/dist/inferno-hydrate.min.js', 'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js', 'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js', 'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js', 'devextreme-cldr-data': 'npm:devextreme-cldr-data@1.0.3', // SystemJS plugins 'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js', // Prettier 'prettier/standalone': 'npm:prettier@2.8.8/standalone.js', 'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js', }, packages: { 'devextreme': { defaultExtension: 'js', }, 'devextreme-react': { main: 'index.js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/localization/messages': { format: 'json', defaultExtension: 'json', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', 'npm:@devextreme/runtime@3.0.13/inferno/package.json', ], babelOptions: { sourceMaps: false, stage0: true, react: true, }, }; System.config(window.config);
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.js'; ReactDOM.render(<App />, document.getElementById('app'));
<!DOCTYPE html> <html lang="en"> <head> <title>DevExtreme Demo</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.1.7/css/dx.light.css" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.1.7/css/dx-gantt.min.css" /> <script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script> <script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script> <script type="text/javascript" src="config.js"></script> <script type="text/javascript"> System.import("./index.tsx"); </script> <link rel="stylesheet" type="text/css" href="styles.css" /> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app"></div> </div> </body> </html>
using DevExtreme.AspNet.Mvc.FileManagement; using DevExtreme.MVC.Demos.Models.FileManagement; using System; using System.Web; using System.Web.Http; namespace DevExtreme.MVC.Demos.Controllers.ApiControllers { public class FileManagerDbProviderApiController : ApiController { [AcceptVerbs("GET", "POST")] [Route("api/file-manager-db", Name = "FileManagerDBProviderApi")] public object Process(FileSystemCommand command, string arguments) { var request = new HttpContextWrapper(HttpContext.Current).Request; var config = new FileSystemConfiguration { Request = request, FileSystemProvider = new DbFileProvider(), AllowCopy = true, AllowCreate = true, AllowMove = true, AllowDelete = true, AllowRename = true, AllowedFileExtensions = new string[0] }; var processor = new FileSystemCommandProcessor(config); var result = processor.Execute(command, arguments); return Ok(result.GetClientCommandResult()); } } }
using System; using System.Collections.Generic; using System.IO; using System.Linq; using DevExtreme.AspNet.Mvc.FileManagement; namespace DevExtreme.MVC.Demos.Models.FileManagement { public class DbFileProvider : IFileSystemItemLoader, IFileSystemItemEditor { const int GuestPersonId = 1; public DbFileProvider() { FileManagementDbContext = new InMemoryFileManagementDataContext(); } InMemoryFileManagementDataContext FileManagementDbContext { get; } public IEnumerable<FileSystemItem> GetItems(FileSystemLoadItemOptions options) { int parentId = ParseKey(options.Directory.Key); var fileItems = GetDirectoryContents(parentId); var hasSubDirectoriesInfo = GetHasSubDirectoriesInfo(fileItems); var clientItemList = new List<FileSystemItem>(); foreach(var item in fileItems) { var clientItem = new FileSystemItem { Key = item.Id.ToString(), Name = item.Name, IsDirectory = item.IsDirectory, DateModified = item.Modified }; if(item.IsDirectory) { clientItem.HasSubDirectories = hasSubDirectoriesInfo.ContainsKey(item.Id) && hasSubDirectoriesInfo[item.Id]; } clientItem.CustomFields["modifiedBy"] = item.ModifiedBy.FullName; clientItem.CustomFields["created"] = item.Created; clientItemList.Add(clientItem); } return clientItemList; } public void CreateDirectory(FileSystemCreateDirectoryOptions options) { var parentDirectory = options.ParentDirectory; if(!IsFileItemExists(parentDirectory)) ThrowItemNotFoundException(parentDirectory); var directory = new FileItem { Name = options.DirectoryName, Modified = DateTime.Now, Created = DateTime.Now, IsDirectory = true, ParentId = ParseKey(parentDirectory.Key), ModifiedById = GuestPersonId }; FileManagementDbContext.FileItems.Add(directory); FileManagementDbContext.SaveChanges(); } public void RenameItem(FileSystemRenameItemOptions options) { var item = options.Item; if(!IsFileItemExists(item)) ThrowItemNotFoundException(item); var fileItem = GetFileItem(item); fileItem.Name = options.ItemNewName; fileItem.ModifiedById = GuestPersonId; fileItem.Modified = DateTime.Now; FileManagementDbContext.SaveChanges(); } public void MoveItem(FileSystemMoveItemOptions options) { var item = options.Item; var destinationDirectory = options.DestinationDirectory; if(!IsFileItemExists(item)) ThrowItemNotFoundException(item); if(!IsFileItemExists(destinationDirectory)) ThrowItemNotFoundException(destinationDirectory); if(!AllowCopyOrMove(item, destinationDirectory)) ThrowNoAccessException(); var fileItem = GetFileItem(item); fileItem.ParentId = ParseKey(destinationDirectory.Key); fileItem.Modified = DateTime.Now; fileItem.ModifiedById = GuestPersonId; FileManagementDbContext.SaveChanges(); } public void CopyItem(FileSystemCopyItemOptions options) { var item = options.Item; var destinationDirectory = options.DestinationDirectory; if(!IsFileItemExists(item)) ThrowItemNotFoundException(item); if(!IsFileItemExists(destinationDirectory)) ThrowItemNotFoundException(destinationDirectory); if(!AllowCopyOrMove(item, destinationDirectory)) ThrowNoAccessException(); var sourceFileItem = GetFileItem(item); var copyFileItem = CreateCopy(sourceFileItem); copyFileItem.ParentId = ParseKey(destinationDirectory.Key); copyFileItem.Name = GenerateCopiedFileItemName(copyFileItem.ParentId, copyFileItem.Name, copyFileItem.IsDirectory); FileManagementDbContext.FileItems.Add(copyFileItem); if(copyFileItem.IsDirectory) CopyDirectoryContentRecursive(sourceFileItem, copyFileItem); FileManagementDbContext.SaveChanges(); } void CopyDirectoryContentRecursive(FileItem sourcePathInfo, FileItem destinationPathInfo) { foreach(var fileItem in GetDirectoryContents(sourcePathInfo.Id)) { var copyItem = CreateCopy(fileItem); copyItem.Parent = destinationPathInfo; FileManagementDbContext.FileItems.Add(copyItem); if(fileItem.IsDirectory) CopyDirectoryContentRecursive(fileItem, copyItem); } } public void DeleteItem(FileSystemDeleteItemOptions options) { var item = options.Item; if(!IsFileItemExists(item)) ThrowItemNotFoundException(item); var fileItem = GetFileItem(item); FileManagementDbContext.FileItems.Remove(fileItem); if(fileItem.IsDirectory) RemoveDirectoryContentRecursive(fileItem.Id); FileManagementDbContext.SaveChanges(); } void RemoveDirectoryContentRecursive(int parenDirectoryKey) { var itemsToRemove = FileManagementDbContext .FileItems .Where(item => item.ParentId == parenDirectoryKey) .Select(item => new FileItem { Id = item.Id, IsDirectory = item.IsDirectory }); foreach(var item in itemsToRemove) { FileManagementDbContext.FileItems.Remove(item); } foreach(var item in itemsToRemove) { if(!item.IsDirectory) continue; RemoveDirectoryContentRecursive(item.Id); } } IEnumerable<FileItem> GetDirectoryContents(int parentKey) { return FileManagementDbContext.FileItems .OrderByDescending(item => item.IsDirectory) .ThenBy(item => item.Name) .Where(items => items.ParentId == parentKey); } IDictionary<int, bool> GetHasSubDirectoriesInfo(IEnumerable<FileItem> fileItems) { var keys = fileItems.Select(i => i.Id).ToArray(); return FileManagementDbContext.FileItems .Where(item => item.IsDirectory) .GroupBy(i => i.ParentId) .Where(i => keys.Contains(i.Key)) .ToDictionary(group => group.Key, group => group.Any()); } FileItem GetFileItem(FileSystemItemInfo item) { var itemId = ParseKey(item.Key); return FileManagementDbContext.FileItems.FirstOrDefault(i => i.Id == itemId); } bool IsFileItemExists(FileSystemItemInfo itemInfo) { var pathKeys = itemInfo.PathKeys.Select(key => ParseKey(key)).ToArray(); var foundEntries = FileManagementDbContext.FileItems .Where(item => pathKeys.Contains(item.Id)) .Select(item => new { item.Id, item.ParentId, item.Name, item.IsDirectory }); var pathNames = itemInfo.Path.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); var isDirectoryExists = true; for(var i = 0; i < pathKeys.Length && isDirectoryExists; i++) { var entry = foundEntries.FirstOrDefault(e => e.Id == pathKeys[i]); isDirectoryExists = entry != null && entry.Name == pathNames[i] && (i == 0 && entry.ParentId == 0 || entry.ParentId == pathKeys[i - 1]); if(isDirectoryExists && i < pathKeys.Length - 1) isDirectoryExists = entry.IsDirectory; } return isDirectoryExists; } static bool AllowCopyOrMove(FileSystemItemInfo item, FileSystemItemInfo destinationDirectory) { if(destinationDirectory.PathKeys.Length < item.PathKeys.Length) return true; var isValid = false; for(var i = 0; i < destinationDirectory.PathKeys.Length && !isValid; i++) { isValid = destinationDirectory.PathKeys[i] != item.PathKeys[i]; } return isValid; } static FileItem CreateCopy(FileItem fileItem) { return new FileItem { Name = fileItem.Name, Created = DateTime.Now, Modified = DateTime.Now, IsDirectory = fileItem.IsDirectory, ModifiedById = GuestPersonId }; } static int ParseKey(string key) { return string.IsNullOrEmpty(key) ? 0 : int.Parse(key); } string GenerateCopiedFileItemName(int parentDirKey, string copiedFileItemName, bool isDirectory) { var dirNames = GetDirectoryContents(parentDirKey) .Where(i => i.IsDirectory == isDirectory) .Select(i => i.Name); string newName; var fileExtension = isDirectory ? "" : "." + Path.GetExtension(copiedFileItemName); var copyNamePrefix = isDirectory ? copiedFileItemName : Path.GetFileNameWithoutExtension(copiedFileItemName); var index = -1; do { var pathPostfix = index < 1 ? string.Empty : $" {index}{fileExtension}"; newName = $"{copyNamePrefix} {(index < 0 ? "" : "copy")}{pathPostfix}"; index++; } while(dirNames.Contains(newName)); return newName; } void ThrowItemNotFoundException(FileSystemItemInfo item) { var itemType = item.IsDirectory ? "Directory" : "File"; var errorCode = item.IsDirectory ? FileSystemErrorCode.DirectoryNotFound : FileSystemErrorCode.FileNotFound; string message = $"{itemType} '{item.Path}' not found."; throw new FileSystemException(errorCode, message); } void ThrowNoAccessException() { string message = "Access denied. The operation cannot be completed."; throw new FileSystemException(FileSystemErrorCode.NoAccess, message); } } }