Added reload button and animation
This commit is contained in:
58
.idea/.idea.HopFrame/.idea/workspace.xml
generated
58
.idea/.idea.HopFrame/.idea/workspace.xml
generated
@@ -11,15 +11,13 @@
|
|||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="0648788e-7696-4e60-bf12-5d5601f33d8c" name="Changes" comment="">
|
<list default="true" id="0648788e-7696-4e60-bf12-5d5601f33d8c" name="Changes" comment="">
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/.idea.HopFrame/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.HopFrame/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/.idea.HopFrame/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.HopFrame/.idea/workspace.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/DbContextConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/DbContextConfig.cs" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/HopFrameConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/HopFrameConfig.cs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/PropertyConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/PropertyConfig.cs" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/PropertyConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/PropertyConfig.cs" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/TableConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/TableConfig.cs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Services/ITableManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Services/ITableManager.cs" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Services/ITableManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Services/ITableManager.cs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Services/Implementations/TableManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Services/Implementations/TableManager.cs" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Services/Implementations/TableManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Services/Implementations/TableManager.cs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Web/Components/Dialogs/HopFrameEditor.razor" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Web/Components/Dialogs/HopFrameEditor.razor" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Web/Components/Pages/HopFrameListView.razor" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Web/Components/Pages/HopFrameListView.razor" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/HopFrame.Web/Components/Pages/HopFrameListView.razor" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Web/Components/Pages/HopFrameListView.razor" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Web/Helpers/TypeExtensions.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Web/Helpers/TypeExtensions.cs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/HopFrame.Web/Models/EditorDialogData.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Web/Models/EditorDialogData.cs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/testing/HopFrame.Testing/Components/Pages/Home.razor" beforeDir="false" afterPath="$PROJECT_DIR$/testing/HopFrame.Testing/Components/Pages/Home.razor" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/testing/HopFrame.Testing/Models/Post.cs" beforeDir="false" afterPath="$PROJECT_DIR$/testing/HopFrame.Testing/Models/Post.cs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/testing/HopFrame.Testing/Program.cs" beforeDir="false" afterPath="$PROJECT_DIR$/testing/HopFrame.Testing/Program.cs" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/testing/HopFrame.Testing/Program.cs" beforeDir="false" afterPath="$PROJECT_DIR$/testing/HopFrame.Testing/Program.cs" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
@@ -81,24 +79,24 @@
|
|||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
<option name="showLibraryContents" value="true" />
|
<option name="showLibraryContents" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent"><![CDATA[{
|
<component name="PropertiesComponent">{
|
||||||
"keyToString": {
|
"keyToString": {
|
||||||
".NET Launch Settings Profile.HopFrame.Testing.executor": "Run",
|
".NET Launch Settings Profile.HopFrame.Testing.executor": "Run",
|
||||||
".NET Launch Settings Profile.HopFrame.Testing: https.executor": "Run",
|
".NET Launch Settings Profile.HopFrame.Testing: https.executor": "Run",
|
||||||
".NET Project.HopFrame.Testing.executor": "Run",
|
".NET Project.HopFrame.Testing.executor": "Run",
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
"RunOnceActivity.git.unshallow": "true",
|
"RunOnceActivity.git.unshallow": "true",
|
||||||
"git-widget-placeholder": "feature/setup",
|
"git-widget-placeholder": "feature/setup",
|
||||||
"list.type.of.created.stylesheet": "CSS",
|
"list.type.of.created.stylesheet": "CSS",
|
||||||
"node.js.detected.package.eslint": "true",
|
"node.js.detected.package.eslint": "true",
|
||||||
"node.js.detected.package.tslint": "true",
|
"node.js.detected.package.tslint": "true",
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
"node.js.selected.package.tslint": "(autodetect)",
|
"node.js.selected.package.tslint": "(autodetect)",
|
||||||
"nodejs_package_manager_path": "npm",
|
"nodejs_package_manager_path": "npm",
|
||||||
"settings.editor.selected.configurable": "preferences.environmentSetup",
|
"settings.editor.selected.configurable": "preferences.environmentSetup",
|
||||||
"vue.rearranger.settings.migration": "true"
|
"vue.rearranger.settings.migration": "true"
|
||||||
}
|
}
|
||||||
}]]></component>
|
}</component>
|
||||||
<component name="RunManager" selected=".NET Launch Settings Profile.HopFrame.Testing: https">
|
<component name="RunManager" selected=".NET Launch Settings Profile.HopFrame.Testing: https">
|
||||||
<configuration name="HopFrame.Testing: http" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
|
<configuration name="HopFrame.Testing: http" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
|
||||||
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/testing/HopFrame.Testing/HopFrame.Testing.csproj" />
|
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/testing/HopFrame.Testing/HopFrame.Testing.csproj" />
|
||||||
@@ -151,7 +149,8 @@
|
|||||||
<workItem from="1736863626597" duration="7027000" />
|
<workItem from="1736863626597" duration="7027000" />
|
||||||
<workItem from="1736875984621" duration="8464000" />
|
<workItem from="1736875984621" duration="8464000" />
|
||||||
<workItem from="1736884461354" duration="1075000" />
|
<workItem from="1736884461354" duration="1075000" />
|
||||||
<workItem from="1736962119221" duration="7774000" />
|
<workItem from="1736962119221" duration="8119000" />
|
||||||
|
<workItem from="1737021098746" duration="1810000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00001" summary="Added basic configuration">
|
<task id="LOCAL-00001" summary="Added basic configuration">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
@@ -185,7 +184,15 @@
|
|||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1736885531216</updated>
|
<updated>1736885531216</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="5" />
|
<task id="LOCAL-00005" summary="Added entry saving support">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1736970238802</created>
|
||||||
|
<option name="number" value="00005" />
|
||||||
|
<option name="presentableId" value="LOCAL-00005" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1736970238802</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="6" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
@@ -199,6 +206,7 @@
|
|||||||
<MESSAGE value="Added admin page navigation" />
|
<MESSAGE value="Added admin page navigation" />
|
||||||
<MESSAGE value="Added database loading logic" />
|
<MESSAGE value="Added database loading logic" />
|
||||||
<MESSAGE value="Started working on listing page" />
|
<MESSAGE value="Started working on listing page" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="Started working on listing page" />
|
<MESSAGE value="Added entry saving support" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="Added entry saving support" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -21,7 +21,8 @@ public class DbContextConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DbContextConfig<TDbContext>(Type context) : DbContextConfig(context) where TDbContext : DbContext {
|
public class DbContextConfig<TDbContext>(DbContextConfig config) {
|
||||||
|
public DbContextConfig InnerConfig { get; } = config;
|
||||||
|
|
||||||
public DbContextConfig<TDbContext> Table<TModel>(Action<TableConfig<TModel>> configurator) where TModel : class {
|
public DbContextConfig<TDbContext> Table<TModel>(Action<TableConfig<TModel>> configurator) where TModel : class {
|
||||||
var table = Table<TModel>();
|
var table = Table<TModel>();
|
||||||
@@ -30,7 +31,7 @@ public class DbContextConfig<TDbContext>(Type context) : DbContextConfig(context
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TableConfig<TModel> Table<TModel>() where TModel : class {
|
public TableConfig<TModel> Table<TModel>() where TModel : class {
|
||||||
var table = Tables.Single(table => table.TableType == typeof(TModel));
|
var table = InnerConfig.Tables.Single(table => table.TableType == typeof(TModel));
|
||||||
return new TableConfig<TModel>(table);
|
return new TableConfig<TModel>(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,15 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
namespace HopFrame.Core.Config;
|
namespace HopFrame.Core.Config;
|
||||||
|
|
||||||
public class HopFrameConfig {
|
public class HopFrameConfig {
|
||||||
public List<DbContextConfig> Contexts { get; init; } = new();
|
public List<DbContextConfig> Contexts { get; } = new();
|
||||||
public bool DisplayUserInfo { get; set; } = true;
|
public bool DisplayUserInfo { get; set; } = true;
|
||||||
public Type? AuthHandler { get; set; }
|
|
||||||
public string? BasePolicy { get; set; }
|
public string? BasePolicy { get; set; }
|
||||||
public string? LoginPageRewrite { get; set; }
|
public string? LoginPageRewrite { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HopFrameConfigurator(HopFrameConfig config) {
|
public class HopFrameConfigurator(HopFrameConfig config) {
|
||||||
|
public HopFrameConfig InnerConfig { get; } = config;
|
||||||
|
|
||||||
public HopFrameConfigurator AddDbContext<TDbContext>(Action<DbContextConfig<TDbContext>> configurator) where TDbContext : DbContext {
|
public HopFrameConfigurator AddDbContext<TDbContext>(Action<DbContextConfig<TDbContext>> configurator) where TDbContext : DbContext {
|
||||||
var context = AddDbContext<TDbContext>();
|
var context = AddDbContext<TDbContext>();
|
||||||
configurator.Invoke(context);
|
configurator.Invoke(context);
|
||||||
@@ -19,28 +20,23 @@ public class HopFrameConfigurator(HopFrameConfig config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DbContextConfig<TDbContext> AddDbContext<TDbContext>() where TDbContext : DbContext {
|
public DbContextConfig<TDbContext> AddDbContext<TDbContext>() where TDbContext : DbContext {
|
||||||
var context = new DbContextConfig<TDbContext>(typeof(TDbContext));
|
var context = new DbContextConfig(typeof(TDbContext));
|
||||||
config.Contexts.Add(context);
|
InnerConfig.Contexts.Add(context);
|
||||||
return context;
|
return new DbContextConfig<TDbContext>(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HopFrameConfigurator DisplayUserInfo(bool display) {
|
public HopFrameConfigurator DisplayUserInfo(bool display) {
|
||||||
config.DisplayUserInfo = display;
|
InnerConfig.DisplayUserInfo = display;
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HopFrameConfigurator SetAuthHandler<TAuthHandler>() where TAuthHandler : IHopFrameAuthHandler {
|
|
||||||
config.AuthHandler = typeof(TAuthHandler);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HopFrameConfigurator SetBasePolicy(string basePolicy) {
|
public HopFrameConfigurator SetBasePolicy(string basePolicy) {
|
||||||
config.BasePolicy = basePolicy;
|
InnerConfig.BasePolicy = basePolicy;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HopFrameConfigurator SetLoginPage(string url) {
|
public HopFrameConfigurator SetLoginPage(string url) {
|
||||||
config.LoginPageRewrite = url;
|
InnerConfig.LoginPageRewrite = url;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,63 +16,70 @@ public class PropertyConfig(PropertyInfo info) {
|
|||||||
public bool Editable { get; set; } = true;
|
public bool Editable { get; set; } = true;
|
||||||
public bool Creatable { get; set; } = true;
|
public bool Creatable { get; set; } = true;
|
||||||
public bool DisplayValue { get; set; } = true;
|
public bool DisplayValue { get; set; } = true;
|
||||||
|
public bool IsRelation { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PropertyConfig<TProp>(PropertyConfig config) {
|
public class PropertyConfig<TProp>(PropertyConfig config) {
|
||||||
|
public PropertyConfig InnerConfig { get; } = config;
|
||||||
|
|
||||||
public PropertyConfig<TProp> SetDisplayName(string displayName) {
|
public PropertyConfig<TProp> SetDisplayName(string displayName) {
|
||||||
config.Name = displayName;
|
InnerConfig.Name = displayName;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyConfig<TProp> List(bool list) {
|
public PropertyConfig<TProp> List(bool list) {
|
||||||
config.List = list;
|
InnerConfig.List = list;
|
||||||
config.Searchable = false;
|
InnerConfig.Searchable = false;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyConfig<TProp> Sortable(bool sortable) {
|
public PropertyConfig<TProp> Sortable(bool sortable) {
|
||||||
config.Sortable = sortable;
|
InnerConfig.Sortable = sortable;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyConfig<TProp> Searchable(bool searchable) {
|
public PropertyConfig<TProp> Searchable(bool searchable) {
|
||||||
config.Searchable = searchable;
|
InnerConfig.Searchable = searchable;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyConfig<TProp> DisplayedProperty<TInnerProp>(Expression<Func<TProp, TInnerProp>> propertyExpression) {
|
public PropertyConfig<TProp> DisplayedProperty<TInnerProp>(Expression<Func<TProp, TInnerProp>> propertyExpression) {
|
||||||
config.DisplayedProperty = TableConfig<TProp>.GetPropertyInfo(propertyExpression);
|
InnerConfig.DisplayedProperty = TableConfig<TProp>.GetPropertyInfo(propertyExpression);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyConfig<TProp> Format(Func<TProp, string> formatter) {
|
public PropertyConfig<TProp> Format(Func<TProp, string> formatter) {
|
||||||
config.Formatter = obj => formatter.Invoke((TProp)obj);
|
InnerConfig.Formatter = obj => formatter.Invoke((TProp)obj);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyConfig<TProp> ValueParser(Func<string, TProp> parser) {
|
public PropertyConfig<TProp> ValueParser(Func<string, TProp> parser) {
|
||||||
config.Parser = str => parser.Invoke(str)!;
|
InnerConfig.Parser = str => parser.Invoke(str)!;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyConfig<TProp> ValueTemplate(Func<TProp> template) {
|
public PropertyConfig<TProp> ValueTemplate(Func<TProp> template) {
|
||||||
config.Template = () => template.Invoke()!;
|
InnerConfig.Template = () => template.Invoke()!;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyConfig<TProp> Editable(bool editable) {
|
public PropertyConfig<TProp> Editable(bool editable) {
|
||||||
config.Editable = editable;
|
InnerConfig.Editable = editable;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyConfig<TProp> Creatable(bool creatable) {
|
public PropertyConfig<TProp> Creatable(bool creatable) {
|
||||||
config.Creatable = creatable;
|
InnerConfig.Creatable = creatable;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyConfig<TProp> DisplayValue(bool display) {
|
public PropertyConfig<TProp> DisplayValue(bool display) {
|
||||||
config.DisplayValue = display;
|
InnerConfig.DisplayValue = display;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyConfig<TProp> IsRelation(bool isRelation) {
|
||||||
|
InnerConfig.IsRelation = isRelation;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,16 +35,17 @@ public class TableConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TableConfig<TModel>(TableConfig innerConfig) {
|
public class TableConfig<TModel>(TableConfig config) {
|
||||||
|
public TableConfig InnerConfig { get; } = config;
|
||||||
|
|
||||||
public TableConfig<TModel> Ignore() {
|
public TableConfig<TModel> Ignore() {
|
||||||
innerConfig.Ignored = true;
|
InnerConfig.Ignored = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyConfig<TProp> Property<TProp>(Expression<Func<TModel, TProp>> propertyExpression) {
|
public PropertyConfig<TProp> Property<TProp>(Expression<Func<TModel, TProp>> propertyExpression) {
|
||||||
var info = GetPropertyInfo(propertyExpression);
|
var info = GetPropertyInfo(propertyExpression);
|
||||||
var prop = innerConfig.Properties
|
var prop = InnerConfig.Properties
|
||||||
.Single(prop => prop.Info.Name == info.Name);
|
.Single(prop => prop.Info.Name == info.Name);
|
||||||
return new PropertyConfig<TProp>(prop);
|
return new PropertyConfig<TProp>(prop);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ namespace HopFrame.Core.Services;
|
|||||||
|
|
||||||
public interface ITableManager {
|
public interface ITableManager {
|
||||||
public IQueryable<object> LoadPage(int page, int perPage = 20);
|
public IQueryable<object> LoadPage(int page, int perPage = 20);
|
||||||
public (IEnumerable<object>, int) Search(string searchTerm, int page = 0, int perPage = 20);
|
public Task<(IEnumerable<object>, int)> Search(string searchTerm, int page = 0, int perPage = 20);
|
||||||
public int TotalPages(int perPage = 20);
|
public Task<int> TotalPages(int perPage = 20);
|
||||||
public Task DeleteItem(object item);
|
public Task DeleteItem(object item);
|
||||||
public Task EditItem(object item);
|
public Task EditItem(object item);
|
||||||
public Task AddItem(object item);
|
public Task AddItem(object item);
|
||||||
|
|||||||
@@ -16,19 +16,21 @@ internal sealed class TableManager<TModel>(DbContext context, TableConfig config
|
|||||||
.Take(perPage);
|
.Take(perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public (IEnumerable<object>, int) Search(string searchTerm, int page = 0, int perPage = 20) {
|
public Task<(IEnumerable<object>, int)> Search(string searchTerm, int page = 0, int perPage = 20) {
|
||||||
var table = context.Set<TModel>();
|
var table = context.Set<TModel>();
|
||||||
var all = IncludeForgeinKeys(table)
|
var all = IncludeForgeinKeys(table)
|
||||||
.AsEnumerable()
|
.AsEnumerable()
|
||||||
.Where(item => ItemSearched(item, searchTerm))
|
.Where(item => ItemSearched(item, searchTerm))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return (all.Skip(page * perPage).Take(perPage), (int)Math.Ceiling(all.Count / (double)perPage));
|
return Task.FromResult((
|
||||||
|
(IEnumerable<object>)all.Skip(page * perPage).Take(perPage),
|
||||||
|
(int)Math.Ceiling(all.Count / (double)perPage)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int TotalPages(int perPage = 20) {
|
public async Task<int> TotalPages(int perPage = 20) {
|
||||||
var table = context.Set<TModel>();
|
var table = context.Set<TModel>();
|
||||||
return (int)Math.Ceiling(table.Count() / (double)perPage);
|
return (int)Math.Ceiling(await table.CountAsync() / (double)perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteItem(object item) {
|
public async Task DeleteItem(object item) {
|
||||||
|
|||||||
@@ -1,22 +1,32 @@
|
|||||||
@page "/admin/{TableName}"
|
@page "/admin/{TableName}"
|
||||||
@layout HopFrameLayout
|
@layout HopFrameLayout
|
||||||
@rendermode InteractiveServer
|
@rendermode InteractiveServer
|
||||||
|
@implements IDisposable
|
||||||
|
|
||||||
@using HopFrame.Core.Config
|
@using HopFrame.Core.Config
|
||||||
@using HopFrame.Core.Services
|
@using HopFrame.Core.Services
|
||||||
@using HopFrame.Web.Models
|
@using HopFrame.Web.Models
|
||||||
@using Microsoft.JSInterop
|
@using Microsoft.JSInterop
|
||||||
@using System.Text.Json
|
@using Microsoft.EntityFrameworkCore
|
||||||
|
|
||||||
<FluentDialogProvider />
|
<FluentDialogProvider />
|
||||||
|
|
||||||
<div style="display: flex; flex-direction: column; height: 100%">
|
<div style="display: flex; flex-direction: column; height: 100%">
|
||||||
<FluentToolbar Class="hopframe-toolbar">
|
<FluentToolbar Class="hopframe-toolbar">
|
||||||
<h3>@_config?.PropertyName</h3>
|
<h3>@_config?.PropertyName</h3>
|
||||||
|
<FluentButton
|
||||||
|
IconStart="@(new Icons.Regular.Size16.ArrowClockwise())"
|
||||||
|
OnClick="Reload"
|
||||||
|
Loading="_loading"
|
||||||
|
Style="margin-left: 10px">
|
||||||
|
Refresh
|
||||||
|
</FluentButton>
|
||||||
|
|
||||||
<FluentSpacer />
|
<FluentSpacer />
|
||||||
<FluentSearch @oninput="OnSearch" @onchange="OnSearch" />
|
<FluentSearch @oninput="OnSearch" @onchange="OnSearch" />
|
||||||
<FluentButton OnClick="async () => { await CreateOrEdit(null); }">Add Entry</FluentButton>
|
<FluentButton OnClick="async () => { await CreateOrEdit(null); }">Add Entry</FluentButton>
|
||||||
</FluentToolbar>
|
</FluentToolbar>
|
||||||
|
<FluentProgress Visible="_loading" Width="100%" />
|
||||||
|
|
||||||
<div style="overflow-y: auto; flex-grow: 1">
|
<div style="overflow-y: auto; flex-grow: 1">
|
||||||
<FluentDataGrid Items="_currentlyDisplayedModels?.AsQueryable()">
|
<FluentDataGrid Items="_currentlyDisplayedModels?.AsQueryable()">
|
||||||
@@ -48,7 +58,7 @@
|
|||||||
|
|
||||||
@if (_totalPages > 1) {
|
@if (_totalPages > 1) {
|
||||||
<div class="hopframe-paginator">
|
<div class="hopframe-paginator">
|
||||||
<FluentButton BackgroundColor="transparent" OnClick="() => ChangePage(_currentPage - 1)">
|
<FluentButton BackgroundColor="transparent" OnClick="async () => await ChangePage(_currentPage - 1)">
|
||||||
<FluentIcon Value="@(new Icons.Regular.Size20.ArrowPrevious())" Color="Color.Neutral" />
|
<FluentIcon Value="@(new Icons.Regular.Size20.ArrowPrevious())" Color="Color.Neutral" />
|
||||||
</FluentButton>
|
</FluentButton>
|
||||||
|
|
||||||
@@ -58,12 +68,12 @@
|
|||||||
Items="Enumerable.Range(0, _totalPages)"
|
Items="Enumerable.Range(0, _totalPages)"
|
||||||
OptionValue="@(p => p.ToString())"
|
OptionValue="@(p => p.ToString())"
|
||||||
OptionText="@(p => (p + 1).ToString())"
|
OptionText="@(p => (p + 1).ToString())"
|
||||||
ValueChanged="s => ChangePage(Convert.ToInt32(s))"
|
ValueChanged="async s => await ChangePage(Convert.ToInt32(s))"
|
||||||
Width="max-content" SelectedOption="@_currentPage"/>
|
Width="max-content" SelectedOption="@_currentPage"/>
|
||||||
|
|
||||||
<span>of @_totalPages</span>
|
<span>of @_totalPages</span>
|
||||||
|
|
||||||
<FluentButton BackgroundColor="transparent" OnClick="() => ChangePage(_currentPage + 1)">
|
<FluentButton BackgroundColor="transparent" OnClick="async () => await ChangePage(_currentPage + 1)">
|
||||||
<FluentIcon Value="@(new Icons.Regular.Size20.ArrowNext())" Color="Color.Neutral" />
|
<FluentIcon Value="@(new Icons.Regular.Size20.ArrowNext())" Color="Color.Neutral" />
|
||||||
</FluentButton>
|
</FluentButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -99,18 +109,20 @@
|
|||||||
private int _currentPage;
|
private int _currentPage;
|
||||||
private int _totalPages;
|
private int _totalPages;
|
||||||
private string? _searchTerm;
|
private string? _searchTerm;
|
||||||
|
private bool _loading;
|
||||||
|
|
||||||
protected override void OnInitialized() {
|
protected override void OnInitialized() {
|
||||||
_config ??= Explorer.GetTable(TableName);
|
_config ??= Explorer.GetTable(TableName);
|
||||||
|
|
||||||
if (_config is null) {
|
if (_config is null) {
|
||||||
Navigator.NavigateTo("/admin", true);
|
Navigator.NavigateTo("/admin", true);
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_manager ??= Explorer.GetTableManager(_config.PropertyName);
|
protected override async Task OnInitializedAsync() {
|
||||||
_currentlyDisplayedModels = _manager!.LoadPage(_currentPage).ToArray();
|
_manager ??= Explorer.GetTableManager(_config!.PropertyName);
|
||||||
_totalPages = _manager.TotalPages();
|
_currentlyDisplayedModels = await _manager!.LoadPage(_currentPage).ToArrayAsync();
|
||||||
|
_totalPages = await _manager.TotalPages();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender) {
|
protected override async Task OnAfterRenderAsync(bool firstRender) {
|
||||||
@@ -122,6 +134,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
_searchCancel.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
private CancellationTokenSource _searchCancel = new();
|
private CancellationTokenSource _searchCancel = new();
|
||||||
private async Task OnSearch(ChangeEventArgs eventArgs) {
|
private async Task OnSearch(ChangeEventArgs eventArgs) {
|
||||||
await _searchCancel.CancelAsync();
|
await _searchCancel.CancelAsync();
|
||||||
@@ -130,24 +146,26 @@
|
|||||||
_searchCancel = new();
|
_searchCancel = new();
|
||||||
|
|
||||||
await Task.Delay(500, _searchCancel.Token);
|
await Task.Delay(500, _searchCancel.Token);
|
||||||
(var query, _totalPages) = _manager!.Search(_searchTerm);
|
(var query, _totalPages) = await _manager!.Search(_searchTerm);
|
||||||
_currentlyDisplayedModels = query.ToArray();
|
_currentlyDisplayedModels = query.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Reload() {
|
private async Task Reload() {
|
||||||
|
_loading = true;
|
||||||
if (!string.IsNullOrEmpty(_searchTerm)) {
|
if (!string.IsNullOrEmpty(_searchTerm)) {
|
||||||
(var query, _totalPages) = _manager!.Search(_searchTerm);
|
(var query, _totalPages) = await _manager!.Search(_searchTerm);
|
||||||
_currentlyDisplayedModels = query.ToArray();
|
_currentlyDisplayedModels = query.ToArray();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
OnInitialized();
|
await OnInitializedAsync();
|
||||||
}
|
}
|
||||||
|
_loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ChangePage(int page) {
|
private async Task ChangePage(int page) {
|
||||||
if (page < 0 || page > _totalPages - 1) return;
|
if (page < 0 || page > _totalPages - 1) return;
|
||||||
_currentPage = page;
|
_currentPage = page;
|
||||||
Reload();
|
await Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DeleteEntry(object element) {
|
private async Task DeleteEntry(object element) {
|
||||||
@@ -156,8 +174,7 @@
|
|||||||
if (result.Cancelled) return;
|
if (result.Cancelled) return;
|
||||||
|
|
||||||
await _manager!.DeleteItem(element);
|
await _manager!.DeleteItem(element);
|
||||||
|
await Reload();
|
||||||
Reload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CreateOrEdit(object? element) {
|
private async Task CreateOrEdit(object? element) {
|
||||||
@@ -176,6 +193,6 @@
|
|||||||
else
|
else
|
||||||
await _manager!.EditItem(data!.CurrentObject!);
|
await _manager!.EditItem(data!.CurrentObject!);
|
||||||
|
|
||||||
Reload();
|
await Reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,6 @@ builder.Services.AddDbContext<DatabaseContext>(options => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddHopFrame(options => {
|
builder.Services.AddHopFrame(options => {
|
||||||
options.SetAuthHandler<AuthService>();
|
|
||||||
options.AddDbContext<DatabaseContext>(context => {
|
options.AddDbContext<DatabaseContext>(context => {
|
||||||
context.Table<User>(table => {
|
context.Table<User>(table => {
|
||||||
table.Property(u => u.Password)
|
table.Property(u => u.Password)
|
||||||
|
|||||||
Reference in New Issue
Block a user