Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.x] Defer Prop #24

Draft
wants to merge 46 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
1dc8b6b
added header constants
adrum Dec 14, 2024
3a33449
refactor resolve props
adrum Dec 14, 2024
c456148
added always prop
adrum Dec 14, 2024
7d0d3bf
fix some compile time warnings
adrum Dec 14, 2024
f9ad84b
added always prop test
adrum Dec 15, 2024
77473d6
added async task wrapper
adrum Dec 15, 2024
f64ca76
.net 8
adrum Dec 15, 2024
51fe030
restore header keys
adrum Dec 21, 2024
62a0864
added .net 9
adrum Dec 21, 2024
97b7c67
Merge branch 'fix/warnings' into feature/optional-prop
adrum Dec 21, 2024
2ab0765
added ignore first load
adrum Dec 21, 2024
bf08e03
add optional prop
adrum Dec 21, 2024
3e30450
added optional test
adrum Dec 21, 2024
1d74592
added merge prop
adrum Dec 21, 2024
05bf42d
added unit test for merge prop
adrum Dec 21, 2024
3cacdaa
update version in actions
adrum Dec 21, 2024
52ad4b8
update version in actions
adrum Dec 21, 2024
08c35f1
Merge branch 'feature/optional-prop' into feature/defer-prop
adrum Dec 21, 2024
1e18696
dont resolve Lazy and Optional Props until they are invoked
adrum Dec 21, 2024
9696eb1
Merge branch 'feature/optional-prop' into feature/defer-prop
adrum Dec 21, 2024
7860eea
dont include Merge props in the json
adrum Dec 21, 2024
fdd092b
Merge branch 'feature/merge-prop' into feature/defer-prop
adrum Dec 21, 2024
b72751d
add defer prop
adrum Dec 21, 2024
f362bda
fix result test of deferred props
adrum Dec 21, 2024
21a8f65
fix formatting
adrum Dec 21, 2024
298eaa0
Merge branch 'main' into fork/adrum/feature/defer-prop
kapi2289 Jan 6, 2025
bd5b6c1
Merge branch 'main' into fork/adrum/feature/optional-prop
kapi2289 Jan 6, 2025
d71be3b
Merge branch 'main' into fork/adrum/feature/merge-prop
kapi2289 Jan 6, 2025
66312a3
Merge branch 'main' into fork/adrum/feature/optional-prop
kapi2289 Jan 6, 2025
cf2c45e
Minor fixes and changes
kapi2289 Jan 6, 2025
42396a7
Add missing Inertia static methods
kapi2289 Jan 6, 2025
6b383a3
Merge branch 'main' into feature/optional-prop
adrum Jan 11, 2025
ea4592e
make optional prop invokable
adrum Jan 11, 2025
f62c188
Merge branch 'main' into feature/merge-prop
adrum Jan 11, 2025
1e949b0
fix merge prop tests
adrum Jan 11, 2025
ad8c476
fix test sdks?
adrum Jan 11, 2025
6333daa
fix test sdks?
adrum Jan 11, 2025
6394500
Merge branch 'feature/merge-prop' into feature/defer-prop
adrum Jan 11, 2025
575f96f
fix defer after merge
adrum Jan 11, 2025
e2ef3c3
Merge branch 'feature/optional-prop' into feature/defer-prop
adrum Jan 11, 2025
07ea498
fix tests and namespace
adrum Jan 11, 2025
a6a9fe0
Merge branch 'v1' into feature/optional-prop
adrum Feb 8, 2025
2ae0bff
revert formatting
adrum Feb 8, 2025
0e9353c
one more formatting fix
adrum Feb 8, 2025
eb076cc
Merge branch 'feature/optional-prop' into feature/merge-prop
adrum Feb 8, 2025
2dc5e86
Merge branch 'feature/merge-prop' into feature/defer-prop
adrum Feb 8, 2025
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
14 changes: 14 additions & 0 deletions InertiaCore/Inertia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,21 @@ public static class Inertia

public static AlwaysProp Always(Func<Task<object?>> callback) => _factory.Always(callback);

public static DeferProp Defer(Func<object?> callback, string group = "default") => _factory.Defer(callback, group);

public static DeferProp Defer(Func<Task<object?>> callback, string group = "default") => _factory.Defer(callback, group);

