Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
12 changes: 11 additions & 1 deletion src/DotNetEd.CoreAdmin/Controllers/CoreAdminDataController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Reflection;
Expand Down Expand Up @@ -37,6 +38,12 @@ public IActionResult Index(string id)
viewModel.EntityType = dbSetProperty.PropertyType.GetGenericArguments().First();
viewModel.DbSetProperty = dbSetProperty;

if (Attribute.IsDefined(viewModel.EntityType, typeof(DisplayAttribute)))
{
viewModel.DbDisplayName = viewModel.EntityType.GetCustomAttribute<DisplayAttribute>().Name;
}


var dbContextObject = (DbContext)this.HttpContext.RequestServices.GetRequiredService(dbSetEntity.DbContextType);
var query = dbContextObject.Set(viewModel.EntityType);

Expand Down Expand Up @@ -218,7 +225,8 @@ public IActionResult Create(string id)
var autoGeneratedPropertyNames =
newEntity.GetType().GetProperties()
.Where(p => p.GetCustomAttributes().Any(a => a.GetType().Name.Contains("DatabaseGenerated"))).Select(p => p.Name);


ViewBag.DbDisplayName = entityType.GetCustomAttribute<DisplayAttribute>().Name ?? id;
ViewBag.IgnoreFromForm = autoGeneratedPropertyNames;
ViewBag.Relationships = relationships;
return View(newEntity);
Expand All @@ -234,6 +242,7 @@ public IActionResult EditEntity(string dbSetName, string id)
.Where(p => p.GetCustomAttributes().Any(a => a.GetType().Name.Contains("DatabaseGenerated"))).Select(p => p.Name);

ViewBag.DbSetName = dbSetName;
ViewBag.DbDisplayName = entityType.GetCustomAttribute<DisplayAttribute>().Name ?? dbSetName;
ViewBag.Id = id;
ViewBag.Relationships = relationships;
ViewBag.IgnoreFromForm = databaseGeneratedProperties;
Expand All @@ -242,6 +251,7 @@ public IActionResult EditEntity(string dbSetName, string id)




[HttpPost]
public async Task<IActionResult> EditEntityPost(string dbSetName, string id, [FromForm] object formData)
{
Expand Down
2 changes: 2 additions & 0 deletions src/DotNetEd.CoreAdmin/DotNetEd.CoreAdmin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<Content Remove="Translations\it-IT.json" />
<Content Remove="Translations\ja-JP.json" />
<Content Remove="Translations\pt-BR.json" />
<Content Remove="Translations\de.json" />
</ItemGroup>

<ItemGroup>
Expand All @@ -37,6 +38,7 @@
<EmbeddedResource Include="Translations\fr-FR.json" />
<EmbeddedResource Include="Translations\ja-JP.json" />
<EmbeddedResource Include="Translations\pt-BR.json" />
<EmbeddedResource Include="Translations\de.json" />
</ItemGroup>

<ItemGroup>
Expand Down
3 changes: 2 additions & 1 deletion src/DotNetEd.CoreAdmin/JsonLocalizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)

