ragdoll-rails 0.1.9 → 0.1.11
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/app/assets/javascripts/ragdoll/application.js +129 -0
- data/app/assets/javascripts/ragdoll/bulk_upload_status.js +454 -0
- data/app/assets/stylesheets/ragdoll/application.css +84 -0
- data/app/assets/stylesheets/ragdoll/bulk_upload_status.css +379 -0
- data/app/channels/application_cable/channel.rb +6 -0
- data/app/channels/application_cable/connection.rb +6 -0
- data/app/channels/ragdoll/bulk_upload_status_channel.rb +27 -0
- data/app/channels/ragdoll/file_processing_channel.rb +26 -0
- data/app/components/ragdoll/alert_component.html.erb +4 -0
- data/app/components/ragdoll/alert_component.rb +32 -0
- data/app/components/ragdoll/application_component.rb +6 -0
- data/app/components/ragdoll/card_component.html.erb +15 -0
- data/app/components/ragdoll/card_component.rb +21 -0
- data/app/components/ragdoll/document_list_component.html.erb +41 -0
- data/app/components/ragdoll/document_list_component.rb +13 -0
- data/app/components/ragdoll/document_table_component.html.erb +76 -0
- data/app/components/ragdoll/document_table_component.rb +13 -0
- data/app/components/ragdoll/empty_state_component.html.erb +12 -0
- data/app/components/ragdoll/empty_state_component.rb +17 -0
- data/app/components/ragdoll/flash_messages_component.html.erb +3 -0
- data/app/components/ragdoll/flash_messages_component.rb +37 -0
- data/app/components/ragdoll/navbar_component.html.erb +24 -0
- data/app/components/ragdoll/navbar_component.rb +31 -0
- data/app/components/ragdoll/page_header_component.html.erb +13 -0
- data/app/components/ragdoll/page_header_component.rb +15 -0
- data/app/components/ragdoll/stats_card_component.html.erb +11 -0
- data/app/components/ragdoll/stats_card_component.rb +17 -0
- data/app/components/ragdoll/status_badge_component.html.erb +3 -0
- data/app/components/ragdoll/status_badge_component.rb +30 -0
- data/app/controllers/ragdoll/api/v1/analytics_controller.rb +72 -0
- data/app/controllers/ragdoll/api/v1/base_controller.rb +29 -0
- data/app/controllers/ragdoll/api/v1/documents_controller.rb +148 -0
- data/app/controllers/ragdoll/api/v1/search_controller.rb +87 -0
- data/app/controllers/ragdoll/api/v1/system_controller.rb +97 -0
- data/app/controllers/ragdoll/application_controller.rb +17 -0
- data/app/controllers/ragdoll/configuration_controller.rb +82 -0
- data/app/controllers/ragdoll/dashboard_controller.rb +98 -0
- data/app/controllers/ragdoll/documents_controller.rb +460 -0
- data/app/controllers/ragdoll/documents_controller_backup.rb +68 -0
- data/app/controllers/ragdoll/jobs_controller.rb +116 -0
- data/app/controllers/ragdoll/search_controller.rb +368 -0
- data/app/jobs/application_job.rb +9 -0
- data/app/jobs/ragdoll/bulk_document_processing_job.rb +280 -0
- data/app/jobs/ragdoll/process_file_job.rb +166 -0
- data/app/services/ragdoll/worker_health_service.rb +111 -0
- data/app/views/layouts/ragdoll/application.html.erb +162 -0
- data/app/views/ragdoll/dashboard/analytics.html.erb +333 -0
- data/app/views/ragdoll/dashboard/index.html.erb +208 -0
- data/app/views/ragdoll/documents/edit.html.erb +91 -0
- data/app/views/ragdoll/documents/index.html.erb +302 -0
- data/app/views/ragdoll/documents/new.html.erb +1518 -0
- data/app/views/ragdoll/documents/show.html.erb +188 -0
- data/app/views/ragdoll/documents/upload_results.html.erb +248 -0
- data/app/views/ragdoll/jobs/index.html.erb +669 -0
- data/app/views/ragdoll/jobs/show.html.erb +129 -0
- data/app/views/ragdoll/search/index.html.erb +324 -0
- data/config/cable.yml +12 -0
- data/config/routes.rb +56 -1
- data/lib/ragdoll/rails/engine.rb +32 -1
- data/lib/ragdoll/rails/version.rb +1 -1
- metadata +86 -1
@@ -0,0 +1,188 @@
|
|
1
|
+
<% content_for(:title, "Document: #{@document.title}") %>
|
2
|
+
|
3
|
+
<div class="container-fluid mt-4">
|
4
|
+
<div class="row">
|
5
|
+
<div class="col-md-8">
|
6
|
+
<!-- Document Details -->
|
7
|
+
<div class="card mb-4">
|
8
|
+
<div class="card-header d-flex justify-content-between align-items-center">
|
9
|
+
<h4 class="card-title mb-0">
|
10
|
+
<i class="fas fa-file-alt"></i> <%= @document.title %>
|
11
|
+
</h4>
|
12
|
+
<span class="badge bg-<%= @document.status == 'processed' ? 'success' : @document.status == 'failed' ? 'danger' : 'warning' %> fs-6">
|
13
|
+
<%= @document.status.humanize %>
|
14
|
+
</span>
|
15
|
+
</div>
|
16
|
+
<div class="card-body">
|
17
|
+
<div class="row">
|
18
|
+
<div class="col-md-6">
|
19
|
+
<p><strong>Document Type:</strong> <%= @document.document_type %></p>
|
20
|
+
<p><strong>Created:</strong> <%= @document.created_at.strftime("%B %d, %Y at %I:%M %p") %></p>
|
21
|
+
<p><strong>Last Modified:</strong> <%= @document.file_modified_at&.strftime("%B %d, %Y at %I:%M %p") || "N/A" %></p>
|
22
|
+
</div>
|
23
|
+
<div class="col-md-6">
|
24
|
+
<p><strong>File Size:</strong> <%= number_to_human_size(@document.metadata['file_size']) if @document.metadata && @document.metadata['file_size'] %></p>
|
25
|
+
<p><strong>Encoding:</strong> <%= @document.metadata['encoding'] if @document.metadata && @document.metadata['encoding'] %></p>
|
26
|
+
<p><strong>Location:</strong> <code class="text-muted small"><%= @document.location %></code></p>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<% if @document.summary.present? %>
|
31
|
+
<div class="mt-3">
|
32
|
+
<h6><strong>Summary:</strong></h6>
|
33
|
+
<p class="text-muted"><%= @document.summary %></p>
|
34
|
+
</div>
|
35
|
+
<% end %>
|
36
|
+
|
37
|
+
<% if @document.keywords.present? %>
|
38
|
+
<div class="mt-3">
|
39
|
+
<h6><strong>Keywords:</strong></h6>
|
40
|
+
<% @document.keywords.each do |keyword| %>
|
41
|
+
<span class="badge bg-light text-dark me-1"><%= keyword %></span>
|
42
|
+
<% end %>
|
43
|
+
</div>
|
44
|
+
<% end %>
|
45
|
+
</div>
|
46
|
+
<div class="card-footer">
|
47
|
+
<div class="btn-group" role="group">
|
48
|
+
<%= link_to "Edit", ragdoll.edit_document_path(@document), class: "btn btn-outline-primary" %>
|
49
|
+
<%= link_to "Reprocess", ragdoll.reprocess_document_path(@document), method: :post, class: "btn btn-outline-warning", data: { confirm: "Are you sure you want to reprocess this document?" } %>
|
50
|
+
<%= link_to "Download", ragdoll.download_document_path(@document), class: "btn btn-outline-info" %>
|
51
|
+
<%= link_to "Delete", ragdoll.document_path(@document), method: :delete, class: "btn btn-outline-danger", data: { confirm: "Are you sure you want to delete '#{@document.title}'?\n\nThis action cannot be undone.", turbo_method: :delete } %>
|
52
|
+
<%= link_to "Back to Documents", ragdoll.documents_path, class: "btn btn-secondary" %>
|
53
|
+
</div>
|
54
|
+
</div>
|
55
|
+
</div>
|
56
|
+
|
57
|
+
<!-- Embeddings -->
|
58
|
+
<% if @embeddings && @embeddings.any? %>
|
59
|
+
<div class="card">
|
60
|
+
<div class="card-header">
|
61
|
+
<h5 class="card-title mb-0">
|
62
|
+
<i class="fas fa-vector-square"></i> Embeddings
|
63
|
+
<span class="badge bg-info"><%= @embeddings.count %></span>
|
64
|
+
</h5>
|
65
|
+
</div>
|
66
|
+
<div class="card-body">
|
67
|
+
<div class="table-responsive">
|
68
|
+
<table class="table table-sm">
|
69
|
+
<thead>
|
70
|
+
<tr>
|
71
|
+
<th>ID</th>
|
72
|
+
<th>Content Preview</th>
|
73
|
+
<th>Vector Dimensions</th>
|
74
|
+
<th>Created</th>
|
75
|
+
</tr>
|
76
|
+
</thead>
|
77
|
+
<tbody>
|
78
|
+
<% @embeddings.limit(10).each do |embedding| %>
|
79
|
+
<tr>
|
80
|
+
<td><code><%= embedding.id %></code></td>
|
81
|
+
<td>
|
82
|
+
<%= truncate(embedding.content, length: 100) %>
|
83
|
+
</td>
|
84
|
+
<td>
|
85
|
+
<span class="badge bg-secondary">
|
86
|
+
<%= embedding.embedding_vector&.size || "N/A" %>
|
87
|
+
</span>
|
88
|
+
</td>
|
89
|
+
<td>
|
90
|
+
<small class="text-muted">
|
91
|
+
<%= time_ago_in_words(embedding.created_at) %> ago
|
92
|
+
</small>
|
93
|
+
</td>
|
94
|
+
</tr>
|
95
|
+
<% end %>
|
96
|
+
</tbody>
|
97
|
+
</table>
|
98
|
+
</div>
|
99
|
+
<% if @embeddings.count > 10 %>
|
100
|
+
<p class="text-muted small mt-2">
|
101
|
+
Showing first 10 of <%= @embeddings.count %> embeddings.
|
102
|
+
</p>
|
103
|
+
<% end %>
|
104
|
+
</div>
|
105
|
+
</div>
|
106
|
+
<% else %>
|
107
|
+
<div class="card">
|
108
|
+
<div class="card-body text-center text-muted">
|
109
|
+
<i class="fas fa-info-circle fa-2x mb-3"></i>
|
110
|
+
<p>No embeddings available for this document.</p>
|
111
|
+
<p class="small">Embeddings will be generated when the document is processed.</p>
|
112
|
+
</div>
|
113
|
+
</div>
|
114
|
+
<% end %>
|
115
|
+
</div>
|
116
|
+
|
117
|
+
<!-- Sidebar -->
|
118
|
+
<div class="col-md-4">
|
119
|
+
<!-- Document Metadata -->
|
120
|
+
<div class="card mb-4">
|
121
|
+
<div class="card-header">
|
122
|
+
<h6 class="card-title mb-0">
|
123
|
+
<i class="fas fa-info-circle"></i> Metadata
|
124
|
+
</h6>
|
125
|
+
</div>
|
126
|
+
<div class="card-body">
|
127
|
+
<% if @document.metadata.present? %>
|
128
|
+
<% @document.metadata.each do |key, value| %>
|
129
|
+
<div class="row mb-2">
|
130
|
+
<div class="col-5">
|
131
|
+
<small class="text-muted"><%= key.humanize %>:</small>
|
132
|
+
</div>
|
133
|
+
<div class="col-7">
|
134
|
+
<small>
|
135
|
+
<% if value.is_a?(String) && value.length > 30 %>
|
136
|
+
<span title="<%= value %>"><%= truncate(value, length: 30) %></span>
|
137
|
+
<% else %>
|
138
|
+
<%= value %>
|
139
|
+
<% end %>
|
140
|
+
</small>
|
141
|
+
</div>
|
142
|
+
</div>
|
143
|
+
<% end %>
|
144
|
+
<% else %>
|
145
|
+
<p class="text-muted small">No metadata available.</p>
|
146
|
+
<% end %>
|
147
|
+
</div>
|
148
|
+
</div>
|
149
|
+
|
150
|
+
<!-- Recent Searches -->
|
151
|
+
<% if @recent_searches && @recent_searches.any? %>
|
152
|
+
<div class="card">
|
153
|
+
<div class="card-header">
|
154
|
+
<h6 class="card-title mb-0">
|
155
|
+
<i class="fas fa-search"></i> Recent Searches
|
156
|
+
</h6>
|
157
|
+
</div>
|
158
|
+
<div class="card-body">
|
159
|
+
<% @recent_searches.each do |search| %>
|
160
|
+
<div class="mb-2">
|
161
|
+
<small>
|
162
|
+
<%= link_to search.query, ragdoll.search_index_path(query: search.query), class: "text-decoration-none" %>
|
163
|
+
<span class="text-muted">
|
164
|
+
- <%= time_ago_in_words(search.created_at) %> ago
|
165
|
+
</span>
|
166
|
+
</small>
|
167
|
+
</div>
|
168
|
+
<% end %>
|
169
|
+
</div>
|
170
|
+
</div>
|
171
|
+
<% end %>
|
172
|
+
|
173
|
+
<!-- Quick Actions -->
|
174
|
+
<div class="card mt-4">
|
175
|
+
<div class="card-header">
|
176
|
+
<h6 class="card-title mb-0">
|
177
|
+
<i class="fas fa-bolt"></i> Quick Actions
|
178
|
+
</h6>
|
179
|
+
</div>
|
180
|
+
<div class="card-body">
|
181
|
+
<%= link_to "Search this Document", ragdoll.search_index_path(query: @document.title), class: "btn btn-outline-primary btn-sm w-100 mb-2" %>
|
182
|
+
<%= link_to "View Similar Documents", ragdoll.documents_path(document_type: @document.document_type), class: "btn btn-outline-secondary btn-sm w-100 mb-2" %>
|
183
|
+
<%= link_to "Upload New Document", ragdoll.new_document_path, class: "btn btn-outline-success btn-sm w-100" %>
|
184
|
+
</div>
|
185
|
+
</div>
|
186
|
+
</div>
|
187
|
+
</div>
|
188
|
+
</div>
|
@@ -0,0 +1,248 @@
|
|
1
|
+
<% content_for(:title, "Upload Results") %>
|
2
|
+
|
3
|
+
<%= render Ragdoll::PageHeaderComponent.new(
|
4
|
+
title: "Upload Results",
|
5
|
+
subtitle: "Review the results of your document upload",
|
6
|
+
icon: "fas fa-check-circle"
|
7
|
+
) %>
|
8
|
+
|
9
|
+
<div class="row">
|
10
|
+
<div class="col-lg-8">
|
11
|
+
<div class="card">
|
12
|
+
<div class="card-header d-flex justify-content-between align-items-center">
|
13
|
+
<h5 class="card-title mb-0">
|
14
|
+
<i class="fas fa-list-alt"></i> Upload Summary
|
15
|
+
</h5>
|
16
|
+
<div>
|
17
|
+
<% successful_count = @results&.count { |r| r[:success] } || 0 %>
|
18
|
+
<% failed_count = (@results&.length || 0) - successful_count %>
|
19
|
+
<% duplicate_count = @results&.count { |r| r[:success] && r[:duplicate] } || 0 %>
|
20
|
+
<% new_count = successful_count - duplicate_count %>
|
21
|
+
|
22
|
+
<span class="badge bg-success me-1"><%= new_count %> new</span>
|
23
|
+
<% if duplicate_count > 0 %>
|
24
|
+
<span class="badge bg-warning me-1"><%= duplicate_count %> duplicate<%= duplicate_count > 1 ? 's' : '' %></span>
|
25
|
+
<% end %>
|
26
|
+
<% if failed_count > 0 %>
|
27
|
+
<span class="badge bg-danger"><%= failed_count %> failed</span>
|
28
|
+
<% end %>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
<div class="card-body">
|
32
|
+
<% if @results&.any? %>
|
33
|
+
<% @results.each_with_index do |result, index| %>
|
34
|
+
<div class="result-item border-bottom py-3 <%= 'border-bottom-0' if index == @results.count - 1 %>">
|
35
|
+
<div class="d-flex align-items-start">
|
36
|
+
<div class="result-icon me-3 mt-1">
|
37
|
+
<% if result[:success] %>
|
38
|
+
<% if result[:duplicate] && !result[:forced] %>
|
39
|
+
<i class="fas fa-copy fa-lg text-warning" title="Duplicate detected"></i>
|
40
|
+
<% elsif result[:duplicate] && result[:forced] %>
|
41
|
+
<i class="fas fa-check-circle fa-lg text-success" title="Duplicate forced"></i>
|
42
|
+
<% else %>
|
43
|
+
<i class="fas fa-check-circle fa-lg text-success" title="Successfully added"></i>
|
44
|
+
<% end %>
|
45
|
+
<% else %>
|
46
|
+
<i class="fas fa-times-circle fa-lg text-danger" title="Failed"></i>
|
47
|
+
<% end %>
|
48
|
+
</div>
|
49
|
+
|
50
|
+
<div class="flex-grow-1">
|
51
|
+
<div class="d-flex justify-content-between align-items-start mb-2">
|
52
|
+
<h6 class="mb-0">
|
53
|
+
<i class="fas fa-file me-1"></i>
|
54
|
+
<%= result[:file] %>
|
55
|
+
</h6>
|
56
|
+
<% if result[:success] %>
|
57
|
+
<% if result[:duplicate] && !result[:forced] %>
|
58
|
+
<span class="badge bg-warning">
|
59
|
+
<i class="fas fa-copy me-1"></i>Duplicate Detected
|
60
|
+
</span>
|
61
|
+
<% elsif result[:duplicate] && result[:forced] %>
|
62
|
+
<span class="badge bg-success">
|
63
|
+
<i class="fas fa-exclamation-triangle me-1"></i>Duplicate Forced
|
64
|
+
</span>
|
65
|
+
<% else %>
|
66
|
+
<%= render Ragdoll::StatusBadgeComponent.new(status: "success") %>
|
67
|
+
<% end %>
|
68
|
+
<% else %>
|
69
|
+
<%= render Ragdoll::StatusBadgeComponent.new(status: "failed") %>
|
70
|
+
<% end %>
|
71
|
+
</div>
|
72
|
+
|
73
|
+
<% if result[:success] %>
|
74
|
+
<% if result[:document] %>
|
75
|
+
<p class="text-muted mb-2">
|
76
|
+
<% if result[:duplicate] && !result[:forced] %>
|
77
|
+
<strong>Duplicate detected:</strong> This document already exists in the system. The existing document was returned instead of creating a duplicate.
|
78
|
+
<% elsif result[:duplicate] && result[:forced] %>
|
79
|
+
<strong>Duplicate forced:</strong> A new document was created despite an existing duplicate in the system.
|
80
|
+
<% else %>
|
81
|
+
Document successfully added to the system.
|
82
|
+
<% end %>
|
83
|
+
<% if result[:message] %>
|
84
|
+
<br><em><%= result[:message] %></em>
|
85
|
+
<% end %>
|
86
|
+
</p>
|
87
|
+
<div class="small text-muted">
|
88
|
+
<i class="fas fa-id-badge me-1"></i>
|
89
|
+
Document ID: <%= result[:document].id %>
|
90
|
+
<span class="mx-2">•</span>
|
91
|
+
<i class="fas fa-clock me-1"></i>
|
92
|
+
Added <%= time_ago_in_words(result[:document].created_at) %> ago
|
93
|
+
</div>
|
94
|
+
<div class="mt-2">
|
95
|
+
<%= link_to ragdoll.document_path(result[:document]),
|
96
|
+
class: "btn btn-sm btn-outline-primary" do %>
|
97
|
+
<i class="fas fa-eye me-1"></i> View Document
|
98
|
+
<% end %>
|
99
|
+
</div>
|
100
|
+
<% else %>
|
101
|
+
<p class="text-success mb-0">
|
102
|
+
File processed successfully.
|
103
|
+
<% if result[:message] %>
|
104
|
+
<%= result[:message] %>
|
105
|
+
<% end %>
|
106
|
+
</p>
|
107
|
+
<% end %>
|
108
|
+
<% else %>
|
109
|
+
<div class="alert alert-danger mb-0">
|
110
|
+
<i class="fas fa-exclamation-triangle me-2"></i>
|
111
|
+
<strong>Error:</strong> <%= result[:error] %>
|
112
|
+
</div>
|
113
|
+
<% end %>
|
114
|
+
</div>
|
115
|
+
</div>
|
116
|
+
</div>
|
117
|
+
<% end %>
|
118
|
+
<% else %>
|
119
|
+
<%= render Ragdoll::EmptyStateComponent.new(
|
120
|
+
title: "No results",
|
121
|
+
message: "No upload results to display.",
|
122
|
+
icon: "fas fa-upload"
|
123
|
+
) %>
|
124
|
+
<% end %>
|
125
|
+
</div>
|
126
|
+
|
127
|
+
<% if @results&.any? %>
|
128
|
+
<div class="card-footer bg-light">
|
129
|
+
<div class="d-flex justify-content-between align-items-center">
|
130
|
+
<div class="small text-muted">
|
131
|
+
Upload completed at <%= Time.current.strftime("%B %d, %Y at %I:%M %p") %>
|
132
|
+
</div>
|
133
|
+
<div class="btn-group" role="group">
|
134
|
+
<%= link_to ragdoll.new_document_path, class: "btn btn-outline-primary btn-sm" do %>
|
135
|
+
<i class="fas fa-plus me-1"></i> Upload More
|
136
|
+
<% end %>
|
137
|
+
<%= link_to ragdoll.documents_path, class: "btn btn-primary btn-sm" do %>
|
138
|
+
<i class="fas fa-list me-1"></i> View All Documents
|
139
|
+
<% end %>
|
140
|
+
</div>
|
141
|
+
</div>
|
142
|
+
</div>
|
143
|
+
<% end %>
|
144
|
+
</div>
|
145
|
+
</div>
|
146
|
+
|
147
|
+
<!-- Sidebar -->
|
148
|
+
<div class="col-lg-4">
|
149
|
+
<!-- Next Steps -->
|
150
|
+
<div class="card mb-4">
|
151
|
+
<div class="card-header">
|
152
|
+
<h6 class="card-title mb-0">
|
153
|
+
<i class="fas fa-arrow-right"></i> Next Steps
|
154
|
+
</h6>
|
155
|
+
</div>
|
156
|
+
<div class="card-body">
|
157
|
+
<% if @results&.any? { |r| r[:success] } %>
|
158
|
+
<ul class="list-unstyled mb-0">
|
159
|
+
<li class="mb-2">
|
160
|
+
<i class="fas fa-check text-success me-2"></i>
|
161
|
+
Documents are being processed in the background
|
162
|
+
</li>
|
163
|
+
<li class="mb-2">
|
164
|
+
<i class="fas fa-robot text-info me-2"></i>
|
165
|
+
AI embeddings will be generated automatically
|
166
|
+
</li>
|
167
|
+
<li class="mb-2">
|
168
|
+
<i class="fas fa-search text-primary me-2"></i>
|
169
|
+
Documents will be available for search once processed
|
170
|
+
</li>
|
171
|
+
<li>
|
172
|
+
<i class="fas fa-chart-bar text-warning me-2"></i>
|
173
|
+
Monitor processing status in the dashboard
|
174
|
+
</li>
|
175
|
+
</ul>
|
176
|
+
<% else %>
|
177
|
+
<p class="text-muted mb-3">
|
178
|
+
All uploads failed. Please check the error messages and try again.
|
179
|
+
</p>
|
180
|
+
<%= link_to ragdoll.new_document_path, class: "btn btn-primary btn-sm w-100" do %>
|
181
|
+
<i class="fas fa-retry me-1"></i> Try Again
|
182
|
+
<% end %>
|
183
|
+
<% end %>
|
184
|
+
</div>
|
185
|
+
</div>
|
186
|
+
|
187
|
+
<!-- Processing Status -->
|
188
|
+
<% if @results&.any? { |r| r[:success] } %>
|
189
|
+
<div class="card">
|
190
|
+
<div class="card-header">
|
191
|
+
<h6 class="card-title mb-0">
|
192
|
+
<i class="fas fa-cogs"></i> Processing Status
|
193
|
+
</h6>
|
194
|
+
</div>
|
195
|
+
<div class="card-body">
|
196
|
+
<p class="small text-muted mb-3">
|
197
|
+
Your documents are being processed. You can monitor the progress in real-time.
|
198
|
+
</p>
|
199
|
+
|
200
|
+
<div class="d-grid gap-2">
|
201
|
+
<%= link_to ragdoll.jobs_path, class: "btn btn-outline-info btn-sm" do %>
|
202
|
+
<i class="fas fa-tasks me-1"></i> View Job Queue
|
203
|
+
<% end %>
|
204
|
+
|
205
|
+
<%= link_to ragdoll.dashboard_index_path, class: "btn btn-outline-secondary btn-sm" do %>
|
206
|
+
<i class="fas fa-tachometer-alt me-1"></i> Dashboard
|
207
|
+
<% end %>
|
208
|
+
</div>
|
209
|
+
</div>
|
210
|
+
</div>
|
211
|
+
<% end %>
|
212
|
+
</div>
|
213
|
+
</div>
|
214
|
+
|
215
|
+
<script>
|
216
|
+
// Auto-refresh successful documents to check processing status
|
217
|
+
<% if @results&.any? { |r| r[:success] && r[:document] } %>
|
218
|
+
document.addEventListener('DOMContentLoaded', function() {
|
219
|
+
// Refresh every 30 seconds to check processing status
|
220
|
+
setInterval(function() {
|
221
|
+
if (document.visibilityState === 'visible') {
|
222
|
+
// Only refresh if page is visible
|
223
|
+
const statusElements = document.querySelectorAll('[data-document-id]');
|
224
|
+
statusElements.forEach(function(element) {
|
225
|
+
// Could add AJAX calls here to update document status
|
226
|
+
});
|
227
|
+
}
|
228
|
+
}, 30000);
|
229
|
+
});
|
230
|
+
<% end %>
|
231
|
+
</script>
|
232
|
+
|
233
|
+
<style>
|
234
|
+
.result-item {
|
235
|
+
transition: background-color 0.2s ease;
|
236
|
+
}
|
237
|
+
|
238
|
+
.result-item:hover {
|
239
|
+
background-color: #f8f9fa;
|
240
|
+
border-radius: 0.375rem;
|
241
|
+
margin: -0.5rem;
|
242
|
+
padding: 1rem !important;
|
243
|
+
}
|
244
|
+
|
245
|
+
.result-icon {
|
246
|
+
min-width: 24px;
|
247
|
+
}
|
248
|
+
</style>
|