Skip to content

Commit

Permalink
CardView Component;fixes #725
Browse files Browse the repository at this point in the history
* First implementation
* Next step card view
* Finish implementation
* Changes according to SQ
* Add CardView Tests
* Add newline
* Remove drag/drop
* Unit Test selected item
* Test Search and Sort
* Security risk
* Styles typo
* SQ recommendations
* Error in SQ recommendations
* NewLine
  • Loading branch information
lxatstariongroup authored Dec 16, 2024
1 parent 364bada commit 7cd9b4c
Show file tree
Hide file tree
Showing 17 changed files with 1,030 additions and 20 deletions.
484 changes: 484 additions & 0 deletions COMET.Web.Common.Tests/Components/CardView/CardViewTestFixture.cs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions COMET.Web.Common/COMET.Web.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@
<PackageReference Include="CDP4ServicesDal-CE" Version="27.4.1" />
<PackageReference Include="CDP4Web-CE" Version="27.4.1" />
<PackageReference Include="DevExpress.Blazor" Version="23.2.9" />
<PackageReference Include="FastMember" Version="1.5.0" />
<PackageReference Include="FluentResults" Version="3.16.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.2" />
<PackageReference Include="ReactiveUI" Version="20.1.63" />
<PackageReference Include="System.Drawing.Common" Version="8.0.10" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.5.0" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
</ItemGroup>

Expand Down
141 changes: 141 additions & 0 deletions COMET.Web.Common/Components/CardView/CardField.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CardField.cs" company="Starion Group S.A.">
// Copyright (c) 2023-2024 Starion Group S.A.
//
// Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Théate Antoine, Nabil Abbar
//
// This file is part of CDP4-COMET WEB Community Edition
// The CDP4-COMET WEB Community Edition is the Starion Web Application implementation of ECSS-E-TM-10-25
// Annex A and Annex C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace COMET.Web.Common.Components.CardView
{
using System.Text.RegularExpressions;

using FastMember;

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;

/// <summary>
/// A component that represents a data field in a <see cref="CardView{T}"/>'s ItemTemplate
/// </summary>
/// <typeparam name="T"></typeparam>
public class CardField<T> : ComponentBase
{
/// <summary>
/// The <see cref="FastMember.TypeAccessor"/> used to read properties from the instance of T.
/// This is a static property on a generic type, so it will have different static values for each used generic type in the application
/// </summary>
private static TypeAccessor typeAccessor;

/// <summary>
/// Initializes the static properties of this <see cref="CardField{T}"/> class
/// </summary>
static CardField()
{
typeAccessor = TypeAccessor.Create(typeof(T));
}

/// <summary>
/// Gets or sets The parent <see cref="CardView{T}"/>t
/// </summary>
[CascadingParameter(Name="CardView")]
private CardView<T> CardView { get; set; }

/// <summary>
/// The SearchTerm of the <see cref="CardView{T}"/> used to visually show the SearchTerm in this <see cref="CardField{T}"/>
/// </summary>
[CascadingParameter(Name = "SearchTerm")]
private string SearchTerm { get; set; }

/// <summary>
/// Gets or sets the context of this <see cref="CardField{T}"/>
/// </summary>
[Parameter]
public T Context { get; set; }

/// <summary>
/// Gets or sets the FieldName (propertyname of T) to show in the UI
/// </summary>
[Parameter]
public string FieldName { get; set; }

/// <summary>
/// Gets or sets a value indicating that sorting is allowed for this <see cref="CardField{T}"/>
/// </summary>
[Parameter]
public bool AllowSort { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating that searching is allowed for this <see cref="CardField{T}"/>
/// </summary>
[Parameter]
public bool AllowSearch { get; set; } = true;

/// <summary>
/// Method invoked when the component is ready to start, having received its
/// initial parameters from its parent in the render tree.
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
this.CardView.InitializeCardField(this);
}

/// <summary>
/// Renders the component to the supplied <see cref="RenderTreeBuilder"/>.
/// </summary>
/// <param name="builder">A <see cref="RenderTreeBuilder"/> that will receive the render output.</param>
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
var value = typeAccessor[this.Context, this.FieldName].ToString();

if (this.AllowSearch && !string.IsNullOrWhiteSpace(value) && !string.IsNullOrWhiteSpace(this.SearchTerm))
{
var separatorPattern = $"({this.SearchTerm})";
var result = Regex.Split(value, separatorPattern, RegexOptions.IgnoreCase, TimeSpan.FromSeconds(30));
var elementCounter = 0;

foreach (var element in result)
{
if (string.Equals(element, this.SearchTerm, StringComparison.OrdinalIgnoreCase))
{
builder.OpenElement(elementCounter, "span");
elementCounter++;
builder.AddAttribute(elementCounter, "class", "search-mark");
elementCounter++;
builder.AddContent(elementCounter, element);
elementCounter++;
builder.CloseElement();
}
else
{
builder.AddContent(elementCounter, element);
elementCounter++;
}
}
}
else
{
builder.AddContent(0, value);
}
}
}
}
61 changes: 61 additions & 0 deletions COMET.Web.Common/Components/CardView/CardView.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<!------------------------------------------------------------------------------
// Copyright (c) 2023-2024 Starion Group S.A.
//
// Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Théate Antoine, Nabil Abbar
//
// This file is part of CDP4-COMET WEB Community Edition
// The CDP4-COMET WEB Community Edition is the Starion Web Application implementation of ECSS-E-TM-10-25
// Annex A and Annex C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
------------------------------------------------------------------------------->

@namespace COMET.Web.Common.Components.CardView
@typeparam T
@inherits DisposableComponent

<p>
<table>
<tr>
<td id="search-textbox" style="visibility:@(this.AllowSearch ? "block": "hidden");">
<DxTextBox CssClass="inline-search-icon" SizeMode="SizeMode.Medium" BindValueMode="BindValueMode.OnDelayedInput" InputDelay="500" TextChanged="this.OnSearchTextChanged" NullText="Search..." ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto">
</DxTextBox>
</td>
<td id="sort-dropdown" style="visibility:@(this.AllowSort ? "block": "hidden");">
<DxComboBox TData="string" TValue="string" CssClass="inline-sort-icon" FilteringMode="DataGridFilteringMode.Contains" SizeMode="SizeMode.Medium" Data="@this.SortFields" SelectedItemChanged="@( x => this.OnSelectedSortItemChanged(x))"
@bind-Value="@this.SelectedSortField">
</DxComboBox>
</td>
</tr>
</table>
</p>
<div class="container" style="height:calc(100% - 40px); overflow:auto;">
<div class="row">
<Virtualize ItemSize="@this.ItemSize" ItemsProvider="this.LoadItems" @ref="this.virtualize">
<ItemContent>
<div class="col" style="padding-left:0px;margin-left:0px;height:(@this.ItemSize)px;min-width:(@this.MinWidth)px;">
<div class="card @(this.GetSelectedClass(@context))"
@onclick="@(() => this.SelectItem(@context))">
<div class="card-body" style="overflow-y:hidden;overflow-x:hidden">
<CascadingValue Name="CardView" Value = "this">
<CascadingValue Name="SearchTerm" Value="this.SearchTerm">
@this.ItemTemplate(@context)
</CascadingValue>
</CascadingValue>
</div>
</div>
</div>
</ItemContent>
</Virtualize>
</div>
</div>
Loading

0 comments on commit 7cd9b4c

Please sign in to comment.