public static LazyProp Lazy(Func<object?> callback) => _factory.Lazy(callback);

public static LazyProp Lazy(Func<Task<object?>> callback) => _factory.Lazy(callback);

public static OptionalProp Optional(Func<object?> callback) => _factory.Optional(callback);

public static OptionalProp Optional(Func<Task<object?>> callback) => _factory.Optional(callback);

public static MergeProp Merge(object? value) => _factory.Merge(value);

public static MergeProp Merge(Func<object?> callback) => _factory.Merge(callback);

public static MergeProp Merge(Func<Task<object?>> callback) => _factory.Merge(callback);
}
8 changes: 8 additions & 0 deletions InertiaCore/Models/Page.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Text.Json.Serialization;

namespace InertiaCore.Models;

internal class Page
Expand All @@ -6,4 +8,10 @@ internal class Page
public string Component { get; set; } = default!;
public string? Version { get; set; }
public string Url { get; set; } = default!;

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public List<string>? MergeProps { get; set; }

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public Dictionary<string, List<string>>? DeferredProps { get; set; }
}
36 changes: 36 additions & 0 deletions InertiaCore/Props/DeferProp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using InertiaCore.Utils;

namespace InertiaCore.Props;

public class DeferProp : InvokableProp, IIgnoresFirstLoad, Mergeable
{
public bool merge { get; set; }
protected readonly string _group = "default";

public DeferProp(object? value, string group) : base(value)
{
_group = group;
}

internal DeferProp(Func<object?> value, string group) : base(value)
{
_group = group;
}

internal DeferProp(Func<Task<object?>> value, string group) : base(value)
{
_group = group;
}

public Mergeable Merge()
{
merge = true;

return this;
}

public string? Group()
{
return _group;
}
}
4 changes: 3 additions & 1 deletion InertiaCore/Props/LazyProp.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using InertiaCore.Utils;

namespace InertiaCore.Props;

public class LazyProp : InvokableProp
public class LazyProp : InvokableProp, IIgnoresFirstLoad
{
internal LazyProp(Func<object?> value) : base(value)
{
Expand Down
25 changes: 25 additions & 0 deletions InertiaCore/Props/MergeProp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using InertiaCore.Props;

namespace InertiaCore.Utils;

public class MergeProp : InvokableProp, Mergeable
{
public bool merge { get; set; } = true;

public MergeProp(object? value) : base(value)
{
merge = true;
}

internal MergeProp(Func<object?> value) : base(value)
{
merge = true;
}

internal MergeProp(Func<Task<object?>> value) : base(value)
{
merge = true;
}
}


14 changes: 14 additions & 0 deletions InertiaCore/Props/OptionalProp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using InertiaCore.Utils;

namespace InertiaCore.Props;

public class OptionalProp : InvokableProp, IIgnoresFirstLoad
{
internal OptionalProp(Func<object?> value) : base(value)
{
}

internal OptionalProp(Func<Task<object?>> value) : base(value)
{
}
}
72 changes: 71 additions & 1 deletion InertiaCore/Response.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ protected internal async Task ProcessResponse()
Props = props
};

page.MergeProps = ResolveMergeProps(props);
page.DeferredProps = ResolveDeferredProps(props);
page.Props["errors"] = GetErrors();

SetPage(page);
Expand Down Expand Up @@ -84,7 +86,7 @@ protected internal async Task ProcessResponse()

if (!isPartial)
return props
.Where(kv => kv.Value is not LazyProp)
.Where(kv => kv.Value is not IIgnoresFirstLoad)
.ToDictionary(kv => kv.Key, kv => kv.Value);

props = props.ToDictionary(kv => kv.Key, kv => kv.Value);
Expand Down Expand Up @@ -140,6 +142,74 @@ protected internal async Task ProcessResponse()
.Concat(alwaysProps).ToDictionary(kv => kv.Key, kv => kv.Value);
}

/// <summary>
/// Resolve `merge` properties that should be appended to the existing values by the front-end.
/// </summary>
private List<string>? ResolveMergeProps(Dictionary<string, object?> props)
{
// Parse the "RESET" header into a collection of keys to reset
var resetProps = new HashSet<string>(
_context!.HttpContext.Request.Headers[InertiaHeader.Reset]
.ToString()
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => s.Trim()),
StringComparer.OrdinalIgnoreCase
);

