Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Empty-state improvements — all list views now show a contextual title and an actionable hint; search result empty states include a "Clear search" link; history and stats link to active jobs; processes and recurring tasks explain what to do next
- Inline notifications — bulk and single-job actions now surface a flash notice; Turbo Stream discard responses prepend the message to the page without a full reload; bulk discard/retry counts are shown ("3 jobs discarded")
- Dark mode — toggle button in the header switches between light and dark palettes; preference persisted in `localStorage`; respects `prefers-color-scheme` on first visit; driven entirely by CSS custom properties on `[data-theme="dark"]`

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ The dashboard will be available at `/solid_stack` (or whatever path you choose).
- **Auto-refresh** — dashboard, jobs, processes, and history views poll automatically; pauses when the tab is hidden or a checkbox is checked; intervals configurable via `dashboard_refresh_interval` and `default_refresh_interval`
- **Turbo Stream** job discard — removes the row inline without a full page reload
- **Dark mode** — toggle button in the header switches between light and dark palettes; preference persisted in `localStorage`; respects `prefers-color-scheme` on first visit
- **Empty-state improvements** — all list views show a contextual title and an actionable hint; search empty states include a "Clear search" link; filters-active history view offers "Clear filters"; processes and recurring tasks explain the next step
- **Inline notifications** — bulk and single-job actions surface a flash notice; Turbo Stream discard responses inject the message inline without a full page reload; bulk actions report the affected count ("3 jobs discarded")

