diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9b68d7f..1c156ac 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,6 +4,7 @@ stages:
- build
- test
- publish
+ - publish-help
before_script:
- echo "Setting up environment"
@@ -37,3 +38,16 @@ publish:
dependencies:
- build
- test
+
+publish-help:
+ stage: publish-help
+ script:
+ - export VERSION=$(echo $CI_COMMIT_TAG | sed 's/^v//')
+ - docker login -u leon.hoppe -p ${CI_REGISTRY_PASSWORD} registry.leon-hoppe.de
+ - docker build -t registry.leon-hoppe.de/leon.hoppe/hopframe:$VERSION -t registry.leon-hoppe.de/leon.hoppe/hopframe:latest .
+ - docker push registry.leon-hoppe.de/leon.hoppe/hopframe:$VERSION
+ - docker push registry.leon-hoppe.de/leon.hoppe/hopframe:latest
+ only:
+ - tags
+ dependencies:
+ - publish
diff --git a/.idea/.idea.HopFrame/.idea/workspace.xml b/.idea/.idea.HopFrame/.idea/workspace.xml
index a12d024..0de882e 100644
--- a/.idea/.idea.HopFrame/.idea/workspace.xml
+++ b/.idea/.idea.HopFrame/.idea/workspace.xml
@@ -12,11 +12,10 @@
-
-
-
-
-
+
+
+
+
@@ -99,7 +98,7 @@
-
+ {}{
@@ -129,14 +128,14 @@
"RunOnceActivity.git.unshallow": "true",
"b5f11219-dfc4-47a1-b02c-90ab603034fb.executor": "Debug",
"dcdf1689-dc07-47e4-8824-2e60a4fbf301.executor": "Debug",
- "git-widget-placeholder": "dev",
+ "git-widget-placeholder": "!31 on feature/docs",
"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.environmentSetup",
+ "settings.editor.selected.configurable": "preferences.pluginManager",
"vue.rearranger.settings.migration": "true"
}
}
@@ -244,7 +243,11 @@
-
+
+
+
+
+
@@ -566,7 +569,15 @@
1738774569657
-
+
+
+ 1738775556256
+
+
+
+ 1738775556256
+
+
@@ -617,7 +628,6 @@
-
@@ -642,6 +652,7 @@
-
+
+
\ No newline at end of file
diff --git a/docs/.idea/.gitignore b/docs/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/docs/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/docs/.idea/docs.iml b/docs/.idea/docs.iml
new file mode 100644
index 0000000..6102194
--- /dev/null
+++ b/docs/.idea/docs.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/.idea/modules.xml b/docs/.idea/modules.xml
new file mode 100644
index 0000000..6049cfe
--- /dev/null
+++ b/docs/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/.idea/vcs.xml b/docs/.idea/vcs.xml
new file mode 100644
index 0000000..6c0b863
--- /dev/null
+++ b/docs/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/Dockerfile b/docs/Dockerfile
new file mode 100644
index 0000000..ee0a50d
--- /dev/null
+++ b/docs/Dockerfile
@@ -0,0 +1,19 @@
+FROM jetbrains/writerside-builder:243.22562 AS build
+
+ARG INSTANCE=Writerside/hopframe
+
+RUN mkdir /opt/sources
+
+WORKDIR /opt/sources
+
+ADD Writerside ./Writerside
+
+RUN export DISPLAY=:99 && Xvfb :99 & /opt/builder/bin/idea.sh helpbuilderinspect --source-dir /opt/sources --product $INSTANCE --runner other --output-dir /opt/wrs-output/
+
+WORKDIR /opt/wrs-output
+
+RUN unzip -O UTF-8 webHelpHOPFRAME2-all.zip -d /opt/wrs-output/unzipped-artifact
+
+FROM httpd:2.4 AS http-server
+
+COPY --from=build /opt/wrs-output/unzipped-artifact/ /usr/local/apache2/htdocs/
\ No newline at end of file
diff --git a/docs/Writerside/c.list b/docs/Writerside/c.list
new file mode 100644
index 0000000..c4c77a2
--- /dev/null
+++ b/docs/Writerside/c.list
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/Writerside/cfg/buildprofiles.xml b/docs/Writerside/cfg/buildprofiles.xml
new file mode 100644
index 0000000..ce856dd
--- /dev/null
+++ b/docs/Writerside/cfg/buildprofiles.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ false
+
+
+
+
diff --git a/docs/Writerside/cfg/glossary.xml b/docs/Writerside/cfg/glossary.xml
new file mode 100644
index 0000000..22bec6b
--- /dev/null
+++ b/docs/Writerside/cfg/glossary.xml
@@ -0,0 +1,7 @@
+
+
+
+
+ Description of what "foo" is.
+
+
\ No newline at end of file
diff --git a/docs/Writerside/hopframe.tree b/docs/Writerside/hopframe.tree
new file mode 100644
index 0000000..3afb72e
--- /dev/null
+++ b/docs/Writerside/hopframe.tree
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/Writerside/images/dashboard.png b/docs/Writerside/images/dashboard.png
new file mode 100644
index 0000000..ec0e556
Binary files /dev/null and b/docs/Writerside/images/dashboard.png differ
diff --git a/docs/Writerside/images/editor.png b/docs/Writerside/images/editor.png
new file mode 100644
index 0000000..e01a622
Binary files /dev/null and b/docs/Writerside/images/editor.png differ
diff --git a/docs/Writerside/images/table.png b/docs/Writerside/images/table.png
new file mode 100644
index 0000000..7d83179
Binary files /dev/null and b/docs/Writerside/images/table.png differ
diff --git a/docs/Writerside/redirection-rules.xml b/docs/Writerside/redirection-rules.xml
new file mode 100644
index 0000000..c7e960a
--- /dev/null
+++ b/docs/Writerside/redirection-rules.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/Writerside/topics/Authentication.md b/docs/Writerside/topics/Authentication.md
new file mode 100644
index 0000000..a54fc51
--- /dev/null
+++ b/docs/Writerside/topics/Authentication.md
@@ -0,0 +1,35 @@
+# Authentication
+
+The HopFrame is a powerful tool to manage your backend data. So you probably don't want anybody to access the pages.
+Luckily the HopFrame supports policy based authentication. By default, everybody is allowed to access the whole
+HopFrame, but you can restrict that by registering a scoped service implementing the `IHopFrameAuthHandler`.
+If no service is registered, the default handler gets registered, but it lets any traffic pass.
+
+## Example
+
+Create a service that handles authentication:
+
+```C#
+public class AuthService(IAuthStore store) : IHopFrameAuthHandler {
+
+ public async Task IsAuthenticatedAsync(string? policy) {
+ var currentUser = await store.GetCurrentUser();
+ return await store.IsPermitted(currentUser, policy);
+ }
+
+ public async Task GetCurrentUserDisplayNameAsync() {
+ var currentUser = await store.GetCurrentUser();
+ return currentUser.FullName;
+ }
+
+}
+```
+
+Now register it in the DI container:
+
+```C#
+builder.Services.AddScoped();
+```
+
+**Hint:** You can display the current users name in the ui by enabling the feature in
+the [HopFrameConfig](HopFrameConfig.md#displayuserinfo).
diff --git a/docs/Writerside/topics/Callbacks.md b/docs/Writerside/topics/Callbacks.md
new file mode 100644
index 0000000..42e0a70
--- /dev/null
+++ b/docs/Writerside/topics/Callbacks.md
@@ -0,0 +1,31 @@
+# Callbacks
+
+Callbacks are a way of executing actions on curtain events in the web ui.
+
+## Registering a callback handler
+
+You can register a callback handler using the method provided in the [](TableConfig.md):
+
+```c#
+table.AddCallbackHandler(CallbackType.DeleteEntry, (user, services) => {
+ var logger = services.GetRequiredService>();
+ logger.LogInformation("User {user} deleted!", user.Username);
+});
+```
+
+The callback handler takes the entity that's modified and a `IServiceProvider` as arguments
+and can either be synchronous or asynchronous.
+
+## Callback types
+
+```C#
+public enum CallbackType {
+ CreateEntry = 0,
+ UpdateEntry = 1,
+ DeleteEntry = 2
+}
+```
+
+- `CallbackType.CreateEntry`: The handler gets executed, when an entity is created.
+- `CallbackType.UpdateEntry`: The handler gets executed, when an entity is updated.
+- `CallbackType.DeleteEntry`: The handler gets executed, when an entity is deleted.
diff --git a/docs/Writerside/topics/Custom-Views.md b/docs/Writerside/topics/Custom-Views.md
new file mode 100644
index 0000000..661db21
--- /dev/null
+++ b/docs/Writerside/topics/Custom-Views.md
@@ -0,0 +1,101 @@
+# Custom Views
+
+You can also add your own pages to the HopFrame UI by defining the routes as custom views.
+You can do that by using the following extension methods for the [](HopFrameConfig.md):
+
+## Configuration methods
+
+### AddCustomView (With configurator delegate)
+
+Creates an entry to the side menu and dashboard with a custom URL.
+
+```c#
+HopFrameConfigurator AddCustomView(string name, string url, Action configuratorDelegate)
+```
+
+- **Parameters:**
+ - `configurator`: The configurator for the HopFrame config that is being created.
+ - `name`: The name of the navigation entry.
+ - `url`: The target URL of the navigation entry.
+ - `configuratorDelegate`: The delegate for configuring the view.
+
+- **Returns:** `HopFrameConfigurator`
+
+### AddCustomView (Without configurator delegate)
+
+Creates an entry to the side menu and dashboard with a custom URL.
+
+```c#
+CustomViewConfigurator AddCustomView(string name, string url)
+```
+
+- **Parameters:**
+ - `configurator`: The configurator for the HopFrame config that is being created.
+ - `name`: The name of the navigation entry.
+ - `url`: The target URL of the navigation entry.
+
+- **Returns:** `CustomViewConfigurator`
+
+## CustomViewConfigurator
+
+### SetDescription
+
+Sets the description displayed in the dashboard.
+
+```c#
+CustomViewConfigurator SetDescription(string description)
+```
+
+- **Parameters:**
+ - `description`: The desired description.
+
+- **Returns:** `CustomViewConfigurator`
+
+### SetPolicy
+
+Sets the policy needed in order to access the view.
+
+```c#
+CustomViewConfigurator SetPolicy(string policy)
+```
+
+- **Parameters:**
+ - `policy`: The desired policy.
+
+- **Returns:** `CustomViewConfigurator`
+
+### SetIcon
+
+Sets the icon displayed in the sidebar.
+
+```c#
+CustomViewConfigurator SetIcon(string icon)
+```
+
+- **Parameters:**
+ - `icon`: The desired [fluent-icon](https://www.fluentui-blazor.net/Icon#explorer).
+
+- **Returns:** `CustomViewConfigurator`
+
+### SetLinkMatch
+
+Sets the rule for the sidebar to determine if the link is active.
+
+```c#
+CustomViewConfigurator SetLinkMatch(NavLinkMatch match)
+```
+
+- **Parameters:**
+ - `match`: The desired match rule.
+
+- **Returns:** `CustomViewConfigurator`
+
+## Example
+
+```C#
+builder.Services.AddHopFrame(options => {
+ options.AddCustomView("Counter", "/counter")
+ .SetDescription("A custom view")
+ .SetPolicy("counter.view");
+});
+```
diff --git a/docs/Writerside/topics/Dashboard.md b/docs/Writerside/topics/Dashboard.md
new file mode 100644
index 0000000..09b8d49
--- /dev/null
+++ b/docs/Writerside/topics/Dashboard.md
@@ -0,0 +1,9 @@
+# Dashboard
+
+The dashboard gives you an overview of all pages accessible through the HopFrame interface.
+
+An example configuration could lead to something like this:
+
+
+
+You could use the sidebar or the `Open` button to open any page that you have access to.
diff --git a/docs/Writerside/topics/DbContextConfig.md b/docs/Writerside/topics/DbContextConfig.md
new file mode 100644
index 0000000..2c44453
--- /dev/null
+++ b/docs/Writerside/topics/DbContextConfig.md
@@ -0,0 +1,38 @@
+# DbContextConfig
+
+This config contains all configurations for the given DbContext type.
+
+## Configuration methods
+
+### Table (With configurator)
+
+Configures the table of the `DbContext` using the provided configurator.
+
+```c#
+DbContextConfigurator Table(Action> configurator) where TModel : class
+```
+
+- **Type Parameters:**
+ - `TModel`: The model of the table for identifying the correct one.
+
+- **Parameters:**
+ - `configurator`: Used for configuring the table.
+
+- **Returns:** `DbContextConfigurator`
+
+- **See Also:** [](TableConfig.md)
+
+### Table (Without configurator)
+
+Configures the table of the `DbContext`.
+
+```c#
+TableConfigurator Table() where TModel : class
+```
+
+- **Type Parameters:**
+ - `TModel`: The model of the table for identifying the correct one.
+
+- **Returns:** `TableConfigurator`
+
+- **See Also:** [](TableConfig.md)
diff --git a/docs/Writerside/topics/Events.md b/docs/Writerside/topics/Events.md
new file mode 100644
index 0000000..d8c6e20
--- /dev/null
+++ b/docs/Writerside/topics/Events.md
@@ -0,0 +1,214 @@
+# Events
+
+## Base event
+
+Every event inherits from the base event, so these properties and methods are always available
+
+```C#
+public abstract class HopFrameEventArgs {
+ public TSender Sender { get; }
+ public bool IsCanceled { get; }
+ public TableConfig Table { get; }
+
+ public void SetCancelled(bool canceled);
+}
+```
+
+**Properties:**
+
+- **Sender**: The sender of the event.
+ - **Type:** `TSender`
+- **IsCanceled**: Indicates whether the event is canceled.
+ - **Type:** `bool`
+- **Table**: The table configuration related to the event.
+ - **Type:** `TableConfig`
+
+**Methods:**
+
+- **SetCancelled**
+ - **Parameters:**
+ - `canceled`: A boolean value to set the cancellation state.
+ - **Returns:** `void`
+
+## DeleteEntryEvent
+
+Event arguments for a delete entry event.
+
+```C#
+public sealed class DeleteEntryEvent : HopFrameEventArgs {
+ public object Entity { get; }
+}
+```
+
+**Properties:**
+
+- **Entity**: The entity being deleted.
+ - **Type:** `object`
+
+## CreateEntryEvent
+
+Event arguments for a create entry event.
+
+```C#
+public sealed class CreateEntryEvent : HopFrameEventArgs {
+
+}
+```
+
+## UpdateEntryEvent
+
+Event arguments for an update entry event.
+
+```C#
+public sealed class UpdateEntryEvent : HopFrameEventArgs {
+ public object Entity { get; }
+}
+```
+
+**Properties:**
+
+- **Entity**: The entity being updated.
+ - **Type:** `object`
+
+## SelectEntryEvent
+
+Event arguments for a select entry event.
+
+```C#
+public sealed class SelectEntryEvent : HopFrameEventArgs {
+ public object Entity { get; }
+ public bool Selected { get; set; }
+}
+```
+
+**Properties:**
+
+- **Entity**: The entity being selected.
+ - **Type:** `object`
+- **Selected**: Indicates whether the entity is selected.
+ - **Type:** `bool`
+
+## PageChangeEvent
+
+Event arguments for a page change event.
+
+```C#
+public sealed class PageChangeEvent : HopFrameEventArgs {
+ public int CurrentPage { get; }
+ public int TotalPages { get; }
+ public int NewPage { get; set; }
+}
+```
+
+**Properties:**
+
+- **CurrentPage**: The current page number.
+ - **Type:** `int`
+- **TotalPages**: The total number of pages.
+ - **Type:** `int`
+- **NewPage**: The new page number to navigate to.
+ - **Type:** `int`
+
+## ReloadEvent
+
+Event arguments for a reload event.
+
+```C#
+public sealed class ReloadEvent : HopFrameEventArgs {
+
+}
+```
+
+## SearchEvent
+
+Event arguments for a search event.
+
+```C#
+public sealed class SearchEvent : HopFrameEventArgs {
+ public string SearchTerm { get; set; }
+ public int CurrentPage { get; }
+
+ public void SetSearchResult(IEnumerable result, int totalPages);
+}
+```
+
+**Properties:**
+
+- **SearchTerm**: The search term used.
+ - **Type:** `string`
+- **CurrentPage**: The current page number.
+ - **Type:** `int`
+- **SearchResult**: The search results.
+ - **Type:** `IEnumerable