Forráskód Böngészése

feat(core): add page title support and PageContext

- Add abstract title property to PageComponent base class
- Create PageContext class to expose page metadata to templates
- Add property binding support for child components via prop-* attributes
- Register authorisation services in Spry module
- Add add_resource method for static resource registration
- Implement title property across all demo and example page components
- Make UserIdentityProvider public for external access
Billy Barrow 1 hónapja
szülő
commit
b1c88fd3fc

+ 2 - 0
demo/Pages/ComponentsActionsPage.vala

@@ -9,6 +9,8 @@ using Inversion;
  */
 public class ComponentsActionsPage : PageComponent {
     
+    public override string title { get { return "Actions - Spry"; } }
+    
     public const string ROUTE = "/components/actions";
     
     private ComponentFactory factory = inject<ComponentFactory>();

+ 2 - 0
demo/Pages/ComponentsContinuationsPage.vala

@@ -9,6 +9,8 @@ using Inversion;
  */
 public class ComponentsContinuationsPage : PageComponent {
     
+    public override string title { get { return "Continuations - Spry"; } }
+    
     public const string ROUTE = "/components/continuations";
     
     private ComponentFactory factory = inject<ComponentFactory>();

+ 2 - 0
demo/Pages/ComponentsMkconstPage.vala

@@ -9,6 +9,8 @@ using Inversion;
  */
 public class ComponentsMkconstPage : PageComponent {
     
+    public override string title { get { return "spry-mkconst Tool - Spry"; } }
+    
     public const string ROUTE = "/components/spry-mkconst";
     
     private ComponentFactory factory = inject<ComponentFactory>();

+ 2 - 0
demo/Pages/ComponentsOutletsPage.vala

@@ -9,6 +9,8 @@ using Inversion;
  */
 public class ComponentsOutletsPage : PageComponent {
     
+    public override string title { get { return "Outlets - Spry"; } }
+    
     public const string ROUTE = "/components/outlets";
     
     private ComponentFactory factory = inject<ComponentFactory>();

+ 2 - 0
demo/Pages/ComponentsOverviewPage.vala

@@ -9,6 +9,8 @@ using Inversion;
  */
 public class ComponentsOverviewPage : PageComponent {
     
+    public override string title { get { return "Components Overview - Spry"; } }
+    
     public const string ROUTE = "/components/overview";
     
     private ComponentFactory factory = inject<ComponentFactory>();

+ 2 - 0
demo/Pages/ComponentsTemplateSyntaxPage.vala

@@ -8,6 +8,8 @@ using Spry;
  */
 public class ComponentsTemplateSyntaxPage : PageComponent {
     
+    public override string title { get { return "Template Syntax - Spry"; } }
+    
     public const string ROUTE = "/components/template-syntax";
     
     public override string markup { get {

+ 2 - 0
demo/Pages/HomePage.vala

@@ -9,6 +9,8 @@ using Inversion;
  */
 public class HomePage : PageComponent {
     
+    public override string title { get { return "Spry - A Component-Based Web Framework for Vala"; } }
+    
     public const string ROUTE = "/";
     
     private ComponentFactory factory = inject<ComponentFactory>();

+ 2 - 0
demo/Pages/PageComponentsOverviewPage.vala

@@ -9,6 +9,8 @@ using Inversion;
  */
 public class PageComponentsOverviewPage : PageComponent {
     
+    public override string title { get { return "Page Components - Spry"; } }
+    
     public const string ROUTE = "/page-components/overview";
     
     private ComponentFactory factory = inject<ComponentFactory>();

+ 2 - 0
demo/Pages/PageTemplatesPage.vala

@@ -9,6 +9,8 @@ using Inversion;
  */
 public class PageTemplatesPage : PageComponent {
     
+    public override string title { get { return "Page Templates - Spry"; } }
+    
     public const string ROUTE = "/page-components/templates";
     
     private ComponentFactory factory = inject<ComponentFactory>();

+ 2 - 0
demo/Pages/StaticResourcesMkssrPage.vala

@@ -9,6 +9,8 @@ using Inversion;
  */
 public class StaticResourcesMkssrPage : PageComponent {
     
+    public override string title { get { return "spry-mkssr Tool - Spry"; } }
+    
     public const string ROUTE = "/static-resources/spry-mkssr";
     
     private ComponentFactory factory = inject<ComponentFactory>();

+ 2 - 0
demo/Pages/StaticResourcesOverviewPage.vala

@@ -9,6 +9,8 @@ using Inversion;
  */
 public class StaticResourcesOverviewPage : PageComponent {
     
+    public override string title { get { return "Static Resources - Spry"; } }
+    
     public const string ROUTE = "/static-resources/overview";
     
     private ComponentFactory factory = inject<ComponentFactory>();

+ 8 - 0
examples/TemplateExample.vala

@@ -409,6 +409,8 @@ class AdminSectionTemplate : PageTemplate {
  */
 class HomePage : PageComponent {
     
+    public override string title { get { return "Home"; } }
+    
     private AppState app_state = inject<AppState>();
     
     public const string ROUTE = "/";
@@ -450,6 +452,8 @@ class HomePage : PageComponent {
  */
 class AboutPage : PageComponent {
     
+    public override string title { get { return "About"; } }
+    
     public const string ROUTE = "/about";
     
     public override string markup { get {
@@ -486,6 +490,8 @@ Prefix "/admin/users" matches /admin/users only
  */
 class AdminDashboardPage : PageComponent {
     
+    public override string title { get { return "Admin Dashboard"; } }
+    
     private UserStore user_store = inject<UserStore>();
     
     public const string ROUTE = "/admin";
@@ -521,6 +527,8 @@ class AdminDashboardPage : PageComponent {
  */
 class AdminUsersPage : PageComponent {
     
+    public override string title { get { return "User Management"; } }
+    
     private UserStore user_store = inject<UserStore>();
     private ComponentFactory factory = inject<ComponentFactory>();
     private HttpContext http_context = inject<HttpContext>();

+ 2 - 0
examples/TodoComponent.vala

@@ -332,6 +332,8 @@ class FooterComponent : Component {
  */
 class TodoPage : PageComponent {
     
+    public override string title { get { return "Todo"; } }
+    
     private TodoStore todo_store = inject<TodoStore>();
     private ComponentFactory factory = inject<ComponentFactory>();
     

+ 10 - 0
examples/UsersExample.vala

@@ -330,6 +330,8 @@ public class MainLayoutTemplate : PageTemplate {
  */
 public class HomePage : PageComponent {
     
+    public override string title { get { return "Authentication Example"; } }
+    
     private AuthorisationContext _auth_context = inject<AuthorisationContext>();
     
     public const string ROUTE = "/";
@@ -382,6 +384,8 @@ public class HomePage : PageComponent {
  */
 public class RegisterPage : PageComponent {
     
+    public override string title { get { return "Register"; } }
+    
     private UserService _user_service = inject<UserService>();
     private HttpContext _http_context = inject<HttpContext>();
     
@@ -590,6 +594,8 @@ public class RegisterPage : PageComponent {
  */
 public class LoginPage : PageComponent {
     
+    public override string title { get { return "Login"; } }
+    
     private ComponentFactory _factory = inject<ComponentFactory>();
     
     public const string ROUTE = "/login";
@@ -648,6 +654,8 @@ public class LogoutEndpoint : Object, Endpoint {
  */
 public class DashboardPage : PageComponent {
     
+    public override string title { get { return "Dashboard"; } }
+    
     private AuthorisationContext _auth_context = inject<AuthorisationContext>();
     
     public const string ROUTE = "/dashboard";
@@ -787,6 +795,8 @@ public class DashboardPage : PageComponent {
  */
 public class UserAdminPage : PageComponent {
     
+    public override string title { get { return "User Administration"; } }
+    
     private ComponentFactory _factory = inject<ComponentFactory>();
     private UserManagementComponent _user_management;
     

+ 12 - 0
src/Authentication/AuthenticationModule.vala

@@ -6,11 +6,23 @@ namespace Spry.Authentication {
     public class AuthenticationModule : Object, Module {
 
         public void register_components (Inversion.Container container) throws Error {
+            // Sql table setup
             var sql = container.configure_with<DatabaseConfigurator>();
             sql.add_migration<Migrations.M0001_Initial>();
             sql.add_entity<UserEntity>(UserEntity.entity_mapping);
             sql.add_entity<UserPermissionEntity>(UserPermissionEntity.entity_mapping);
             sql.add_projection<UserProjection> (UserProjection.projection_mapping);
+
+            // Service setup
+            container.register_scoped<UserService>();
+            container.register_scoped<UserIdentityProvider>()
+                .as<Authorisation.IdentityProvider>();
+
+            // Component setup
+            container.register_transient<LoginComponent>();
+            container.register_transient<UserComponent>();
+            container.register_transient<UserEditComponent>();
+            container.register_transient<UserManagementComponent>();
         }
 
     }

+ 1 - 1
src/Authentication/Components/LoginComponent.vala

@@ -17,7 +17,7 @@ namespace Spry.Authentication {
           hx-disabled-elt="find input, find button"
           hx-indicator="find button"
           hx-swap="outerHTML"
-          style="display: grid; grid-template-columns: max-content auto; column-gap: 3em; row-gap: 1em;">
+          style="display: grid; grid-template-columns: max-content auto; column-gap: 3em; row-gap: 1em; align-items: center">
             <label for="username">Username</label>
             <input type="text" placeholder="Enter Username" name="username" value-expr="this.username_prefill" required>
 

+ 1 - 1
src/Authentication/UserIdentityProvider.vala

@@ -6,7 +6,7 @@ using Inversion;
 
 namespace Spry.Authentication {
 
-    class UserIdentityProvider : Object, IdentityProvider {
+    public class UserIdentityProvider : Object, IdentityProvider {
 
         private OrmSession db = inject<OrmSession>();
 

+ 10 - 1
src/Component.vala

@@ -255,6 +255,15 @@ namespace Spry {
                 component = _component_factory.create_by_name(node.get_attribute("name"));
                 _child_components[sid] = component;
             }
+
+            var attributes = node.get_attributes()
+                .where(a => a.key.has_prefix("prop-"))
+                .to_immutable_buffer();
+
+            foreach (var attribute in attributes) {
+                component.set_property(attribute.key.substring(5), attribute.value);
+            }
+
             return component;
         }
 
@@ -372,7 +381,7 @@ namespace Spry {
                     continue;
                 }
 
-                if(node.tag_name == "link" && node.get_attribute("rel") == "stylesheet") {
+                if(node.tag_name == "link") {
                     node.set_attribute("href", path);
                     continue;
                 }

+ 16 - 0
src/PageComponent.vala

@@ -9,7 +9,12 @@ namespace Spry {
 
         private Scope scope = inject<Scope>();
 
+        public abstract string title { get; }
+
         public async Astralis.HttpResult handle_request (HttpContext http_context, RouteContext route_context) throws Error {
+            // Register a context for anything that gets instansiated after this
+            scope.register_local_scoped<PageContext>(() => new PageContext(this));
+
             // Get templates as renderables in order of lowest to highest "rank"
             var renderables = scope.get_registrations(typeof(PageTemplate))
                 .select_many<Pair<Registration, TemplateRoutePrefix>>(r => r.get_metadata<TemplateRoutePrefix>().select_pairs<Registration, TemplateRoutePrefix>(p => r, p => p))
@@ -45,4 +50,15 @@ namespace Spry {
 
     }
 
+    public class PageContext : Object {
+
+        public PageComponent component { get; private set; }
+        public Type page_type { get { return component.get_type(); }}
+        public string title { get { return component.title; }}
+
+        public PageContext(PageComponent component) {
+            this.component = component;
+        }
+    }
+
 }

+ 9 - 0
src/Spry.vala

@@ -10,6 +10,10 @@ namespace Spry {
             container.register_startup<ComponentContextService>();
             container.register_scoped<ComponentFactory>();
 
+            container.register_scoped<Authorisation.AuthorisationService>();
+            container.register_scoped<Authorisation.AuthorisationPipelineComponent>()
+                .as<PipelineComponent>();
+
             container.register_startup<ContinuationProvider>()
                 .as<Endpoint>()
                 .with_metadata<EndpointRoute>(new EndpointRoute("/_spry/cnu/{token}"));
@@ -47,6 +51,11 @@ namespace Spry {
                 .with_metadata<EndpointRoute>(route);
         }
 
+        public void add_resource<T>() {
+            container.register_startup<T>()
+                .as<Spry.StaticResource>();
+        }
+
         public void add_component<T>() {
             container.register_transient<T>();
         }