foreach(var culture in cultureKeys)
{
var fileName = $"{culture}.json";
//Firefox usually returns something like: "de,en-US;q=0.9,en;q=0.8"
var fileName = $"{culture.Split(',')[0]}.json";
var key = translations.Keys.FirstOrDefault(k => k.EndsWith(fileName));
if (key != null)
{
Expand Down
13 changes: 13 additions & 0 deletions src/DotNetEd.CoreAdmin/Translations/de.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"Create": "Erstellen",
"AccessDatabaseEntries": "Zugang der Datenbank auf der linken Seite",
"DevelopmentModeMessage": "Sie befinden sich im Entwicklermodus. Keine Authentisierung wurde für CoreAdmin festgelegt. Core Admin wird außerhalb vom Entwicklermodus nicht erreichbar sein. Siehe Dokumentation https://github.com/edandersen/core-admin.",
"CreateNew": "Neu Erstellen",
"GoBack": "Zurück",
"Edit": "Bearbeiten",
"Delete": "Löschen",
"DeleteConfirm": "Bestätige Löschung",
"Auto": "Auto",
"Dark": "Dunkel",
"Light": "Hell"
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using DotNetEd.CoreAdmin.ViewModels;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNetEd.CoreAdmin.ViewComponents
Expand All @@ -22,6 +25,15 @@ public IViewComponentResult Invoke()
{
viewModel.DbContextNames.Add(dbSetEntity.DbContextType.Name);
viewModel.DbSetNames.Add(dbSetEntity.Name);

var d = dbSetEntity.Name;
if (Attribute.IsDefined(dbSetEntity.UnderlyingType, typeof(DisplayAttribute)))
{
var displayAttribute = dbSetEntity.UnderlyingType.GetCustomAttributes(typeof(DisplayAttribute), true).FirstOrDefault() as DisplayAttribute;
if (!String.IsNullOrEmpty(displayAttribute.Name))
d = displayAttribute.Name;
}
viewModel.DbDisplayNames.Add(d);
}

return View(viewModel);
Expand Down
1 change: 1 addition & 0 deletions src/DotNetEd.CoreAdmin/ViewModels/DataListViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public class DataListViewModel
public IEnumerable<object> Data { get; internal set; }
public DbContext DbContext { get; internal set; }
public PropertyInfo DbSetProperty { get; internal set; }
public string DbDisplayName { get; internal set; }
}
}
2 changes: 2 additions & 0 deletions src/DotNetEd.CoreAdmin/ViewModels/MenuViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ public class MenuViewModel
{
public List<string> DbContextNames { get; set; } = new List<string>();
public List<string> DbSetNames { get; set; } = new List<string>();

public List<string> DbDisplayNames { get; set; } = new List<string>();
}
}
2 changes: 1 addition & 1 deletion src/DotNetEd.CoreAdmin/Views/CoreAdminData/Create.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Layout = "_CoreAdminLayout";
}

<h1 class="mt-3">@ViewBag.DbSetName - @_localizer["Create"]</h1>
<h1 class="mt-3">@ViewBag.DbDisplayName - @_localizer["Create"]</h1>


