eventsimple 2.0.3 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +1 -1
- data/app/controllers/eventsimple/entities_controller.rb +22 -2
- data/app/views/eventsimple/entities/show.html.erb +41 -4
- data/app/views/eventsimple/shared/_header.html.erb +7 -5
- data/app/views/eventsimple/shared/_style.html.erb +3 -6
- data/app/views/layouts/eventsimple/application.html.erb +7 -6
- data/lib/eventsimple/entity.rb +1 -1
- data/lib/eventsimple/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ae9bbebb1de86056d5f59ce55f4b689acf234bc0edb22250a929bc50beab5e51
|
|
4
|
+
data.tar.gz: a65c7510e97468125924def2c029dfb675553e86380b243c08dcbc7666b082af
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dfda660ee2398b239ace585e95047b2fec9dcd5d8056258513b76061707ec730a5d5fd6ba2d40ffb22406d6aa3d8688401579a4c2d309d61e1afc056b001439b
|
|
7
|
+
data.tar.gz: d23dbffcbc0229dc04f3b57b1755dfb107c1d32e7bbe684592cc0d737dd7c80a7970cb5fc157a5a3d57dca8d08466251e965dd02a30be28d1f1dd3b2d5536dfe
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
+
## 2.0.4 - 2025-12-16
|
|
10
|
+
### Added
|
|
11
|
+
- Fixes an issue where entities with deleted events were not being rendered correctly.
|
|
12
|
+
- Display a diff showing actual vs expected values for mismatched attributes when the current entity state does not match the reprojection from events.
|
|
13
|
+
|
|
9
14
|
## 2.0.3 - 2025-12-12
|
|
10
15
|
### Changed
|
|
11
16
|
- Fix false positive deprecation warnings when using Message as an optional attribute type.
|
data/Gemfile.lock
CHANGED
|
@@ -24,6 +24,10 @@ module Eventsimple
|
|
|
24
24
|
previous_index = @entity_event_history.find_index { |e| e.id == @selected_event.id } + 1
|
|
25
25
|
@previous_event = @entity_event_history[previous_index]
|
|
26
26
|
|
|
27
|
+
# Check projection mismatch BEFORE calling changes (which modifies @entity via reproject)
|
|
28
|
+
@projection_mismatch = !@entity.projection_matches_events?
|
|
29
|
+
@projection_diff = projection_diff if @projection_mismatch
|
|
30
|
+
|
|
27
31
|
@entity_changes = changes
|
|
28
32
|
rescue StandardError => e
|
|
29
33
|
@error_message = e.message
|
|
@@ -44,7 +48,7 @@ module Eventsimple
|
|
|
44
48
|
end
|
|
45
49
|
|
|
46
50
|
def current_attributes
|
|
47
|
-
@current_attributes ||= @entity.reproject(at: @selected_event.created_at).attributes.except(
|
|
51
|
+
@current_attributes ||= @entity.reproject(skip_deleted: true, at: @selected_event.created_at).attributes.except(
|
|
48
52
|
'lock_version',
|
|
49
53
|
)
|
|
50
54
|
end
|
|
@@ -52,12 +56,28 @@ module Eventsimple
|
|
|
52
56
|
def previous_attributes
|
|
53
57
|
@previous_attributes ||=
|
|
54
58
|
if @previous_event
|
|
55
|
-
@entity.reproject(at: @previous_event.created_at).attributes.except(
|
|
59
|
+
@entity.reproject(skip_deleted: true, at: @previous_event.created_at).attributes.except(
|
|
56
60
|
'lock_version',
|
|
57
61
|
)
|
|
58
62
|
else
|
|
59
63
|
@model_class.column_defaults
|
|
60
64
|
end
|
|
61
65
|
end
|
|
66
|
+
|
|
67
|
+
def projection_diff
|
|
68
|
+
actual_attributes = @model_class.unscoped.find(@entity.id).attributes.except('lock_version')
|
|
69
|
+
reprojected_attributes = @model_class.unscoped.find(@entity.id).reproject.attributes.except('lock_version')
|
|
70
|
+
|
|
71
|
+
actual_attributes.filter_map do |attr_name, actual_value|
|
|
72
|
+
reprojected_value = reprojected_attributes[attr_name]
|
|
73
|
+
next if actual_value == reprojected_value
|
|
74
|
+
|
|
75
|
+
{
|
|
76
|
+
attribute: attr_name,
|
|
77
|
+
actual: actual_value,
|
|
78
|
+
expected: reprojected_value,
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
end
|
|
62
82
|
end
|
|
63
83
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
<div class="row align-items-start">
|
|
1
|
+
<div class="row g-4 align-items-start">
|
|
2
2
|
<!-- Pane: Entity Details Start -->
|
|
3
|
-
<div class="col
|
|
3
|
+
<div class="col-12 col-sm-8">
|
|
4
4
|
<h2><%= @model_name%>: <%= @aggregate_id %></h2>
|
|
5
5
|
<hr/>
|
|
6
6
|
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<% @entity_changes.each do |property| %>
|
|
33
33
|
<tr class="<%= property[:is_changed] ? 'table-info' : '' %>">
|
|
34
34
|
<th scope="row"><%= property[:label] %></th>
|
|
35
|
-
<td><code class="entity-property"><%= property[:historical_value].nil? ? '-' : property[:historical_value] %></code></
|
|
35
|
+
<td><code class="entity-property"><%= property[:historical_value].nil? ? '-' : property[:historical_value] %></code></td>
|
|
36
36
|
<td><code class="entity-property"><%= property[:current_value].nil? ? '-' : property[:current_value] %></code></td>
|
|
37
37
|
</tr>
|
|
38
38
|
<% end %>
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
<!-- Pane: Entity Details End -->
|
|
88
88
|
|
|
89
89
|
<!-- Pane: Time Travel Start -->
|
|
90
|
-
<div class="col
|
|
90
|
+
<div class="col-12 col-sm-4">
|
|
91
91
|
<h3>Time Travel</h3>
|
|
92
92
|
<ul class="list-group">
|
|
93
93
|
<% @entity_event_history.each_with_index do | event, index | %>
|
|
@@ -104,6 +104,43 @@
|
|
|
104
104
|
</li>
|
|
105
105
|
<% end %>
|
|
106
106
|
</ul>
|
|
107
|
+
|
|
108
|
+
<% if @projection_mismatch %>
|
|
109
|
+
<!-- Projection Mismatch Warning Start -->
|
|
110
|
+
<div class="mt-4">
|
|
111
|
+
<div class="alert alert-warning" role="alert">
|
|
112
|
+
<h6 class="alert-heading d-flex align-items-center mb-2">
|
|
113
|
+
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
|
114
|
+
Projection Mismatch
|
|
115
|
+
</h6>
|
|
116
|
+
<p class="mb-2 small">
|
|
117
|
+
The current entity state does not match the reprojection from events.
|
|
118
|
+
This may indicate that the entity was modified outside of the event system.
|
|
119
|
+
</p>
|
|
120
|
+
<hr class="my-2">
|
|
121
|
+
<p class="mb-1 small fw-bold">Differences:</p>
|
|
122
|
+
<table class="table table-sm table-borderless mb-0 small">
|
|
123
|
+
<thead>
|
|
124
|
+
<tr>
|
|
125
|
+
<th>Attribute</th>
|
|
126
|
+
<th>Actual</th>
|
|
127
|
+
<th>Expected</th>
|
|
128
|
+
</tr>
|
|
129
|
+
</thead>
|
|
130
|
+
<tbody>
|
|
131
|
+
<% @projection_diff.each do |diff| %>
|
|
132
|
+
<tr>
|
|
133
|
+
<td><code><%= diff[:attribute] %></code></td>
|
|
134
|
+
<td class="text-danger"><%= diff[:actual].nil? ? '-' : diff[:actual] %></td>
|
|
135
|
+
<td class="text-success"><%= diff[:expected].nil? ? '-' : diff[:expected] %></td>
|
|
136
|
+
</tr>
|
|
137
|
+
<% end %>
|
|
138
|
+
</tbody>
|
|
139
|
+
</table>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
<!-- Projection Mismatch Warning End -->
|
|
143
|
+
<% end %>
|
|
107
144
|
</div>
|
|
108
145
|
<!-- Pane: Time Travel End -->
|
|
109
146
|
</div>
|
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
<header class="container mb-4">
|
|
3
3
|
<% if @model_name %>
|
|
4
4
|
<%= form_with scope: :filters, url: model_path(@model_name), method: :get, id: 'model-filter' do |f| %>
|
|
5
|
-
<div class="row">
|
|
6
|
-
<
|
|
7
|
-
|
|
5
|
+
<div class="row g-2 align-items-center">
|
|
6
|
+
<div class="col-auto">
|
|
7
|
+
<label for="filters_keys_keys" class="col-form-label">Filter attribute</label>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="col-auto">
|
|
8
10
|
<%= select :filters_keys, :keys, @filters.keys, { selected: @filters.compact.keys&.first }, { class:"form-select", onchange: "document.getElementById('model-filter-value').name=`filters[${this.value}]`" } %>
|
|
9
11
|
</div>
|
|
10
|
-
<div class="
|
|
12
|
+
<div class="col-auto flex-grow-1" style="max-width: 300px;">
|
|
11
13
|
<%= f.search_field @filters.compact.keys&.first || @filters.keys.first, id: 'model-filter-value', value: @filters.compact.values&.first, class:"form-control", placeholder: "Filter value" %>
|
|
12
14
|
</div>
|
|
13
|
-
<div class="
|
|
15
|
+
<div class="col-auto">
|
|
14
16
|
<%= f.submit 'Search', class: 'btn btn-primary' %>
|
|
15
17
|
</div>
|
|
16
18
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<style>
|
|
2
|
-
|
|
2
|
+
/* Structure */
|
|
3
3
|
body {
|
|
4
4
|
min-height: 100vh;
|
|
5
5
|
min-height: -webkit-fill-available;
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
overflow-y: auto;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
/* Sidebar Nav */
|
|
34
34
|
|
|
35
35
|
.bi {
|
|
36
36
|
vertical-align: -.125em;
|
|
@@ -90,10 +90,7 @@
|
|
|
90
90
|
overflow-y: auto;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
.lh-tight { line-height: 1.25; }
|
|
95
|
-
|
|
96
|
-
// Styles
|
|
93
|
+
/* Styles */
|
|
97
94
|
|
|
98
95
|
code {
|
|
99
96
|
color: deeppink;
|
|
@@ -8,20 +8,21 @@
|
|
|
8
8
|
<%= csrf_meta_tags %>
|
|
9
9
|
<%= csp_meta_tag %>
|
|
10
10
|
|
|
11
|
-
<%= stylesheet_link_tag "https://cdn.jsdelivr.net/npm/bootstrap@5.
|
|
11
|
+
<%= stylesheet_link_tag "https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css",
|
|
12
12
|
media: "all",
|
|
13
|
-
integrity: '
|
|
13
|
+
integrity: 'sha256-2FMn2Zx6PuH5tdBQDRNwrOo60ts5wWPC9R8jK67b3t4=',
|
|
14
14
|
crossorigin: 'anonymous'
|
|
15
15
|
%>
|
|
16
|
-
<%= stylesheet_link_tag "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.
|
|
16
|
+
<%= stylesheet_link_tag "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css",
|
|
17
17
|
media: "all",
|
|
18
18
|
crossorigin: 'anonymous'
|
|
19
19
|
%>
|
|
20
|
-
<%= javascript_include_tag "https://cdn.jsdelivr.net/npm/bootstrap@5.
|
|
21
|
-
integrity: "
|
|
20
|
+
<%= javascript_include_tag "https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.min.js",
|
|
21
|
+
integrity: "sha256-ew8UiV1pJH/YjpOEBInP1HxVvT/SfrCmwSoUzF9JIgc=",
|
|
22
22
|
crossorigin: "anonymous"
|
|
23
23
|
%>
|
|
24
|
-
<%= javascript_include_tag "https://cdn.jsdelivr.net/npm/jquery@3.
|
|
24
|
+
<%= javascript_include_tag "https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js",
|
|
25
|
+
integrity: "sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=",
|
|
25
26
|
crossorigin: "anonymous"
|
|
26
27
|
%>
|
|
27
28
|
|
data/lib/eventsimple/entity.rb
CHANGED
data/lib/eventsimple/version.rb
CHANGED