feat(export): CSV export scope — All / current filter / date range
Finishes the transactions-export partial. The dialog now offers three scopes: - All transactions (unchanged default; exported with no copy). - Current History filter — the Transactions tab publishes a TxFilterSnapshot of the visible legs (a merged autoshield row contributes both its send+receive legs, so the CSV stays a per-leg record like an unfiltered export); the radio is disabled with an explanation when no filter is active, and a snapshot that predates the current tx list (revision mismatch) is refused rather than silently exporting everything. - Date range (YYYY-MM-DD, inclusive end-of-day; pending/dateless rows excluded with a note; invalid/reversed dates blocked inline). The live count reflects what will actually be exported. formatTransactionsCsv and the atomic write are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,11 @@ namespace ui {
|
||||
|
||||
using namespace material;
|
||||
|
||||
// Latest History-tab filter snapshot, published from the filtered-list rebuild below. Used by the
|
||||
// transactions CSV export to offer "export only the current filter".
|
||||
static TxFilterSnapshot s_filter_snapshot;
|
||||
const TxFilterSnapshot& GetTransactionsFilterSnapshot() { return s_filter_snapshot; }
|
||||
|
||||
static std::string TrId(const char* key, const char* id) {
|
||||
return std::string(TR(key)) + "##" + id;
|
||||
}
|
||||
@@ -565,6 +570,35 @@ void RenderTransactionsTab(App* app)
|
||||
s_filtered_search = search_str;
|
||||
s_filtered_chat_rev = chatRev;
|
||||
s_filtered_valid = true;
|
||||
|
||||
// Publish a snapshot of the visible set for "export current filter". A merged autoshield row
|
||||
// contributes BOTH original legs, so the CSV stays a per-leg record like an unfiltered export.
|
||||
s_filter_snapshot.indices.clear();
|
||||
s_filter_snapshot.indices.reserve(s_filtered_cache.size() * 2);
|
||||
for (size_t fi : s_filtered_cache) {
|
||||
const auto& dtx = display_txns[fi];
|
||||
if (dtx.is_shield) {
|
||||
if (dtx.send_idx >= 0) s_filter_snapshot.indices.push_back(static_cast<size_t>(dtx.send_idx));
|
||||
if (dtx.recv_idx >= 0) s_filter_snapshot.indices.push_back(static_cast<size_t>(dtx.recv_idx));
|
||||
} else if (dtx.orig_idx >= 0) {
|
||||
s_filter_snapshot.indices.push_back(static_cast<size_t>(dtx.orig_idx));
|
||||
}
|
||||
}
|
||||
std::sort(s_filter_snapshot.indices.begin(), s_filter_snapshot.indices.end());
|
||||
s_filter_snapshot.active = (type_filter != 0 || !search_str.empty());
|
||||
s_filter_snapshot.txRevision = contentKey;
|
||||
s_filter_snapshot.valid = true;
|
||||
{
|
||||
const char* typeNames[] = { "", TR("sent_filter"), TR("received_filter"),
|
||||
TR("mined_filter"), TR("chat_filter") };
|
||||
std::string desc = (type_filter >= 1 && type_filter <= 4) ? typeNames[type_filter] : "";
|
||||
if (!search_str.empty()) {
|
||||
if (!desc.empty()) desc += ", ";
|
||||
desc += "\"" + search_str + "\"";
|
||||
}
|
||||
if (desc.empty()) desc = TR("all_filter");
|
||||
s_filter_snapshot.description = desc;
|
||||
}
|
||||
}
|
||||
const std::vector<size_t>& filtered_indices = s_filtered_cache;
|
||||
filtered_count = static_cast<int>(filtered_indices.size());
|
||||
|
||||
Reference in New Issue
Block a user