mirror of
https://github.com/we-promise/sure.git
synced 2026-07-16 14:55:23 +00:00
* fix(ds): route remaining literal yellow warning surfaces onto --color-warning Completes the #2198 warning consolidation for view-level surfaces: - rules/index recent-runs status badges → DS::Pill (warning / success / error). - accounts/_account_sidebar_tabs missing-data notice: bg-yellow-tint-10 / text-yellow-600 → bg-warning/10 / text-warning. - import/confirms/_mappings unassigned-account notice → bg-warning/10 / border-warning/20 (also fixes a missing dark variant — it was light-yellow in dark mode). - simplefin/_replacement_prompt card → bg-warning/10 / border-warning/20, dropping the now-redundant theme-dark: companions (the token is theme-aware). rules' blue/purple execution-type badges and the red failed-row highlight are left as-is (not warning surfaces). Part of #2198. * fix(ds): neutral text in sidebar missing-data notice (match DS::Alert recipe) Warning surfaces follow the DS::Alert recipe — warning tint + warning-colored icon, but neutral body text (text-primary / text-secondary). The sidebar missing-data notice was the lone holdout still painting its text (and link) with text-warning. Switch to neutral text; keep the bg-warning/10 tint and the warning-colored triangle/chevron as the accent. More readable (color-on-tint text is low-contrast) and consistent with the DS::Alert migrations. * fix(ds): missing-data sidebar notice → static DS::Alert (drop disclosure) The notice was a raw collapsible <details> styled as a warning — a hybrid that hid its own primary action (the "Configure providers" link) and its explanation behind a chevron click. A warning's job is to surface a problem and its fix; a disclosure's job is to hide secondary detail. The two fought each other (triangle-alert "act on this" vs chevron "optional, expand"). Replace with a static DS::Alert(:warning): icon + title + body + the Configure link, always visible. Fixes the affordance, surfaces the action, canonicalizes the last warning-styled raw <details>, and matches the other DS::Alert notices. * fix(ds): grey body text in missing-data alert for title/body hierarchy DS::Alert renders its body in text-primary (same dark as the title). For this notice, drop the description to text-secondary so the title (primary, semibold) reads above the supporting body (grey) — clearer hierarchy. Still neutral (no colored text); the Configure link stays primary + underline so the action remains the prominent element. * fix(ds): bump account_sidebar_tabs cache version v1→v2 Flush stale <details>-markup fragments on deploy. The sidebar missing-data notice migrated from <details> to a static DS::Alert, but the fragment is cached with a 12h TTL — without a key change, old markup renders until expiry (and inconsistently across staggered multi-server cache warmups). Bumping the version string changes the cache-key namespace so every cached fragment is bypassed immediately.
182 lines
8.1 KiB
Plaintext
182 lines
8.1 KiB
Plaintext
<%= content_for :page_title, t(".page_title") %>
|
|
<%= content_for :page_actions do %>
|
|
<% if @rules.any? %>
|
|
<%= render DS::Menu.new do |menu| %>
|
|
<% menu.with_item(
|
|
variant: "button",
|
|
text: t("rules.clear_ai_cache.button"),
|
|
href: clear_ai_cache_rules_path,
|
|
icon: "refresh-cw",
|
|
method: :post,
|
|
confirm: CustomConfirm.new(
|
|
title: t("rules.clear_ai_cache.confirm_title"),
|
|
body: t("rules.clear_ai_cache.confirm_body"),
|
|
btn_text: t("rules.clear_ai_cache.confirm_button")
|
|
)) %>
|
|
<% menu.with_item(
|
|
variant: "button",
|
|
text: t(".delete_all_rules"),
|
|
href: destroy_all_rules_path,
|
|
icon: "trash-2",
|
|
method: :delete,
|
|
confirm: CustomConfirm.for_resource_deletion("all rules", high_severity: true)) %>
|
|
<% end %>
|
|
<%= render DS::Link.new(
|
|
text: t("rules.apply_all.button"),
|
|
variant: "secondary",
|
|
href: confirm_all_rules_path,
|
|
icon: "play",
|
|
frame: :modal
|
|
) %>
|
|
<% end %>
|
|
<%= render DS::Link.new(
|
|
text: t(".new_rule"),
|
|
variant: "primary",
|
|
href: new_rule_path(resource_type: "transaction"),
|
|
icon: "plus",
|
|
frame: :modal
|
|
) %>
|
|
<% end %>
|
|
|
|
<% if self_hosted? %>
|
|
<div class="flex items-center gap-2 mb-2 py-4">
|
|
<%= icon("circle-alert", size: "sm") %>
|
|
<p class="text-sm text-secondary">
|
|
<%= t(".ai_cost_warning") %>
|
|
</p>
|
|
</div>
|
|
<% end %>
|
|
<div class="bg-container rounded-xl shadow-border-xs p-4">
|
|
<% if @rules.any? %>
|
|
<div class="bg-container-inset rounded-xl">
|
|
<div class="flex justify-between px-4 py-2 text-xs uppercase">
|
|
<div class="flex items-center gap-1.5 font-medium text-secondary">
|
|
<p><%= t(".rules_heading") %></p>
|
|
<span class="text-subdued">·</span>
|
|
<p><%= @rules.count %></p>
|
|
</div>
|
|
<div class="flex items-center gap-1">
|
|
<span class="text-secondary"><%= t(".sort_by") %></span>
|
|
<%= form_with url: rules_path, method: :get, local: true, class: "flex items-center", data: { controller: "auto-submit-form" } do |form| %>
|
|
<%= form.select :sort_by,
|
|
options_for_select([[t(".sort_name"), "name"], [t(".sort_updated_at"), "updated_at"]], @sort_by),
|
|
{},
|
|
class: "min-w-[120px] bg-transparent rounded border-none cursor-pointer text-primary uppercase text-xs w-auto",
|
|
data: { auto_submit_form_target: "auto", autosubmit_trigger_event: "change" } %>
|
|
<%= form.hidden_field :direction, value: @direction %>
|
|
<% end %>
|
|
<%= render DS::Link.new(
|
|
href: rules_path(direction: @direction == "asc" ? "desc" : "asc", sort_by: @sort_by),
|
|
variant: "icon",
|
|
icon: "arrow-up-down",
|
|
size: :sm,
|
|
title: t(".toggle_sort_direction")
|
|
) %>
|
|
</div>
|
|
</div>
|
|
<div class="p-1">
|
|
<div class="flex flex-col bg-container rounded-lg shadow-border-xs">
|
|
<%= render partial: "rule", collection: @rules, spacer_template: "shared/ruler" %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% else %>
|
|
<div class="flex justify-center items-center py-20">
|
|
<div class="text-center flex flex-col items-center max-w-[500px]">
|
|
<p class="text-sm text-primary font-medium mb-1"><%= t(".no_rules_title") %></p>
|
|
<p class="text-sm text-secondary mb-4"><%= t(".no_rules_description") %></p>
|
|
<div class="flex items-center gap-2">
|
|
<%= render DS::Link.new(
|
|
text: t(".new_rule"),
|
|
variant: "primary",
|
|
href: new_rule_path(resource_type: "transaction"),
|
|
icon: "plus",
|
|
frame: :modal
|
|
) %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<!-- Recent Runs Section -->
|
|
<% if @recent_runs.any? %>
|
|
<div class="mt-6 bg-container rounded-xl shadow-border-xs p-4">
|
|
<div class="mb-4">
|
|
<h2 class="text-primary text-lg font-medium mb-1"><%= t("rules.recent_runs.title") %></h2>
|
|
<p class="text-sm text-secondary"><%= t("rules.recent_runs.description") %></p>
|
|
</div>
|
|
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full">
|
|
<thead class="bg-surface border-b border-primary">
|
|
<tr>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-secondary uppercase tracking-wider">
|
|
<%= t("rules.recent_runs.columns.date_time") %>
|
|
</th>
|
|
<th class="px-4 py-3 text-center text-xs font-medium text-secondary uppercase tracking-wider">
|
|
<%= t("rules.recent_runs.columns.execution_type") %>
|
|
</th>
|
|
<th class="px-4 py-3 text-center text-xs font-medium text-secondary uppercase tracking-wider">
|
|
<%= t("rules.recent_runs.columns.status") %>
|
|
</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-secondary uppercase tracking-wider">
|
|
<%= t("rules.recent_runs.columns.rule_name") %>
|
|
</th>
|
|
<th class="px-4 py-3 text-center text-xs font-medium text-secondary uppercase tracking-wider">
|
|
<div class="flex flex-col leading-tight">
|
|
<div><%= t("rules.recent_runs.columns.transactions_counts.queued") %></div>
|
|
<div><%= t("rules.recent_runs.columns.transactions_counts.processed") %></div>
|
|
<div><%= t("rules.recent_runs.columns.transactions_counts.modified") %></div>
|
|
<div><%= t("rules.recent_runs.columns.transactions_counts.blocked", default: "Blocked") %></div>
|
|
</div>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-gray-100">
|
|
<% @recent_runs.each do |run| %>
|
|
<tr class="<%= "bg-red-50 theme-dark:bg-red-950/30" if run.failed? %>">
|
|
<td class="px-4 py-3 text-sm text-primary whitespace-nowrap">
|
|
<%= run.executed_at.strftime("%b %d, %Y %I:%M %p") %>
|
|
</td>
|
|
<td class="px-4 py-3 text-sm text-primary text-center">
|
|
<span class="inline-flex items-center px-2 py-1 rounded-md text-xs font-medium <%= run.execution_type == "manual" ? "bg-blue-50 text-blue-700 theme-dark:bg-blue-950/30 theme-dark:text-blue-400" : "bg-purple-50 text-purple-700 theme-dark:bg-purple-950/30 theme-dark:text-purple-400" %>">
|
|
<%= t("rules.recent_runs.execution_types.#{run.execution_type}") %>
|
|
</span>
|
|
</td>
|
|
<td class="px-4 py-3 text-sm text-center">
|
|
<div class="flex items-center justify-center gap-2">
|
|
<% if run.pending? %>
|
|
<%= render DS::Pill.new(label: t("rules.recent_runs.statuses.#{run.status}"), tone: :warning, marker: false) %>
|
|
<% elsif run.success? %>
|
|
<%= render DS::Pill.new(label: t("rules.recent_runs.statuses.#{run.status}"), tone: :success, marker: false) %>
|
|
<% else %>
|
|
<%= render DS::Pill.new(label: t("rules.recent_runs.statuses.#{run.status}"), tone: :error, marker: false) %>
|
|
<% end %>
|
|
<% if run.failed? && run.error_message.present? %>
|
|
<div data-controller="tooltip" data-tooltip-content-value="<%= run.error_message %>">
|
|
<%= icon("info", size: "sm", class: "text-red-500") %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</td>
|
|
<td class="px-4 py-3 text-sm text-primary">
|
|
<%= run.rule_name.presence || run.rule&.name.presence || t("rules.recent_runs.unnamed_rule") %>
|
|
</td>
|
|
<td class="px-4 py-3 text-sm text-primary text-center tabular-nums">
|
|
<%= "#{number_with_delimiter(run.transactions_queued)} / #{number_with_delimiter(run.transactions_processed)} / #{number_with_delimiter(run.transactions_modified)} / #{number_with_delimiter(run.transactions_blocked)}" %>
|
|
</td>
|
|
</tr>
|
|
<% end %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<% if @pagy.pages > 1 %>
|
|
<div class="mt-4">
|
|
<%= render "shared/pagination", pagy: @pagy %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
<% end %>
|