Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Blazorise.sln
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazorise.Weavers", "Source
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazorise.Weavers.Fody", "Source\SourceGenerators\Blazorise.Weavers.Fody\Blazorise.Weavers.Fody.csproj", "{FFC4A285-1A16-4DD4-8B8C-141521E405B0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazorise.Exporters.Bson", "Source\Extensions\Blazorise.Exporters.Bson\Blazorise.Exporters.Bson.csproj", "{01A482C0-8DD8-4A9D-95FF-5CC2F71DB41B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazorise.Exporters.Csv", "Source\Extensions\Blazorise.Exporters.Csv\Blazorise.Exporters.Csv.csproj", "{1D465B0D-4905-438A-8581-A0657A602A33}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blazorise.Exporters", "Source\Extensions\Blazorise.Exporters\Blazorise.Exporters.csproj", "{B5B0EB7F-3457-4E93-AF9A-DE864CBB21BE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -423,6 +429,18 @@ Global
{FFC4A285-1A16-4DD4-8B8C-141521E405B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FFC4A285-1A16-4DD4-8B8C-141521E405B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FFC4A285-1A16-4DD4-8B8C-141521E405B0}.Release|Any CPU.Build.0 = Release|Any CPU
{01A482C0-8DD8-4A9D-95FF-5CC2F71DB41B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{01A482C0-8DD8-4A9D-95FF-5CC2F71DB41B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01A482C0-8DD8-4A9D-95FF-5CC2F71DB41B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01A482C0-8DD8-4A9D-95FF-5CC2F71DB41B}.Release|Any CPU.Build.0 = Release|Any CPU
{1D465B0D-4905-438A-8581-A0657A602A33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D465B0D-4905-438A-8581-A0657A602A33}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D465B0D-4905-438A-8581-A0657A602A33}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D465B0D-4905-438A-8581-A0657A602A33}.Release|Any CPU.Build.0 = Release|Any CPU
{B5B0EB7F-3457-4E93-AF9A-DE864CBB21BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B5B0EB7F-3457-4E93-AF9A-DE864CBB21BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B5B0EB7F-3457-4E93-AF9A-DE864CBB21BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B5B0EB7F-3457-4E93-AF9A-DE864CBB21BE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -495,6 +513,9 @@ Global
{EAB7EC89-900A-4280-B24A-152B9DD2B503} = {9731051E-0AA7-411E-A76A-987854F034DA}
{BF5FFB8C-45AD-4875-BB01-2DA388890419} = {0538DB67-B4F3-4D00-B969-D3874A52E405}
{FFC4A285-1A16-4DD4-8B8C-141521E405B0} = {0538DB67-B4F3-4D00-B969-D3874A52E405}
{01A482C0-8DD8-4A9D-95FF-5CC2F71DB41B} = {9731051E-0AA7-411E-A76A-987854F034DA}
{1D465B0D-4905-438A-8581-A0657A602A33} = {9731051E-0AA7-411E-A76A-987854F034DA}
{B5B0EB7F-3457-4E93-AF9A-DE864CBB21BE} = {9731051E-0AA7-411E-A76A-987854F034DA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {205B3EA4-470F-45DA-911E-346AF7D0A9A5}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#region Using directives
using System;
using System.Threading.Tasks;
using Blazorise.Exporters;
using Blazorise.Extensions;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

<ItemGroup>
<ProjectReference Include="..\..\Blazorise\Blazorise.csproj" />
<ProjectReference Include="..\Blazorise.Exporters\Blazorise.Exporters.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Blazorise.DataGrid;

/// <summary>
/// Specifies the number of rows to export from a data grid.
/// </summary>
public class DataGridExportOptions
{
/// <summary>
/// -1 means all rows
/// </summary>
public int NumberOfRows { get; init; } = -1;
}
62 changes: 61 additions & 1 deletion Source/Extensions/Blazorise.DataGrid/DataGrid.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
using System.Collections.Specialized;
using System.Dynamic;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Blazorise.DataGrid.Utils;
using Blazorise.DeepCloner;
using Blazorise.Exporters;
using Blazorise.Extensions;
using Blazorise.Licensing;
using Blazorise.Modules;
Expand All @@ -25,7 +27,7 @@ namespace Blazorise.DataGrid;
/// </summary>
/// <typeparam name="TItem">Type parameter for the model displayed in the <see cref="DataGrid{TItem}"/>.</typeparam>
[CascadingTypeParameter( nameof( TItem ) )]
public partial class DataGrid<TItem> : BaseDataGridComponent
public partial class DataGrid<TItem> : BaseDataGridComponent, IExportableComponent
{
#region Members

Expand Down Expand Up @@ -488,6 +490,8 @@ protected override async Task OnAfterRenderAsync( bool firstRender )

IsClientMacintoshOS = await IsUserAgentMacintoshOS();
await JSModule.Initialize( tableRef.ElementRef, ElementId );
JSExportersModule = new( JSRuntime, VersionProvider, BlazoriseOptions );

if ( IsCellNavigable )
{
await JSModule.InitializeTableCellNavigation( tableRef.ElementRef, ElementId );
Expand Down Expand Up @@ -1803,6 +1807,57 @@ public ValueTask ScrollToPixels( int pixels )
public ValueTask ScrollToRow( int row )
=> tableRef.ScrollToRow( row );

public async Task<TExportResult> Export<TExportResult, TCellValue>( IExporter<TExportResult, TabularSourceData<TCellValue>> exporter, DataGridExportOptions options = null )
where TExportResult : IExportResult, new()
{
if ( exporter is IExporterWithJsModule exporterWithJsModule )
{
exporterWithJsModule.JsExportersModule = JSExportersModule;
}

var data = ExportData<TCellValue>( options );

TExportResult exportResult = await exporter.Export( data );
return exportResult;
}

private TabularSourceData<TCellValue> ExportData<TCellValue>( DataGridExportOptions options )
{
options ??= new();

// Filter columns (exclude Command, MultiSelect, and DisplayTemplate columns)
var columnsToExport = Columns
.Where( column => column.ColumnType != DataGridColumnType.Command && column.ColumnType != DataGridColumnType.MultiSelect && column.Field != null && column.DisplayTemplate == null )
.ToList();

var exportedData = new List<List<TCellValue>>();

var columnNames = columnsToExport.Select( c => c.Caption ).ToList();

var filteredDataToTake = options.NumberOfRows == -1 ? FilteredData : FilteredData.Take( options.NumberOfRows );

bool isCellValueString = typeof( TCellValue ) == typeof( string );

foreach ( var item in filteredDataToTake )
{
var rowValues = new List<TCellValue>();

foreach ( var column in columnsToExport )
{
var cellValue = column.GetValue( item );
object formattedValue = isCellValueString
? column.FormatDisplayValue( cellValue ) ?? ""
: cellValue;

rowValues.Add( (TCellValue)formattedValue );
}

exportedData.Add( rowValues );
}

return new TabularSourceData<TCellValue> { Data = exportedData, ColumnNames = columnNames };
}

#endregion

#region Editing
Expand Down Expand Up @@ -2800,6 +2855,11 @@ public DataGridRowInfo<TItem> GetRowInfo( TItem item )
/// </summary>
[Inject] public IJSUtilitiesModule JSUtilitiesModule { get; set; }

/// <summary>
/// JSExporterModule for exporting files and copying content to clipboard
/// </summary>
public JSExportersModule JSExportersModule { get; set; }

/// <summary>
/// Gets or sets the license checker for the user session.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="..\..\..\Build\Blazorise.props" />

<PropertyGroup>
<PackageTags>blazorise blazor exporter bson</PackageTags>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Blazorise\Blazorise.csproj" />
<ProjectReference Include="..\Blazorise.Exporters\Blazorise.Exporters.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="MongoDB.Bson" Version="3.3.0" />
</ItemGroup>

<ItemGroup>
<None Include="..\..\..\LICENSE.md" Pack="true" Visible="false" PackagePath="" />
<None Include="..\..\..\NuGet\Blazorise.png" Pack="true" Visible="false" PackagePath="" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace Blazorise.Exporters.Bson;

/// <summary>
/// Options for exporting files in BSON format, including file extension and MIME type.
/// </summary>
public class BsonFileExportOptions : FileExportOptions
{
/// <summary>
/// Represents the file extension for the object, initialized to 'bson'.
/// </summary>
public override string FileExtension { get; init; } = "bson";

/// <summary>
/// Represents the MIME type for BSON data format. It is initialized to 'application/bson'.
/// </summary>
public override string MimeType { get; init; } = "application/bson";

/// <summary>
/// Indicates whether type information should be included. Defaults to true.
/// </summary>
public bool IncludeTypeInformation { get; init; } = true;
}
53 changes: 53 additions & 0 deletions Source/Extensions/Blazorise.Exporters.Bson/BsonToFileExporter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using MongoDB.Bson;

namespace Blazorise.Exporters.Bson;

/// <summary>
/// Exports tabular data to BSON format for file storage. It converts each row into a BSON document and wraps them in a
/// root document.
/// </summary>
public class BsonToFileExporter : BinaryExporterToFile<BsonFileExportOptions, ExportResult, TabularSourceData<object>>
{
/// <summary>
/// Initializes a new instance of the BsonToFileExporter class with optional export settings.
/// </summary>
/// <param name="options">Specifies the configuration for exporting BSON files.</param>
public BsonToFileExporter( BsonFileExportOptions options = null )
: base( options )
{
}

/// <summary>
/// Converts tabular data into BSON format for export.
/// </summary>
/// <param name="dataSource">Contains the data and column names to be transformed into BSON documents.</param>
/// <returns>A task that resolves to a byte array representing the BSON formatted data.</returns>
public override Task<byte[]> GetDataForExport( TabularSourceData<object> dataSource )
{
var bsonDocuments = new List<BsonDocument>();

foreach ( var row in dataSource.Data )
{
var doc = new BsonDocument();

for ( int i = 0; i < dataSource.ColumnNames.Count && i < row.Count; i++ )
{
var key = dataSource.ColumnNames[i];
var value = row[i];

doc.Add( key, BsonValue.Create( value ) );
}

bsonDocuments.Add( doc );
}

var rootDocument = new BsonDocument
{
{ "data", new BsonArray(bsonDocuments) }
};

return Task.FromResult( rootDocument.ToBson() );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="..\..\..\Build\Blazorise.props" />

<PropertyGroup>
<PackageTags>blazorise blazor exporter csv</PackageTags>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Blazorise\Blazorise.csproj" />
<ProjectReference Include="..\Blazorise.Exporters\Blazorise.Exporters.csproj" />
</ItemGroup>

<ItemGroup>
<None Include="..\..\..\LICENSE.md" Pack="true" Visible="false" PackagePath="" />
<None Include="..\..\..\NuGet\Blazorise.png" Pack="true" Visible="false" PackagePath="" />
</ItemGroup>

</Project>
49 changes: 49 additions & 0 deletions Source/Extensions/Blazorise.Exporters.Csv/CsvExportHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Blazorise.Exporters.Csv;

/// <summary>
/// Generates a CSV formatted string from provided data and headers. It includes an option to export headers and escapes
/// special characters.
/// </summary>
public static class CsvExportHelpers
{
/// <summary>
/// Generates a CSV formatted string from provided data and headers, with optional header export.
/// </summary>
/// <param name="data">Contains the rows of data to be included in the CSV output.</param>
/// <param name="headers">Defines the column headers for the CSV output if header export is enabled.</param>
/// <param name="options">Specifies options that control the export behavior, such as whether to include headers.</param>
/// <returns>Returns a string representing the CSV formatted data.</returns>
public static Task<string> GetDataForText( List<List<string>> data, List<string> headers, ICsvExportOptions options )
{
var sb = new StringBuilder();

if ( options?.ExportHeader == true )
{
sb.AppendLine( string.Join( ",", headers.Select( EscapeCsvField ) ) );
}

foreach ( var row in data )
{
sb.AppendLine( string.Join( ",", row.Select( EscapeCsvField ) ) );
}

return Task.FromResult( sb.ToString() );
}

static string EscapeCsvField( string field )
{
if ( field.Contains( '"' ) || field.Contains( ',' ) || field.Contains( '\n' ) || field.Contains( '\r' ) )
{
var escaped = field.Replace( "\"", "\"\"" );

return $"\"{escaped}\"";
}

return field;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Threading.Tasks;

namespace Blazorise.Exporters.Csv;

/// <summary>
/// Provides functionality to export DataGrid content in CSV format directly to the system clipboard.
/// </summary>
public class CsvToClipboardExporter : TextExporterToClipboard<CsvClipboardExportOptions, ExportResult, TabularSourceData<string>>
{
/// <summary>
/// Initializes a new instance of the CsvToClipboardExporter class, allowing for CSV data to be exported to the
/// clipboard.
/// </summary>
/// <param name="options">Specifies the settings for exporting CSV data.</param>
public CsvToClipboardExporter( CsvClipboardExportOptions options = null )
: base( options )
{
}

/// <summary>
/// Retrieves data formatted for export as a string, specifically in CSV format.
/// </summary>
/// <param name="sourceData">Contains the data and column names needed for generating the export content.</param>
/// <returns>A string representing the formatted data ready for export.</returns>
public override async Task<string> GetDataForExport( TabularSourceData<string> sourceData )
{
var content = await CsvExportHelpers.GetDataForText( sourceData.Data, sourceData.ColumnNames, ClipboardOptions );

return content;
}
}
Loading
Loading