Files
sure/app/views/rules/index.html.erb
Zach Gollwitzer 10dd9e061a Improve account sync performance, handle concurrent market data syncing (#2236)
* PlaidConnectable concern

* Remove bad abstraction

* Put sync implementations in own concerns

* Sync strategies

* Move sync orchestration to Sync class

* Clean up sync class, add state machine

* Basic market data sync cron

* Fix price sync

* Improve sync window column names, add timestamps

* 30 day syncs by default

* Clean up market data methods

* Report high duplicate sync counts to Sentry

* Add sync states throughout app

* account tab session

* Persistent account tab selections

* Remove manual sleep

* Add migration to clear stale syncs on self hosted apps

* Tweak sync states

* Sync completion event broadcasts

* Fix timezones in tests

* Cleanup

* More cleanup

* Plaid item UI broadcasts for sync

* Fix account ID namespace conflict

* Sync broadcasters

* Smoother account sync refreshes

* Remove test sync delay
2025-05-15 10:19:56 -04:00

89 lines
3.5 KiB
Plaintext

<header class="flex items-center justify-between">
<h1 class="text-primary text-xl font-medium">Rules</h1>
<div class="flex items-center gap-2">
<% if @rules.any? %>
<%= render MenuComponent.new do |menu| %>
<% menu.with_item(
variant: "button",
text: "Delete all rules",
href: destroy_all_rules_path,
icon: "trash-2",
method: :delete,
confirm: CustomConfirm.for_resource_deletion("all rules", high_severity: true)) %>
<% end %>
<% end %>
<%= render LinkComponent.new(
text: "New rule",
variant: "primary",
href: new_rule_path(resource_type: "transaction"),
icon: "plus",
frame: :modal
) %>
</div>
</header>
<% 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">
AI-enabled rule actions will cost money. Be sure to filter as narrowly as possible to avoid unnecessary costs.
</p>
</div>
<% end %>
<div class="bg-container shadow-border-xs rounded-xl 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>Rules</p>
<span class="text-subdued">&middot;</span>
<p><%= @rules.count %></p>
</div>
<div class="flex items-center gap-1">
<span class="text-secondary">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([["Name", "name"], ["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 LinkComponent.new(
href: rules_path(direction: @direction == "asc" ? "desc" : "asc", sort_by: @sort_by),
variant: "icon",
icon: "arrow-up-down",
size: :sm,
title: "Toggle sort direction"
) %>
</div>
</div>
<div class="p-1">
<div class="flex flex-col bg-container rounded-xl shadow-border-xs first_child:rounded-t-xl last_child:rounded-b-xl">
<% @rules.each_with_index do |rule, idx| %>
<%= render "rule", rule: rule %>
<% unless idx == @rules.size - 1 %>
<div class="h-px bg-divider ml-4 mr-6"></div>
<% end %>
<% end %>
</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">No rules yet</p>
<p class="text-sm text-secondary mb-4">Set up rules to perform actions to your transactions and other data on every account sync.</p>
<div class="flex items-center gap-2">
<%= render LinkComponent.new(
text: "New rule",
variant: "primary",
href: new_rule_path(resource_type: "transaction"),
icon: "plus",
frame: :modal
) %>
</div>
</div>
</div>
<% end %>
</div>