### Configuration
Expand Down
1 change: 0 additions & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ The path to v1.0.0 is staged: first achieve feature parity with `solid_queue_das
> _Make the interface feel fast and operational, not just functional._

### Added
- **Empty-state improvements** — contextual empty states per section with actionable next steps
- **Responsive layout** — stats cards and tables adapt to narrow viewports
- **CSS audit** — review all inline styles, consolidate utility classes, remove duplication, and enforce consistent use of CSS custom properties across all stylesheets

Expand Down
12 changes: 12 additions & 0 deletions app/assets/stylesheets/solid_stack_web/_04_table.css
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,15 @@
text-align: center;
color: var(--muted);
}

.sqw-empty__title {
font-size: 15px;
font-weight: 600;
color: var(--text);
margin-bottom: 0.375rem;
}

.sqw-empty__hint {
font-size: 13px;
margin-top: 0.375rem;
}
8 changes: 7 additions & 1 deletion app/views/solid_stack_web/cable/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@
</table>
<% else %>
<div class="sqw-empty">
<p><%= @search.present? ? "No channels matching &ldquo;#{@search}&rdquo;.".html_safe : "No cable messages." %></p>
<% if @search.present? %>
<p class="sqw-empty__title">No channels matching &ldquo;<%= @search %>&rdquo;</p>
<p class="sqw-empty__hint"><%= link_to "Clear search", cable_path %></p>
<% else %>
<p class="sqw-empty__title">No cable messages</p>
<p class="sqw-empty__hint">Messages will appear here once clients connect and broadcast over Action Cable.</p>
<% end %>
</div>
<% end %>
8 changes: 7 additions & 1 deletion app/views/solid_stack_web/cable_messages/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@
<%== @pagy.series_nav if @pagy.pages > 1 %>
<% else %>
<div class="sqw-empty">
<p><%= @search.present? ? "No messages matching &ldquo;#{@search}&rdquo;.".html_safe : "No messages for this channel." %></p>
<% if @search.present? %>
<p class="sqw-empty__title">No messages matching &ldquo;<%= @search %>&rdquo;</p>
<p class="sqw-empty__hint"><%= link_to "Clear search", cable_channel_messages_path(params[:channel_hash]) %></p>
<% else %>
<p class="sqw-empty__title">No messages for this channel</p>
<p class="sqw-empty__hint">Messages may have been purged or the channel has gone quiet. <%= link_to "Back to channels →", cable_path %></p>
<% end %>
</div>
<% end %>
8 changes: 7 additions & 1 deletion app/views/solid_stack_web/cache_entries/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@
<%== @pagy.series_nav if @pagy.pages > 1 %>
<% else %>
<div class="sqw-empty">
<p><%= @search.present? ? "No entries matching &ldquo;#{@search}&rdquo;.".html_safe : "No cache entries." %></p>
<% if @search.present? %>
<p class="sqw-empty__title">No entries matching &ldquo;<%= @search %>&rdquo;</p>
<p class="sqw-empty__hint"><%= link_to "Clear search", cache_entries_path %></p>
<% else %>
<p class="sqw-empty__title">No cache entries</p>
<p class="sqw-empty__hint">Entries will appear here once your application writes to the cache.</p>
<% end %>
</div>
<% end %>
3 changes: 2 additions & 1 deletion app/views/solid_stack_web/failed_jobs/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@
</div>
<% else %>
<div class="sqw-empty">
<p>No failed jobs.</p>
<p class="sqw-empty__title">No failed jobs</p>
<p class="sqw-empty__hint">All clear — your jobs are running without errors.</p>
</div>
<% end %>
</div>
8 changes: 7 additions & 1 deletion app/views/solid_stack_web/history/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,13 @@
</div>
<% else %>
<div class="sqw-empty">
<p>No finished jobs found.</p>
<% if @search.present? || @queue.present? || @period.present? %>
<p class="sqw-empty__title">No finished jobs match your filters</p>
<p class="sqw-empty__hint"><%= link_to "Clear filters", history_path %></p>
<% else %>
<p class="sqw-empty__title">No finished jobs yet</p>
<p class="sqw-empty__hint">Completed jobs will appear here once workers process them.</p>
<% end %>
</div>
<% end %>
<% end %>
21 changes: 19 additions & 2 deletions app/views/solid_stack_web/jobs/_empty.html.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
<div id="sqw-empty" class="sqw-empty">
<p>No <strong><%= @status %></strong> jobs.</p>
</div>
<% if @search.present? %>
<p class="sqw-empty__title">No <strong><%= @status %></strong> jobs matching &ldquo;<%= @search %>&rdquo;</p>
<p class="sqw-empty__hint"><%= link_to "Clear search", jobs_path(status: @status) %></p>
<% else %>
<p class="sqw-empty__title">No <strong><%= @status %></strong> jobs</p>
<p class="sqw-empty__hint">
<% case @status %>
<% when "ready" %>
Jobs will appear here once they are enqueued and ready to be picked up.
<% when "scheduled" %>
No jobs are scheduled to run in the future.
<% when "claimed" %>
No jobs are currently being processed by a worker.
<% when "blocked" %>
No jobs are blocked by concurrency controls.
<% end %>
</p>
<% end %>
</div>
3 changes: 2 additions & 1 deletion app/views/solid_stack_web/processes/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
</table>
<% else %>
<div class="sqw-empty">
<p>No active processes.</p>
<p class="sqw-empty__title">No active processes</p>
<p class="sqw-empty__hint">Start a Solid Queue worker to begin processing jobs.</p>
</div>
<% end %>
<% end %>
3 changes: 2 additions & 1 deletion app/views/solid_stack_web/queues/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
</table>
<% else %>
<div class="sqw-empty">
<p>No queues with ready jobs.</p>
<p class="sqw-empty__title">No queues with ready jobs</p>
<p class="sqw-empty__hint">Workers are idle or all jobs are in another state. <%= link_to "Check job statuses →", jobs_path %></p>
</div>
<% end %>
3 changes: 2 additions & 1 deletion app/views/solid_stack_web/recurring_tasks/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
</table>
<% else %>
<div class="sqw-empty">
<p>No recurring tasks configured.</p>
<p class="sqw-empty__title">No recurring tasks configured</p>
<p class="sqw-empty__hint">Define recurring tasks in your Solid Queue configuration to see them here.</p>
</div>
<% end %>
3 changes: 2 additions & 1 deletion app/views/solid_stack_web/stats/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
</table>
<% else %>
<div class="sqw-empty">
<p>No finished jobs yet.</p>
<p class="sqw-empty__title">No finished jobs yet</p>
<p class="sqw-empty__hint">Performance stats appear here once jobs complete. <%= link_to "View active jobs →", jobs_path %></p>
</div>
<% end %>
2 changes: 1 addition & 1 deletion spec/requests/solid_stack_web/history_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def finished_job(class_name: "TestJob", queue_name: "default", duration: 30, fin

it "shows an empty state when no finished jobs exist" do
get "#{engine_root}/history"
expect(response.body).to include("No finished jobs found")
expect(response.body).to include("No finished jobs yet")
end

it "displays class name, queue, duration, and finished_at columns" do
Expand Down