mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-09 07:25:19 +02:00
Sync completion event broadcasts
This commit is contained in:
parent
b041edb648
commit
246343a4bf
25 changed files with 237 additions and 169 deletions
|
@ -1,7 +1,6 @@
|
|||
/* Custom shadow borders used for surfaces / containers */
|
||||
@utility shadow-border-xs {
|
||||
box-shadow: var(--shadow-xs), 0px 0px 0px 1px var(--color-alpha-black-50);
|
||||
transform: translateZ(0);
|
||||
|
||||
@variant theme-dark {
|
||||
box-shadow: var(--shadow-xs), 0px 0px 0px 1px var(--color-alpha-white-50);
|
||||
|
@ -10,7 +9,6 @@
|
|||
|
||||
@utility shadow-border-sm {
|
||||
box-shadow: var(--shadow-sm), 0px 0px 0px 1px var(--color-alpha-black-50);
|
||||
transform: translateZ(0);
|
||||
|
||||
@variant theme-dark {
|
||||
box-shadow: var(--shadow-sm), 0px 0px 0px 1px var(--color-alpha-white-50);
|
||||
|
@ -19,7 +17,6 @@
|
|||
|
||||
@utility shadow-border-md {
|
||||
box-shadow: var(--shadow-md), 0px 0px 0px 1px var(--color-alpha-black-50);
|
||||
transform: translateZ(0);
|
||||
|
||||
@variant theme-dark {
|
||||
box-shadow: var(--shadow-md), 0px 0px 0px 1px var(--color-alpha-white-50);
|
||||
|
@ -28,7 +25,6 @@
|
|||
|
||||
@utility shadow-border-lg {
|
||||
box-shadow: var(--shadow-lg), 0px 0px 0px 1px var(--color-alpha-black-50);
|
||||
transform: translateZ(0);
|
||||
|
||||
@variant theme-dark {
|
||||
box-shadow: var(--shadow-lg), 0px 0px 0px 1px var(--color-alpha-white-50);
|
||||
|
@ -37,7 +33,6 @@
|
|||
|
||||
@utility shadow-border-xl {
|
||||
box-shadow: var(--shadow-xl), 0px 0px 0px 1px var(--color-alpha-black-50);
|
||||
transform: translateZ(0);
|
||||
|
||||
@variant theme-dark {
|
||||
box-shadow: var(--shadow-xl), 0px 0px 0px 1px var(--color-alpha-white-50);
|
||||
|
|
|
@ -11,11 +11,6 @@
|
|||
<% else %>
|
||||
<%= nav %>
|
||||
|
||||
<%= form_with url: cookie_session_path, scope: :cookie_session, method: :put, data: { tabs_target: "persistSelectionForm" } do |f| %>
|
||||
<%= f.hidden_field :tab_key, value: "account_group_tab" %>
|
||||
<%= f.hidden_field :tab_value, value: "all", data: { tabs_target: "selectionInput" } %>
|
||||
<% end %>
|
||||
|
||||
<% panels.each do |panel| %>
|
||||
<%= panel %>
|
||||
<% end %>
|
||||
|
|
|
@ -36,8 +36,22 @@ export default class extends Controller {
|
|||
|
||||
// Update URL with the selected tab
|
||||
if (this.sessionKeyValue) {
|
||||
this.selectionInputTarget.value = selectedTabId;
|
||||
this.persistSelectionFormTarget.requestSubmit();
|
||||
this.#updateSessionPreference(selectedTabId);
|
||||
}
|
||||
}
|
||||
|
||||
#updateSessionPreference(selectedTabId) {
|
||||
fetch("/current_session", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"X-CSRF-Token": document.querySelector('[name="csrf-token"]').content,
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
"current_session[tab_key]": this.sessionKeyValue,
|
||||
"current_session[tab_value]": selectedTabId,
|
||||
}).toString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class ApplicationController < ActionController::Base
|
||||
include Onboardable, Localize, AutoSync, Authentication, Invitable,
|
||||
include RestoreLayoutPreferences, Onboardable, Localize, AutoSync, Authentication, Invitable,
|
||||
SelfHostable, StoreLocation, Impersonatable, Breadcrumbable,
|
||||
FeatureGuardable, Notifiable, AccountGroupable
|
||||
FeatureGuardable, Notifiable
|
||||
|
||||
include Pagy::Backend
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
module AccountGroupable
|
||||
module RestoreLayoutPreferences
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_action :set_account_group_tab
|
||||
before_action :restore_active_tabs
|
||||
end
|
||||
|
||||
private
|
||||
def set_account_group_tab
|
||||
last_selected_tab = session["custom_account_group_tab"] || "asset"
|
||||
def restore_active_tabs
|
||||
last_selected_tab = Current.session&.get_preferred_tab("account_sidebar_tab") || "asset"
|
||||
|
||||
@account_group_tab = account_group_tab_param || last_selected_tab
|
||||
end
|
||||
|
@ -17,7 +17,7 @@ module AccountGroupable
|
|||
end
|
||||
|
||||
def account_group_tab_param
|
||||
param_value = params[:account_group_tab]
|
||||
param_value = params[:account_sidebar_tab]
|
||||
return nil unless param_value.in?(valid_account_group_tabs)
|
||||
param_value
|
||||
end
|
14
app/controllers/current_sessions_controller.rb
Normal file
14
app/controllers/current_sessions_controller.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
class CurrentSessionsController < ApplicationController
|
||||
def update
|
||||
if session_params[:tab_key].present? && session_params[:tab_value].present?
|
||||
Current.session.set_preferred_tab(session_params[:tab_key], session_params[:tab_value])
|
||||
end
|
||||
|
||||
head :ok
|
||||
end
|
||||
|
||||
private
|
||||
def session_params
|
||||
params.require(:current_session).permit(:tab_key, :tab_value)
|
||||
end
|
||||
end
|
|
@ -13,7 +13,7 @@ class Account::Syncer
|
|||
def perform_post_sync
|
||||
account.family.auto_match_transfers!
|
||||
account.broadcast_refresh
|
||||
account.family.broadcast_sidebar_refresh
|
||||
SyncCompleteEvent.new(account.family, accounts: [ account ]).broadcast
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -54,8 +54,11 @@ class BalanceSheet
|
|||
groups = account_groups.map do |accountable, accounts|
|
||||
group_total = accounts.sum(&:converted_balance)
|
||||
|
||||
key = accountable.model_name.param_key
|
||||
|
||||
AccountGroup.new(
|
||||
key: accountable.model_name.param_key,
|
||||
id: classification ? "#{classification}_#{key}_group" : "#{key}_group",
|
||||
key: key,
|
||||
name: accountable.display_name,
|
||||
classification: accountable.classification,
|
||||
total: group_total,
|
||||
|
@ -95,7 +98,7 @@ class BalanceSheet
|
|||
|
||||
private
|
||||
ClassificationGroup = Struct.new(:key, :display_name, :icon, :total_money, :account_groups, :syncing?, keyword_init: true)
|
||||
AccountGroup = Struct.new(:key, :name, :accountable_type, :classification, :total, :total_money, :weight, :accounts, :color, :missing_rates?, :syncing?, keyword_init: true)
|
||||
AccountGroup = Struct.new(:id, :key, :name, :accountable_type, :classification, :total, :total_money, :weight, :accounts, :color, :missing_rates?, :syncing?, keyword_init: true)
|
||||
|
||||
def active_accounts
|
||||
family.accounts.active.with_attached_logo
|
||||
|
|
|
@ -44,14 +44,6 @@ class Family < ApplicationRecord
|
|||
.exists?
|
||||
end
|
||||
|
||||
def broadcast_sidebar_refresh
|
||||
broadcast_replace(
|
||||
target: "account-sidebar-tabs",
|
||||
partial: "accounts/sidebar_tabs",
|
||||
locals: { family: self, active_account_group_tab: "all" }
|
||||
)
|
||||
end
|
||||
|
||||
def assigned_merchants
|
||||
merchant_ids = transactions.where.not(merchant_id: nil).pluck(:merchant_id).uniq
|
||||
Merchant.where(id: merchant_ids)
|
||||
|
|
|
@ -24,7 +24,7 @@ class PlaidItem::Syncer
|
|||
|
||||
def perform_post_sync
|
||||
plaid_item.auto_match_categories!
|
||||
plaid_item.family.broadcast_sidebar_refresh
|
||||
SyncCompleteEvent.new(plaid_item.family, accounts: plaid_item.accounts).broadcast
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -9,4 +9,14 @@ class Session < ApplicationRecord
|
|||
self.user_agent = Current.user_agent
|
||||
self.ip_address = Current.ip_address
|
||||
end
|
||||
|
||||
def get_preferred_tab(tab_key)
|
||||
data.dig("tab_preferences", tab_key)
|
||||
end
|
||||
|
||||
def set_preferred_tab(tab_key, tab_value)
|
||||
data["tab_preferences"] ||= {}
|
||||
data["tab_preferences"][tab_key] = tab_value
|
||||
save!
|
||||
end
|
||||
end
|
||||
|
|
|
@ -49,7 +49,9 @@ class Sync < ApplicationRecord
|
|||
begin
|
||||
syncable.perform_sync(self)
|
||||
rescue => e
|
||||
fail_and_report_error(e)
|
||||
fail!
|
||||
update(error: e.message)
|
||||
report_error(e)
|
||||
ensure
|
||||
finalize_if_all_children_finalized
|
||||
end
|
||||
|
@ -64,9 +66,6 @@ class Sync < ApplicationRecord
|
|||
# If this is the "parent" and there are still children running, don't finalize.
|
||||
return unless all_children_finalized?
|
||||
|
||||
# If we make it here, the sync is finalized. Run post-sync, regardless of failure/success.
|
||||
perform_post_sync
|
||||
|
||||
if syncing?
|
||||
if has_failed_children?
|
||||
fail!
|
||||
|
@ -74,6 +73,9 @@ class Sync < ApplicationRecord
|
|||
complete!
|
||||
end
|
||||
end
|
||||
|
||||
# If we make it here, the sync is finalized. Run post-sync, regardless of failure/success.
|
||||
perform_post_sync
|
||||
end
|
||||
|
||||
# If this sync has a parent, try to finalize it so the child status propagates up the chain.
|
||||
|
@ -96,12 +98,10 @@ class Sync < ApplicationRecord
|
|||
def perform_post_sync
|
||||
syncable.perform_post_sync
|
||||
rescue => e
|
||||
fail_and_report_error(e)
|
||||
report_error(e)
|
||||
end
|
||||
|
||||
def fail_and_report_error(error)
|
||||
fail!
|
||||
update(error: error.message)
|
||||
def report_error(error)
|
||||
Sentry.capture_exception(error) do |scope|
|
||||
scope.set_tags(sync_id: id)
|
||||
end
|
||||
|
|
37
app/models/sync_complete_event.rb
Normal file
37
app/models/sync_complete_event.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
class SyncCompleteEvent
|
||||
attr_reader :family, :accounts
|
||||
|
||||
def initialize(family, accounts: [])
|
||||
@family = family
|
||||
@accounts = accounts
|
||||
end
|
||||
|
||||
def broadcast
|
||||
account_groups = family.balance_sheet.account_groups.select do |group|
|
||||
group.accounts.any? { |a| accounts.include?(a) }
|
||||
end
|
||||
|
||||
account_groups.each do |account_group|
|
||||
[ nil, "asset", "liability" ].each do |classification|
|
||||
id = classification ? "#{classification}_#{account_group.id}" : account_group.id
|
||||
family.broadcast_replace(
|
||||
target: id,
|
||||
partial: "accounts/accountable_group",
|
||||
locals: { account_group: account_group, open: true }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
family.broadcast_replace(
|
||||
target: "balance-sheet",
|
||||
partial: "pages/dashboard/balance_sheet",
|
||||
locals: { balance_sheet: family.balance_sheet }
|
||||
)
|
||||
|
||||
family.broadcast_replace(
|
||||
target: "net-worth-chart",
|
||||
partial: "pages/dashboard/net_worth_chart",
|
||||
locals: { balance_sheet: family.balance_sheet, period: Period.last_30_days }
|
||||
)
|
||||
end
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
<%# locals: (family:, active_account_group_tab: "asset") %>
|
||||
<%# locals: (family:, active_tab:, mobile: false) %>
|
||||
|
||||
<div id="account-sidebar-tabs">
|
||||
<% if family.missing_data_provider? %>
|
||||
|
@ -21,7 +21,7 @@
|
|||
</details>
|
||||
<% end %>
|
||||
|
||||
<%= render TabsComponent.new(active_tab: active_account_group_tab, session_key: "account_group_tab", testid: "account-sidebar-tabs") do |tabs| %>
|
||||
<%= render TabsComponent.new(active_tab: active_tab, session_key: "account_sidebar_tab", testid: "account-sidebar-tabs") do |tabs| %>
|
||||
<% tabs.with_nav do |nav| %>
|
||||
<% nav.with_btn(id: "asset", label: "Assets") %>
|
||||
<% nav.with_btn(id: "liability", label: "Debts") %>
|
||||
|
@ -42,7 +42,7 @@
|
|||
|
||||
<div>
|
||||
<% family.balance_sheet.account_groups("asset").each do |group| %>
|
||||
<%= render "accounts/accountable_group", account_group: group %>
|
||||
<%= render "accounts/accountable_group", account_group: group, mobile: mobile %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -62,7 +62,7 @@
|
|||
|
||||
<div>
|
||||
<% family.balance_sheet.account_groups("liability").each do |group| %>
|
||||
<%= render "accounts/accountable_group", account_group: group %>
|
||||
<%= render "accounts/accountable_group", account_group: group, mobile: mobile %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -82,7 +82,7 @@
|
|||
|
||||
<div>
|
||||
<% family.balance_sheet.account_groups.each do |group| %>
|
||||
<%= render "accounts/accountable_group", account_group: group %>
|
||||
<%= render "accounts/accountable_group", account_group: group, mobile: mobile %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<%# locals: (account_group:) %>
|
||||
<%# locals: (account_group:, mobile: false, open: nil, **args) %>
|
||||
|
||||
<%= render DisclosureComponent.new(title: account_group.name, align: :left, open: account_group.accounts.any? { |account| page_active?(account_path(account)) }) do |disclosure| %>
|
||||
<div id="<%= mobile ? "mobile_#{account_group.id}" : account_group.id %>">
|
||||
<% is_open = open.nil? ? account_group.accounts.any? { |account| page_active?(account_path(account)) } : open %>
|
||||
<%= render DisclosureComponent.new(title: account_group.name, align: :left, open: is_open) do |disclosure| %>
|
||||
<% disclosure.with_summary_content do %>
|
||||
<div class="ml-auto text-right grow">
|
||||
<% if account_group.syncing? %>
|
||||
|
@ -71,4 +73,5 @@
|
|||
class: "justify-start"
|
||||
) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<%# locals: (account:, title: nil, tooltip: nil, chart_view: nil, **args) %>
|
||||
<%# locals: (account:, tooltip: nil, chart_view: nil, **args) %>
|
||||
|
||||
<% period = @period || Period.last_30_days %>
|
||||
<% default_value_title = account.asset? ? t(".balance") : t(".owed") %>
|
||||
|
@ -7,10 +7,10 @@
|
|||
<div class="flex justify-between flex-col-reverse lg:flex-row gap-2 px-4 pt-4 mb-2">
|
||||
<div class="space-y-2 w-full">
|
||||
<div class="flex items-center gap-1">
|
||||
<%= tag.p title || default_value_title, class: "text-sm font-medium text-secondary" %>
|
||||
<%= tag.p account.investment? ? "Total value" : default_value_title, class: "text-sm font-medium text-secondary" %>
|
||||
|
||||
<% unless account.syncing? %>
|
||||
<%= tooltip %>
|
||||
<% if !account.syncing? && account.investment? %>
|
||||
<%= render "investments/value_tooltip", balance: account.balance_money, holdings: account.balance_money - account.cash_balance_money, cash: account.cash_balance_money %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<%# locals: (account:, header: nil, chart: nil, tabs: nil) %>
|
||||
<%# locals: (account:, header: nil, chart: nil, chart_view: nil, tabs: nil) %>
|
||||
|
||||
<%= turbo_stream_from account %>
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
|||
<% if chart.present? %>
|
||||
<%= chart %>
|
||||
<% else %>
|
||||
<%= render "accounts/show/chart", account: account %>
|
||||
<%= render "accounts/show/chart", account: account, chart_view: chart_view %>
|
||||
<% end %>
|
||||
|
||||
<div class="min-h-[800px]" data-testid="account-details">
|
||||
|
|
|
@ -1,25 +1,7 @@
|
|||
<%= turbo_stream_from @account %>
|
||||
|
||||
<%= turbo_frame_tag dom_id(@account) do %>
|
||||
<%= tag.div class: "space-y-4" do %>
|
||||
<%= render "accounts/show/header", account: @account %>
|
||||
|
||||
<%= render "accounts/show/chart",
|
||||
<%= render "accounts/show/template",
|
||||
account: @account,
|
||||
title: t(".chart_title"),
|
||||
chart_view: @chart_view,
|
||||
tooltip: render(
|
||||
"investments/value_tooltip",
|
||||
balance: @account.balance_money,
|
||||
holdings: @account.balance_money - @account.cash_balance_money,
|
||||
cash: @account.cash_balance_money
|
||||
) %>
|
||||
|
||||
<div class="min-h-[800px]">
|
||||
<%= render "accounts/show/tabs", account: @account, tabs: [
|
||||
tabs: render("accounts/show/tabs", account: @account, tabs: [
|
||||
{ key: "activity", contents: render("accounts/show/activity", account: @account) },
|
||||
{ key: "holdings", contents: render("investments/holdings_tab", account: @account) },
|
||||
] %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
]) %>
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
<%= render(
|
||||
"accounts/account_sidebar_tabs",
|
||||
family: Current.family,
|
||||
active_account_group_tab: @account_group_tab
|
||||
active_tab: @account_group_tab,
|
||||
mobile: true
|
||||
) %>
|
||||
</div>
|
||||
|
||||
|
@ -81,7 +82,7 @@
|
|||
<% else %>
|
||||
<div class="h-full flex flex-col">
|
||||
<div class="overflow-y-auto grow">
|
||||
<%= render "accounts/account_sidebar_tabs", family: Current.family, active_account_group_tab: @account_group_tab %>
|
||||
<%= render "accounts/account_sidebar_tabs", family: Current.family, active_tab: @account_group_tab %>
|
||||
</div>
|
||||
|
||||
<% if Current.family.trialing? && !self_hosted? %>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<%# locals: (balance_sheet:) %>
|
||||
<%# locals: (balance_sheet:, **args) %>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="space-y-4" id="balance-sheet">
|
||||
<% balance_sheet.classification_groups.each do |classification_group| %>
|
||||
<div class="bg-container shadow-border-xs rounded-xl space-y-4 p-4">
|
||||
<h2 class="text-lg font-medium inline-flex items-center gap-1.5">
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<%# locals: (balance_sheet:, period:) %>
|
||||
<%# locals: (balance_sheet:, period:, **args) %>
|
||||
|
||||
<% series = balance_sheet.net_worth_series(period: period) %>
|
||||
|
||||
<div class="flex justify-between gap-4 px-4">
|
||||
<div id="net-worth-chart">
|
||||
<% series = balance_sheet.net_worth_series(period: period) %>
|
||||
<div class="flex justify-between gap-4 px-4">
|
||||
<div class="space-y-2">
|
||||
<div class="space-y-2">
|
||||
<p class="text-sm text-secondary font-medium"><%= t(".title") %></p>
|
||||
|
@ -33,13 +33,13 @@
|
|||
data: { "auto-submit-form-target": "auto" },
|
||||
class: "bg-container border border-secondary font-medium rounded-lg px-3 py-2 text-sm pr-7 cursor-pointer text-primary focus:outline-hidden focus:ring-0" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if balance_sheet.syncing? %>
|
||||
<% if balance_sheet.syncing? %>
|
||||
<div class="w-full flex items-center justify-center p-4 h-52">
|
||||
<div class="bg-loader rounded-md h-full w-full"></div>
|
||||
</div>
|
||||
<% else %>
|
||||
<% else %>
|
||||
<% if series.any? %>
|
||||
<div
|
||||
id="netWorthChart"
|
||||
|
@ -51,4 +51,5 @@
|
|||
<p class="text-secondary text-sm"><%= t(".data_not_available") %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -26,7 +26,7 @@ Rails.application.routes.draw do
|
|||
get "changelog", to: "pages#changelog"
|
||||
get "feedback", to: "pages#feedback"
|
||||
|
||||
resource :cookie_session, only: %i[update]
|
||||
resource :current_session, only: %i[update]
|
||||
|
||||
resource :registration, only: %i[new create]
|
||||
resources :sessions, only: %i[new create destroy]
|
||||
|
|
5
db/migrate/20250514214242_add_metadata_to_session.rb
Normal file
5
db/migrate/20250514214242_add_metadata_to_session.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddMetadataToSession < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
add_column :sessions, :data, :jsonb, default: {}
|
||||
end
|
||||
end
|
3
db/schema.rb
generated
3
db/schema.rb
generated
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.2].define(version: 2025_05_13_122703) do
|
||||
ActiveRecord::Schema[7.2].define(version: 2025_05_14_214242) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pgcrypto"
|
||||
enable_extension "plpgsql"
|
||||
|
@ -537,6 +537,7 @@ ActiveRecord::Schema[7.2].define(version: 2025_05_13_122703) do
|
|||
t.uuid "active_impersonator_session_id"
|
||||
t.datetime "subscribed_at"
|
||||
t.jsonb "prev_transaction_page_params", default: {}
|
||||
t.jsonb "data", default: {}
|
||||
t.index ["active_impersonator_session_id"], name: "index_sessions_on_active_impersonator_session_id"
|
||||
t.index ["user_id"], name: "index_sessions_on_user_id"
|
||||
end
|
||||
|
|
15
test/controllers/current_sessions_controller_test.rb
Normal file
15
test/controllers/current_sessions_controller_test.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
require "test_helper"
|
||||
|
||||
class CurrentSessionsControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
@user = users(:family_admin)
|
||||
sign_in @user
|
||||
end
|
||||
|
||||
test "can update the preferred tab for any namespace" do
|
||||
put current_session_url, params: { current_session: { tab_key: "accounts_sidebar_tab", tab_value: "asset" } }
|
||||
assert_response :success
|
||||
session = Session.order(updated_at: :desc).first
|
||||
assert_equal "asset", session.get_preferred_tab("accounts_sidebar_tab")
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue