diff --git a/.idea/.idea.HopFrame/.idea/workspace.xml b/.idea/.idea.HopFrame/.idea/workspace.xml
index cb2bebd..1ccd691 100644
--- a/.idea/.idea.HopFrame/.idea/workspace.xml
+++ b/.idea/.idea.HopFrame/.idea/workspace.xml
@@ -11,26 +11,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -136,28 +117,28 @@
- {
+ "keyToString": {
+ ".NET Launch Settings Profile.HopFrame.Testing.Api: https.executor": "Run",
+ ".NET Launch Settings Profile.HopFrame.Testing.executor": "Run",
+ ".NET Launch Settings Profile.HopFrame.Testing: https.executor": "Run",
+ ".NET Project.HopFrame.Testing.executor": "Run",
+ "72b118b0-a6fc-4561-acdf-74f0b454dbb8.executor": "Debug",
+ "RunOnceActivity.ShowReadmeOnStart": "true",
+ "RunOnceActivity.git.unshallow": "true",
+ "b5f11219-dfc4-47a1-b02c-90ab603034fb.executor": "Debug",
+ "dcdf1689-dc07-47e4-8824-2e60a4fbf301.executor": "Debug",
+ "git-widget-placeholder": "!34 on feature/repositories",
+ "list.type.of.created.stylesheet": "CSS",
+ "node.js.detected.package.eslint": "true",
+ "node.js.detected.package.tslint": "true",
+ "node.js.selected.package.eslint": "(autodetect)",
+ "node.js.selected.package.tslint": "(autodetect)",
+ "nodejs_package_manager_path": "npm",
+ "settings.editor.selected.configurable": "preferences.pluginManager",
+ "vue.rearranger.settings.migration": "true"
}
-}]]>
+}
@@ -277,15 +258,7 @@
-
-
-
-
- 1736850899254
-
-
-
- 1736850899254
+
@@ -671,7 +644,15 @@
1740743139064
-
+
+
+ 1741985203179
+
+
+
+ 1741985203179
+
+
@@ -722,7 +703,6 @@
-
@@ -747,6 +727,7 @@
-
+
+
\ No newline at end of file
diff --git a/docs/Writerside/hopframe.tree b/docs/Writerside/hopframe.tree
index 3afb72e..46bb555 100644
--- a/docs/Writerside/hopframe.tree
+++ b/docs/Writerside/hopframe.tree
@@ -17,6 +17,7 @@
+
@@ -27,6 +28,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/docs/Writerside/topics/Custom-Repositories.md b/docs/Writerside/topics/Custom-Repositories.md
new file mode 100644
index 0000000..e0c9c09
--- /dev/null
+++ b/docs/Writerside/topics/Custom-Repositories.md
@@ -0,0 +1,132 @@
+# Custom Repositories
+
+Custom repositories in HopFrame allow you to define and integrate custom logic for managing database entities. By implementing the `IHopFrameRepository` interface, you can gain full control over how data is retrieved, modified, and managed. This feature is ideal for scenarios where the default behavior does not meet specific business requirements.
+
+## IHopFrameRepository Interface
+
+The `IHopFrameRepository` interface defines a contract for a repository that works with a specific model (`TModel`) and its primary key (`TKey`). The interface provides the following methods:
+
+- **LoadPage**
+ Loads a paginated set of items.
+
+ ```c#
+ Task> LoadPage(int page, int perPage);
+ ```
+
+ - **Parameters:**
+ - `page`: The page number to load.
+ - `perPage`: The number of items per page.
+ - **Returns:** A collection of items for the specified page.
+
+- **Search**
+ Performs a search query on the repository.
+
+ ```c#
+ Task> Search(string searchTerm, int page, int perPage);
+ ```
+
+ - **Parameters:**
+ - `searchTerm`: The term to search for.
+ - `page`: The page number to load.
+ - `perPage`: The number of items per page.
+ - **Returns:** A `SearchResult` containing matching items and the total number of pages.
+
+- **GetTotalPageCount**
+ Retrieves the total number of pages based on the items per page.
+
+ ```c#
+ Task GetTotalPageCount(int perPage);
+ ```
+
+ - **Parameters:**
+ - `perPage`: The number of items per page.
+ - **Returns:** The total number of pages.
+
+- **CreateItem**
+ Adds a new item to the repository.
+
+ ```c#
+ Task CreateItem(TModel item);
+ ```
+
+ - **Parameters:**
+ - `item`: The item to create.
+
+- **EditItem**
+ Updates an existing item in the repository.
+
+ ```c#
+ Task EditItem(TModel item);
+ ```
+
+ - **Parameters:**
+ - `item`: The item to update.
+
+- **DeleteItem**
+ Removes an item from the repository.
+
+ ```c#
+ Task DeleteItem(TModel item);
+ ```
+
+ - **Parameters:**
+ - `item`: The item to delete.
+
+- **GetOne**
+ Retrieves a single item based on its primary key.
+
+ ```c#
+ Task GetOne(TKey key);
+ ```
+
+ - **Parameters:**
+ - `key`: The primary key of the item to retrieve.
+ - **Returns:** The item if found, or `null` if not.
+
+## `SearchResult` Struct
+
+The `SearchResult` struct is used to encapsulate the results of a search query.
+
+- **Properties:**
+ - `Items`: The items retrieved from the search query.
+ - `PageCount`: The total number of pages based on the search results.
+
+```c#
+public readonly struct SearchResult(IEnumerable items, int pageCount) {
+ public IEnumerable Items { get; init; }
+ public int PageCount { get; init; }
+}
+```
+
+## Adding Custom Repositories
+
+To add and configure a custom repository in HopFrame, use the `AddCustomRepository` methods. These methods allow you to specify a repository class (`TRepository`) implementing `IHopFrameRepository` and define configurations for the associated table.
+
+- **With Configurator**
+
+ ```c#
+ HopFrameConfigurator AddCustomRepository(
+ Expression> keyExpression,
+ Action> configurator
+ )
+ where TRepository : IHopFrameRepository;
+ ```
+
+ - **Parameters:**
+ - `keyExpression`: The key of the model.
+ - `configurator`: Configures the table page.
+
+- **Without Configurator**
+
+ ```c#
+ TableConfigurator AddCustomRepository(
+ Expression> keyExpression
+ )
+ where TRepository : IHopFrameRepository;
+ ```
+
+ - **Parameters:**
+ - `keyExpression`: The key of the model.
+ - **Returns:** A `TableConfigurator` to configure the table.
+
+By implementing custom repositories and using these methods, you can fully leverage the flexibility of HopFrame for your data management needs. Let me know if you'd like further elaboration!
\ No newline at end of file
diff --git a/docs/Writerside/topics/Exporter-Plugin.md b/docs/Writerside/topics/Exporter-Plugin.md
new file mode 100644
index 0000000..e2492c3
--- /dev/null
+++ b/docs/Writerside/topics/Exporter-Plugin.md
@@ -0,0 +1,51 @@
+# Exporter Plugin
+
+The Exporter Plugin is a tool for managing the import and export of data from the HopFrame UI. It provides functionality for exporting table data into a CSV file and importing data back into the system, making data manipulation and backups more seamless.
+
+## What the Exporter Plugin Does
+
+1. **Export Table Data to CSV**
+ - The plugin allows users to export all data from a table as a CSV file.
+ - The exported file includes all non-virtual properties as table headers.
+ - The export process dynamically constructs rows for each entry in the table.
+
+2. **Import Data from CSV**
+ - Users can import a CSV file to populate or update a table.
+ - The import process reads the file, validates the headers, and creates new entries or updates existing ones.
+ - Relationships and enumerable properties are also resolved using the appropriate managers.
+
+3. **User Interface Integration**
+ - Adds two buttons, "Export" and "Import," to the page header of each table.
+ - **Export Button:** Initiates the export functionality.
+ - **Import Button:** Allows users to upload a CSV file for import.
+
+4. **Error Handling**
+ - Ensures errors during import or export (e.g., invalid file format, missing data, or system issues) are shown to the user as toast messages.
+
+## Adding the Exporter Plugin
+
+To include the Exporter Plugin in your HopFrame setup, use the `AddExporters` method provided by the `HopFrameConfiguratorExtensions`.
+
+Here’s how to register the Exporter Plugin in your application configuration:
+
+```c#
+builder.Services.AddHopFrame(options => {
+ options.AddExporters();
+});
+```
+
+The `AddExporters` method internally registers the `ExporterPlugin` and attaches its functionality to the HopFrame.
+
+## Key Features of the Export Process
+
+- **Dynamic Header Creation:** Automatically generates headers based on the table's non-virtual properties.
+- **Data Transformation:** Transforms property values into CSV-compatible formats.
+- **File Download:** Saves the generated CSV file with the table’s display name.
+
+## Key Features of the Import Process
+
+- **Header Validation:** Validates that the CSV file headers match the table's properties.
+- **Type Conversion:** Converts values in the CSV file to their respective data types.
+- **Relationship Management:** Resolves relationships and enumerable properties during import.
+
+This plugin streamlines data operations, reducing manual effort and enabling quick data migration or updates. Let me know if you’d like to dive deeper into any specific aspect!
\ No newline at end of file
diff --git a/docs/Writerside/topics/HopFrameConfig.md b/docs/Writerside/topics/HopFrameConfig.md
index f6e9ff9..a4329d3 100644
--- a/docs/Writerside/topics/HopFrameConfig.md
+++ b/docs/Writerside/topics/HopFrameConfig.md
@@ -118,6 +118,50 @@ DbContextConfigurator? GetDbContext() where TDbContext :
- **Returns:** The configurator of the context if it already was defined, `null` if not.
+### AddCustomRepository (With configurator)
+
+Adds a table of the desired type and configures it to use a custom repository.
+
+```c#
+HopFrameConfigurator AddCustomRepository(
+ Expression> keyExpression,
+ Action> configurator
+)
+ where TRepository : IHopFrameRepository
+```
+
+- **Type Parameters:**
+ - `TRepository`: The repository class that inherits from `IHopFrameRepository` (needs to be registered as a service).
+ - `TModel`: The model of the table.
+ - `TKey`: The type of the primary key.
+
+- **Parameters:**
+ - `keyExpression`: The key of the model.
+ - `configurator`: The configurator used for configuring the table page.
+
+- **Returns:** `HopFrameConfigurator`
+
+### AddCustomRepository (Without configurator)
+
+Adds a table of the desired type and configures it to use a custom repository.
+
+```c#
+TableConfigurator AddCustomRepository(
+ Expression> keyExpression
+)
+ where TRepository : IHopFrameRepository
+```
+
+- **Type Parameters:**
+ - `TRepository`: The repository class that inherits from `IHopFrameRepository` (needs to be registered as a service).
+ - `TModel`: The model of the table.
+ - `TKey`: The type of the primary key.
+
+- **Parameters:**
+ - `keyExpression`: The key of the model.
+
+- **Returns:** The configurator used for configuring the table page: `TableConfigurator`.
+
### DisplayUserInfo
Determines if the name of the currently logged-in user should be displayed in the top right corner of the admin UI.
diff --git a/docs/Writerside/topics/IFileService.md b/docs/Writerside/topics/IFileService.md
new file mode 100644
index 0000000..6ee41fe
--- /dev/null
+++ b/docs/Writerside/topics/IFileService.md
@@ -0,0 +1,41 @@
+# IFileService
+
+The `IFileService` interface provides methods for handling file operations, such as downloading and uploading files within the HopFrame web application. It abstracts file-related operations to ensure a smooth and consistent user experience.
+
+## Methods
+
+1. **DownloadFile**
+ - Initiates the download of a file with the given name and data.
+ - Suitable for dynamically generating and offering files to the user, such as CSV exports or reports.
+
+ ```c#
+ Task DownloadFile(string name, byte[] data);
+ ```
+
+ - **Parameters:**
+ - `name`: The name of the file to be downloaded (including the extension, e.g., "example.csv").
+ - `data`: The byte array representing the content of the file.
+ - **Usage Example:** Exporting table data as a CSV file for download.
+
+2. **UploadFile**
+ - Allows the user to upload a file through the web interface and returns the uploaded file for further processing.
+ - This method provides integration with Blazor's `IBrowserFile` for easy file handling.
+
+ ```c#
+ Task UploadFile();
+ ```
+
+ - **Returns:** An `IBrowserFile` instance representing the uploaded file.
+ - **Usage Example:** Importing data from a CSV file to populate or update a table.
+
+## Integration
+
+The `IFileService` is commonly used in conjunction with plugins or components that require file operations, such as the Exporter Plugin, which leverages this service to enable data export and import functionality.
+
+## Key Features
+
+- Streamlines file handling for web applications.
+- Simplifies both download and upload processes with minimal code.
+- Ensures compatibility with Blazor's file-handling capabilities.
+
+By implementing or extending the `IFileService`, developers can customize the file-handling behavior to suit specific application needs. Let me know if you'd like more examples or details!
\ No newline at end of file
diff --git a/src/HopFrame.Web/HopFrameConfiguratorExtensions.cs b/src/HopFrame.Web/HopFrameConfiguratorExtensions.cs
index 9eae99e..5282d60 100644
--- a/src/HopFrame.Web/HopFrameConfiguratorExtensions.cs
+++ b/src/HopFrame.Web/HopFrameConfiguratorExtensions.cs
@@ -56,6 +56,10 @@ public static class HopFrameConfiguratorExtensions {
return configurator;
}
+ ///
+ /// Registers the Exporter Plugin for data import/export functionality.
+ ///
+ /// The configurator for the HopFrame configuration.
public static HopFrameConfigurator AddExporters(this HopFrameConfigurator configurator) {
configurator.AddPlugin();
return configurator;
diff --git a/src/HopFrame.Web/Services/IFileService.cs b/src/HopFrame.Web/Services/IFileService.cs
index e8d4dff..4077441 100644
--- a/src/HopFrame.Web/Services/IFileService.cs
+++ b/src/HopFrame.Web/Services/IFileService.cs
@@ -2,10 +2,22 @@
namespace HopFrame.Web.Services;
+///
+/// Provides file handling capabilities for downloading and uploading files.
+///
public interface IFileService {
+ ///
+ /// Initiates a file download with the specified name and data.
+ ///
+ /// The name of the file to be downloaded.
+ /// The byte array representing the file's content.
public Task DownloadFile(string name, byte[] data);
+ ///
+ /// Allows the user to upload a file and returns the uploaded file for processing.
+ ///
+ /// A task that returns an IBrowserFile representing the uploaded file.
public Task UploadFile();
}
\ No newline at end of file