var resolvedProps = props
.Select(kv => kv.Key.ToCamelCase()) // Convert property name to camelCase
.ToList();

// Filter the props that are Mergeable and should be merged
var mergeProps = _props.Where(o => o.Value is Mergeable mergeable && mergeable.ShouldMerge()) // Check if value is Mergeable and should merge
.Where(kv => !resetProps.Contains(kv.Key)) // Exclude reset keys
.Select(kv => kv.Key.ToCamelCase()) // Convert property name to camelCase
.Where(resolvedProps.Contains) // Filter only the props that are in the resolved props
.ToList();

if (mergeProps.Count == 0)
{
return null;
}

// Return the result
return mergeProps;
}

/// <summary>
/// Resolve `deferred` properties that should be fetched after the initial page load.
/// </summary>
private Dictionary<string, List<string>>? ResolveDeferredProps(Dictionary<string, object?> props)
{

bool isPartial = _context!.IsInertiaPartialComponent(_component);
if (isPartial)
{
return null;
}

var deferredProps = _props.Where(o => o.Value is DeferProp) // Filter props that are instances of DeferProp
.Select(kv => new
{
Key = kv.Key,
Group = ((DeferProp)kv.Value!).Group()
}) // Map each prop to a new object with Key and Group

.GroupBy(x => x.Group) // Group by 'Group'
.ToDictionary(
g => g.Key!,
g => g.Select(x => x.Key.ToCamelCase()).ToList() // Extract 'Key' for each group
);

if (deferredProps.Count == 0)
{
return null;
}

// Return the result
return deferredProps;
}

/// <summary>
/// Resolve all necessary class instances in the given props.
/// </summary>
Expand Down
15 changes: 14 additions & 1 deletion InertiaCore/ResponseFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ internal interface IResponseFactory
public AlwaysProp Always(Func<Task<object?>> callback);
public LazyProp Lazy(Func<object?> callback);
public LazyProp Lazy(Func<Task<object?>> callback);
public DeferProp Defer(Func<object?> callback, string group = "default");
public DeferProp Defer(Func<Task<object?>> callback, string group = "default");
public MergeProp Merge(object? value);
public MergeProp Merge(Func<object?> callback);
public MergeProp Merge(Func<Task<object?>> callback);
public OptionalProp Optional(Func<object?> callback);
public OptionalProp Optional(Func<Task<object?>> callback);
}

internal class ResponseFactory : IResponseFactory
Expand Down Expand Up @@ -127,10 +134,16 @@ public void Share(IDictionary<string, object?> data)

context.Features.Set(sharedData);
}

public LazyProp Lazy(Func<object?> callback) => new(callback);
public LazyProp Lazy(Func<Task<object?>> callback) => new(callback);
public AlwaysProp Always(object? value) => new(value);
public AlwaysProp Always(Func<object?> callback) => new(callback);
public AlwaysProp Always(Func<Task<object?>> callback) => new(callback);
public DeferProp Defer(Func<object?> callback, string group = "default") => new(callback, group);
public DeferProp Defer(Func<Task<object?>> callback, string group = "default") => new(callback, group);
public MergeProp Merge(object? value) => new(value);
public MergeProp Merge(Func<object?> callback) => new(callback);
public MergeProp Merge(Func<Task<object?>> callback) => new(callback);
public OptionalProp Optional(Func<object?> callback) => new(callback);
public OptionalProp Optional(Func<Task<object?>> callback) => new(callback);
}
5 changes: 5 additions & 0 deletions InertiaCore/Utils/IIgnoresFirstLoad.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace InertiaCore.Utils;

public interface IIgnoresFirstLoad
{
}
2 changes: 2 additions & 0 deletions InertiaCore/Utils/InertiaHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ public static class InertiaHeader
public const string PartialOnly = "X-Inertia-Partial-Data";

public const string PartialExcept = "X-Inertia-Partial-Except";

public const string Reset = "X-Inertia-Reset";
}
15 changes: 15 additions & 0 deletions InertiaCore/Utils/Mergeable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace InertiaCore.Utils;

public interface Mergeable
{
public bool merge { get; set; }

public Mergeable Merge()
{
merge = true;

return this;
}

public bool ShouldMerge() => merge;
}
Loading