HomeEntrypoint.vala 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. using Statum;
  2. using Invercargill;
  3. using Invercargill.DataStructures;
  4. namespace Example {
  5. // Typed slot models — GObject properties mapped to/from Properties via
  6. // GObjectMapping. ActionDto fields round-trip as nested JSON.
  7. public class CounterPrivate : Object {
  8. public int delta { get; set; }
  9. }
  10. public class CounterPublic : Object {
  11. public int value { get; set; }
  12. public Model.ActionDto bump { get; set; }
  13. }
  14. public class PagePublic : Object {
  15. public Model.ActionDto login { get; set; }
  16. }
  17. public class AuthPublic : Object {
  18. public string name { get; set; }
  19. public string role { get; set; }
  20. public Model.ActionDto logout { get; set; }
  21. public Model.ActionDto update_announcement { get; set; }
  22. }
  23. public class AuthPrivate : Object {
  24. public bool is_admin { get; set; }
  25. }
  26. /** Global broadcast model — a simple announcement string. */
  27. public class AnnouncementPublic : Object {
  28. public string text { get; set; }
  29. }
  30. /** Derived model — a short preview of the announcement, produced by the topic modifier. */
  31. public class AnnouncementPreview : Object {
  32. public string summary { get; set; }
  33. public int chars { get; set; }
  34. }
  35. /** Topic: loads the current announcement from the global slot when triggered. */
  36. public class AnnouncementTopic : Statum.Topic<AnnouncementPublic> {
  37. private StateService state_service = Inversion.inject<StateService>();
  38. public override async AnnouncementPublic load(string topic_key) throws GLib.Error {
  39. var slot = state_service.get_slot(StateService.GLOBAL_KEY_PREFIX + "announcement");
  40. var model = new AnnouncementPublic();
  41. if (slot != null && ((!)slot).current_state != null) {
  42. try {
  43. model = GObjectMapping.from_properties_typed<AnnouncementPublic>(
  44. typeof(AnnouncementPublic), ((!)slot).current_state.public_data);
  45. } catch {}
  46. }
  47. return model;
  48. }
  49. }
  50. /** Modifier: derives an AnnouncementPreview from the AnnouncementPublic payload. */
  51. public class AnnouncementPreviewModifier : Statum.StateModifier {
  52. public override Type state_type { get { return typeof(AnnouncementPreview); } }
  53. public override GLib.Object? derive(GLib.Object payload, GLib.Object? current, HeldStates held) {
  54. var announcement = (AnnouncementPublic) payload;
  55. var preview = new AnnouncementPreview();
  56. preview.chars = announcement.text.length;
  57. preview.summary = announcement.text.length > 40 ? announcement.text.substring(0, 40) + "…" : announcement.text;
  58. return preview;
  59. }
  60. }
  61. /**
  62. * Entrypoint for the home page: hydrates counter + page slots with typed
  63. * models, embedding action references as fields.
  64. */
  65. public class HomeEntrypoint : StatumEntrypoint {
  66. public override async DirectiveBuilder handle() throws GLib.Error {
  67. var bump_private = new CounterPrivate();
  68. bump_private.delta = 1;
  69. var bump_ref = action_registry.author_private<BumpCounterAction, CounterPrivate>(bump_private);
  70. var counter = new CounterPublic();
  71. counter.value = 0;
  72. counter.bump = bump_ref;
  73. var page = new PagePublic();
  74. page.login = action_registry.author<LoginAction>();
  75. // Create a derived "preview" slot and register a topic watcher so it
  76. // updates live when the announcement changes.
  77. var preview_model = new AnnouncementPreview();
  78. preview_model.summary = "";
  79. preview_model.chars = 0;
  80. var preview_slot = state_service.new_slot(Scope.PAGE, new State() {
  81. type_name = "preview",
  82. public_data = GObjectMapping.to_properties(preview_model),
  83. private_data = new PropertyDictionary()
  84. });
  85. topic_registry.watch("announcement:latest", preview_slot.id,
  86. typeof(AnnouncementPreview).name(), request.held);
  87. return directives()
  88. .set_global("announcement")
  89. .subscribe_global("announcement")
  90. .set_typed<CounterPublic>("counter", Scope.PAGE, counter)
  91. .set_typed<PagePublic>("page", Scope.PAGE, page)
  92. .set(preview_slot)
  93. .subscribe(preview_slot.id);
  94. }
  95. }
  96. /**
  97. * Entrypoint for the guarded dashboard page.
  98. */
  99. public class DashboardEntrypoint : StatumEntrypoint {
  100. public override async DirectiveBuilder handle() throws GLib.Error {
  101. return directives()
  102. .set_global("announcement")
  103. .notify("info", "Welcome to your dashboard");
  104. }
  105. }
  106. }