@using (Html.BeginForm("CreateEntityPost",
Expand Down
2 changes: 1 addition & 1 deletion src/DotNetEd.CoreAdmin/Views/CoreAdminData/Edit.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Layout = "_CoreAdminLayout";
}

<h1 class="mt-3">@ViewBag.DbSetName - @_localizer["Edit"]</h1>
<h1 class="mt-3">@ViewBag.DbDisplayName - @_localizer["Edit"]</h1>


@using (Html.BeginForm("EditEntityPost",
Expand Down
85 changes: 47 additions & 38 deletions src/DotNetEd.CoreAdmin/Views/CoreAdminData/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -16,53 +16,63 @@
var options = CoreAdminOptions.FirstOrDefault();
}

<h1 class="mt-3">@Model.DbSetProperty.Name</h1>
<h1 class="mt-3">@Model.DbDisplayName</h1>

<div class="row">
<div class="col-lg-12 my-3 text-end">
@Html.ActionLink(_localizer["CreateNew"], "Create", new { id = Model.DbSetProperty.Name }, new { @class = "btn btn-primary"})
</div>
</div>

@(Html
@(
Html
.Grid(Model.Data)
.Build((columns) => {

foreach(var entityProperty in Model.EntityType.GetProperties())
{

ParameterExpression entity = Expression.Parameter(typeof(object), "ent");
var changedType = Expression.Convert(entity, Model.EntityType);
var property = Expression.Property(changedType, entityProperty.Name);
var propertyDisplayName = entityProperty.Name;
if(Attribute.IsDefined(entityProperty, typeof(DisplayAttribute)))


if (Attribute.IsDefined(entityProperty, typeof(DisplayAttribute)))
{
var displayAttribute = entityProperty.GetCustomAttributes(typeof(DisplayAttribute),true).FirstOrDefault() as DisplayAttribute;
if(displayAttribute != null)
var displayAttribute = entityProperty.GetCustomAttributes(typeof(DisplayAttribute), true).FirstOrDefault() as DisplayAttribute;
if (displayAttribute != null)
{
var displayAutoGeneratedField = displayAttribute.GetAutoGenerateField();
if(!( displayAutoGeneratedField.HasValue? displayAutoGeneratedField.Value : false ))
if (!(displayAutoGeneratedField.HasValue ? displayAutoGeneratedField.Value : false))
continue;
if(!string.IsNullOrEmpty(displayAttribute.Description))
propertyDisplayName = displayAttribute.Description;
if (!string.IsNullOrEmpty(displayAttribute.Name))
propertyDisplayName = displayAttribute.Name;
}
}
else if (entityProperty.PropertyType == typeof(Boolean))
}

if (entityProperty.PropertyType == typeof(Boolean))
{
var lambda = Expression.Lambda<Func<object, Boolean>>(property, entity);
columns.Add(lambda).RenderedAs(m=> Html.CheckBox(entityProperty.Name, lambda.Compile().Invoke(m))).Titled(propertyDisplayName);
var l = Expression.Lambda<Func<object, Boolean>>(property, entity);
columns.Add(l).RenderedAs(m => Html.CheckBox(entityProperty.Name, l.Compile().Invoke(m), new { onclick = "return false;", style = "cursor: default;" })).Titled(propertyDisplayName);
continue;
}
else if (entityProperty.PropertyType == typeof(byte[]))


if (entityProperty.PropertyType == typeof(byte[]))
{
var lambda = Expression.Lambda<Func<object, byte[]>>(property, entity);
var l = Expression.Lambda<Func<object, byte[]>>(property, entity);

columns.Add(lambda).Titled(entityProperty.Name)
.RenderedAs((value) => {
var base64 = ImageUtils.WebBase64EncodeImageByteArrayOrNull(lambda.Compile().Invoke(value));
columns.Add(l).Titled(entityProperty.Name)
.RenderedAs((value) =>
{
var base64 = ImageUtils.WebBase64EncodeImageByteArrayOrNull(l.Compile().Invoke(value));
return base64 == null ? string.Empty : $"<img height='48' src='{base64}'>";
} ).Encoded(false);
}
/* if (entityProperty.PropertyType == typeof(Guid))
}).Encoded(false);
continue;
}


/* if (entityProperty.PropertyType == typeof(Guid))
{
var lambda = Expression.Lambda<Func<object,Guid>>(property, entity);

Expand Down Expand Up @@ -128,23 +138,22 @@
var lambda = Expression.Lambda<Func<object, DateTimeOffset?>>(property, entity);
columns.Add(lambda).Titled(propertyDisplayName);
}*/
else
{
//Use reflection to build up lambda expression and call columns.Add(...) and Titled(...) for any field that can be rendered as text.
//This is equivalent to:
//if(entityProperty.PropertyType == typeof(Foo?)){
// var lambda = Expression.Lambda<Func<object, Foo?>>(property, entity);
// columns.Add(lambda).Titled(propertyDisplayName);
//}
//But avoids needing an else if for each possible type, nullable types, etc..
var funcType = typeof(Func<,>).MakeGenericType(typeof(object),entityProperty.PropertyType);
var lambdaMethod = typeof(Expression).GetMethods(BindingFlags.Public|BindingFlags.Static).Where(m=>m.Name == "Lambda" && m.IsGenericMethod).First().MakeGenericMethod(funcType);
var lambda = lambdaMethod.Invoke(null,new object[]{property,new ParameterExpression[]{entity}});
var addMethod = columns.GetType().GetMethods(BindingFlags.Public|BindingFlags.Instance).Where(m=>m.Name=="Add" && m.IsGenericMethod).First();
var column = addMethod.MakeGenericMethod(entityProperty.PropertyType).Invoke(columns,new object[]{lambda});
var titledMethod = typeof(GridColumnExtensions).GetMethods(BindingFlags.Static|BindingFlags.Public).Where(m=>m.Name=="Titled").First().MakeGenericMethod(typeof(object),entityProperty.PropertyType);
titledMethod.Invoke(null, new[]{column, propertyDisplayName});
}

//Use reflection to build up lambda expression and call columns.Add(...) and Titled(...) for any field that can be rendered as text.
//This is equivalent to:
//if(entityProperty.PropertyType == typeof(Foo?)){
// var lambda = Expression.Lambda<Func<object, Foo?>>(property, entity);
// columns.Add(lambda).Titled(propertyDisplayName);
//}
//But avoids needing an else if for each possible type, nullable types, etc..
var funcType = typeof(Func<,>).MakeGenericType(typeof(object),entityProperty.PropertyType);
var lambdaMethod = typeof(Expression).GetMethods(BindingFlags.Public|BindingFlags.Static).Where(m=>m.Name == "Lambda" && m.IsGenericMethod).First().MakeGenericMethod(funcType);
var lambda = lambdaMethod.Invoke(null,new object[]{property,new ParameterExpression[]{entity}});
var addMethod = columns.GetType().GetMethods(BindingFlags.Public|BindingFlags.Instance).Where(m=>m.Name=="Add" && m.IsGenericMethod).First();
var column = addMethod.MakeGenericMethod(entityProperty.PropertyType).Invoke(columns,new object[]{lambda});
var titledMethod = typeof(GridColumnExtensions).GetMethods(BindingFlags.Static|BindingFlags.Public).Where(m=>m.Name=="Titled").First().MakeGenericMethod(typeof(object),entityProperty.PropertyType);
titledMethod.Invoke(null, new[]{column, propertyDisplayName});

}

// only supports single PKs, not composite ones
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@model DotNetEd.CoreAdmin.ViewModels.MenuViewModel

@model DotNetEd.CoreAdmin.ViewModels.MenuViewModel
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link" title="Home" href="@Url.Action("Index", "CoreAdmin")">
Expand All @@ -14,13 +15,13 @@
<span>Resources</span>
</h6>
<ul class="nav flex-column mb-auto">
@foreach (var dbSetName in Model.DbSetNames)
{
@for (int i = 0; i < Model.DbSetNames.Count; i++)
{
<li class="nav-item">
<a class="nav-link d-flex align-items-center gap-2" title="@dbSetName" href="@Url.Action("Index", "CoreAdminData", new { Id = dbSetName })">
<a class="nav-link d-flex align-items-center gap-2" title="@Model.DbSetNames[i]" href="@Url.Action("Index", "CoreAdminData", new { Id = Model.DbSetNames[i] })">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-layers"><polygon points="12 2 2 7 12 12 22 7 12 2"></polygon><polyline points="2 17 12 22 22 17"></polyline><polyline points="2 12 12 17 22 12"></polyline></svg>

@dbSetName
@Model.DbDisplayNames[i]
</a>
</li>
}
Expand Down
11 changes: 11 additions & 0 deletions src/DotNetEd.CoreAdmin/Views/Shared/DisplayTemplates/String.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@model object

@if (Model == null)
{
<strong>Null string</strong>
}
else
{
<p>@Model</p>
<hr/>
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@

var values = Enum.GetValues(ViewData.ModelMetadata.ModelType);
var names = Enum.GetNames(ViewData.ModelMetadata.ModelType);

var items = new List<SelectListItem>();
for (var i = 0; i < values.Length; i++)
{
items.Add(new SelectListItem() { Text = names[i], Value = values.GetValue(i).ToString(), Selected = (Model.ToString() == values.GetValue(i).ToString()) });
}
var selectList = Html.GetEnumSelectList(ViewData.ModelMetadata.ModelType);

@Html.DropDownList("", items, new {@class = "form-control"})
@Html.DropDownList("", selectList, new { @class = "form-control" })

}