1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-08-06 22:15:20 +02:00

Data exports (#2517)

* Import / export UI

* Data exports

* Lint fixes, brakeman update
This commit is contained in:
Zach Gollwitzer 2025-07-24 10:50:05 -04:00 committed by GitHub
parent b7c56e2fb7
commit 0329a5f211
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 717 additions and 2 deletions

View file

@ -0,0 +1,39 @@
<%= turbo_frame_tag "family_exports",
data: exports.any? { |e| e.pending? || e.processing? } ? {
turbo_refresh_url: family_exports_path,
turbo_refresh_interval: 3000
} : {} do %>
<div class="mt-4 space-y-3 max-h-96 overflow-y-auto">
<% if exports.any? %>
<% exports.each do |export| %>
<div class="flex items-center justify-between bg-container p-4 rounded-lg border border-primary">
<div>
<p class="text-sm font-medium text-primary">Export from <%= export.created_at.strftime("%B %d, %Y at %I:%M %p") %></p>
<p class="text-xs text-secondary"><%= export.filename %></p>
</div>
<% if export.processing? || export.pending? %>
<div class="flex items-center gap-2 text-secondary">
<div class="animate-spin h-4 w-4 border-2 border-secondary border-t-transparent rounded-full"></div>
<span class="text-sm">Exporting...</span>
</div>
<% elsif export.completed? %>
<%= link_to download_family_export_path(export),
class: "flex items-center gap-2 text-primary hover:text-primary-hover",
data: { turbo_frame: "_top" } do %>
<%= icon "download", class: "w-5 h-5" %>
<span class="text-sm font-medium">Download</span>
<% end %>
<% elsif export.failed? %>
<div class="flex items-center gap-2 text-destructive">
<%= icon "alert-circle", class: "w-4 h-4" %>
<span class="text-sm">Failed</span>
</div>
<% end %>
</div>
<% end %>
<% else %>
<p class="text-sm text-secondary text-center py-4">No exports yet</p>
<% end %>
</div>
<% end %>

View file

@ -0,0 +1 @@
<%= render "list", exports: @exports %>

View file

@ -0,0 +1,42 @@
<%= render DS::Dialog.new do |dialog| %>
<% dialog.with_header(title: "Export your data", subtitle: "Download all your financial data") %>
<% dialog.with_body do %>
<div class="space-y-4">
<div class="bg-container-inset rounded-lg p-4 space-y-3">
<h3 class="font-medium text-primary">What's included:</h3>
<ul class="space-y-2 text-sm text-secondary">
<li class="flex items-start gap-2">
<%= icon "check", class: "shrink-0 mt-0.5 text-positive" %>
<span>All accounts and balances</span>
</li>
<li class="flex items-start gap-2">
<%= icon "check", class: "shrink-0 mt-0.5 text-positive" %>
<span>Transaction history</span>
</li>
<li class="flex items-start gap-2">
<%= icon "check", class: "shrink-0 mt-0.5 text-positive" %>
<span>Investment trades</span>
</li>
<li class="flex items-start gap-2">
<%= icon "check", class: "shrink-0 mt-0.5 text-positive" %>
<span>Categories and tags</span>
</li>
</ul>
</div>
<div class="bg-amber-50 border border-amber-200 rounded-lg p-3">
<p class="text-sm text-amber-800">
<strong>Note:</strong> This export includes all of your data, but only some of the data can be imported back into Maybe via the CSV import feature. We support account, transaction (with category and tags), and trade imports. Other account data cannot be imported and is for your records only.
</p>
</div>
<%= form_with url: family_exports_path, method: :post, class: "space-y-4" do |form| %>
<div class="flex gap-3">
<%= link_to "Cancel", "#", class: "flex-1 text-center px-4 py-2 border border-primary rounded-lg hover:bg-surface-hover", data: { action: "click->modal#close" } %>
<%= form.submit "Export data", class: "flex-1 bg-inverse fg-inverse rounded-lg px-4 py-2 cursor-pointer" %>
</div>
<% end %>
</div>
<% end %>
<% end %>

View file

@ -122,6 +122,29 @@
</div>
<% end %>
<% if Current.user.admin? %>
<%= settings_section title: "Data Import/Export" do %>
<div class="space-y-4">
<div class="flex gap-4 items-center">
<%= render DS::Link.new(
text: "Export data",
icon: "database",
href: new_family_export_path,
variant: "secondary",
full_width: true,
data: { turbo_frame: :modal }
) %>
</div>
<%= turbo_frame_tag "family_exports", src: family_exports_path, loading: :lazy do %>
<div class="mt-4 text-center text-secondary">
<div class="animate-spin inline-block h-4 w-4 border-2 border-secondary border-t-transparent rounded-full"></div>
</div>
<% end %>
</div>
<% end %>
<% end %>
<%= settings_section title: t(".danger_zone_title") do %>
<div class="space-y-4">
<% if Current.user.admin? %>