mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-10 16:05:22 +02:00
Add change name rule for transaction
This commit is contained in:
parent
d8e34cf791
commit
ca8cf82037
6 changed files with 114 additions and 17 deletions
|
@ -19,10 +19,13 @@ export default class extends Controller {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (actionExecutor.type === "select") {
|
if (actionExecutor.type === "select") {
|
||||||
this.#updateValueSelectFor(actionExecutor);
|
this.#convertToSelect(actionExecutor);
|
||||||
this.#showAndEnableValueSelect();
|
this.#showActionValue();
|
||||||
|
} else if (actionExecutor.type === "text") {
|
||||||
|
this.#convertToTextInput();
|
||||||
|
this.#showActionValue();
|
||||||
} else {
|
} else {
|
||||||
this.#hideAndDisableValueSelect();
|
this.#hideActionValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,26 +33,62 @@ export default class extends Controller {
|
||||||
return this.actionValueTarget.querySelector("select");
|
return this.actionValueTarget.querySelector("select");
|
||||||
}
|
}
|
||||||
|
|
||||||
#showAndEnableValueSelect() {
|
get valueInputEl() {
|
||||||
|
return this.actionValueTarget.querySelector("input");
|
||||||
|
}
|
||||||
|
|
||||||
|
#showActionValue() {
|
||||||
this.actionValueTarget.classList.remove("hidden");
|
this.actionValueTarget.classList.remove("hidden");
|
||||||
this.valueSelectEl.disabled = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#hideAndDisableValueSelect() {
|
#hideActionValue() {
|
||||||
this.actionValueTarget.classList.add("hidden");
|
this.actionValueTarget.classList.add("hidden");
|
||||||
this.valueSelectEl.disabled = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#updateValueSelectFor(actionExecutor) {
|
|
||||||
// Clear existing options
|
|
||||||
this.valueSelectEl.innerHTML = "";
|
|
||||||
|
|
||||||
// Add new options
|
#convertToTextInput() {
|
||||||
|
// If we already have a text input, do nothing
|
||||||
|
if (this.valueInputEl && this.valueInputEl.type === "text") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert select to text input
|
||||||
|
const valueField = this.valueSelectEl || this.valueInputEl;
|
||||||
|
|
||||||
|
if (valueField) {
|
||||||
|
const textInput = document.createElement("input");
|
||||||
|
textInput.type = "text";
|
||||||
|
textInput.name = valueField.name;
|
||||||
|
textInput.id = valueField.id;
|
||||||
|
textInput.placeholder = "Enter a value";
|
||||||
|
textInput.className = "form-field__input";
|
||||||
|
|
||||||
|
valueField.replaceWith(textInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts a field to a select with new options based on the action executor
|
||||||
|
// This includes a current select with different options
|
||||||
|
#convertToSelect(actionExecutor) {
|
||||||
|
const valueField = this.valueInputEl || this.valueSelectEl;
|
||||||
|
|
||||||
|
if (!valueField) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectInput = document.createElement("select");
|
||||||
|
selectInput.name = valueField.name;
|
||||||
|
selectInput.id = valueField.id;
|
||||||
|
selectInput.className = "form-field__input";
|
||||||
|
|
||||||
|
// Add options
|
||||||
for (const option of actionExecutor.options) {
|
for (const option of actionExecutor.options) {
|
||||||
const optionEl = document.createElement("option");
|
const optionEl = document.createElement("option");
|
||||||
optionEl.value = option[1];
|
optionEl.value = option[1];
|
||||||
optionEl.textContent = option[0];
|
optionEl.textContent = option[0];
|
||||||
this.valueSelectEl.appendChild(optionEl);
|
selectInput.appendChild(optionEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
valueField.replaceWith(selectInput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
class Rule::ActionExecutor
|
class Rule::ActionExecutor
|
||||||
TYPES = [ "select", "function" ]
|
TYPES = [ "select", "function", "text" ]
|
||||||
|
|
||||||
def initialize(rule)
|
def initialize(rule)
|
||||||
@rule = rule
|
@rule = rule
|
||||||
|
|
29
app/models/rule/action_executor/set_transaction_name.rb
Normal file
29
app/models/rule/action_executor/set_transaction_name.rb
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
class Rule::ActionExecutor::SetTransactionName < Rule::ActionExecutor
|
||||||
|
def type
|
||||||
|
"text"
|
||||||
|
end
|
||||||
|
|
||||||
|
def options
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute(transaction_scope, value: nil, ignore_attribute_locks: false)
|
||||||
|
return if value.blank?
|
||||||
|
|
||||||
|
scope = transaction_scope
|
||||||
|
unless ignore_attribute_locks
|
||||||
|
scope = scope.enrichable(:name)
|
||||||
|
end
|
||||||
|
|
||||||
|
scope.each do |txn|
|
||||||
|
Rule.transaction do
|
||||||
|
txn.entry.log_enrichment!(
|
||||||
|
attribute_name: "name",
|
||||||
|
attribute_value: value,
|
||||||
|
source: "rule"
|
||||||
|
)
|
||||||
|
txn.entry.update!(name: value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -14,7 +14,8 @@ class Rule::Registry::TransactionResource < Rule::Registry
|
||||||
def action_executors
|
def action_executors
|
||||||
enabled_executors = [
|
enabled_executors = [
|
||||||
Rule::ActionExecutor::SetTransactionCategory.new(rule),
|
Rule::ActionExecutor::SetTransactionCategory.new(rule),
|
||||||
Rule::ActionExecutor::SetTransactionTags.new(rule)
|
Rule::ActionExecutor::SetTransactionTags.new(rule),
|
||||||
|
Rule::ActionExecutor::SetTransactionName.new(rule)
|
||||||
]
|
]
|
||||||
|
|
||||||
if ai_enabled?
|
if ai_enabled?
|
||||||
|
|
|
@ -2,21 +2,28 @@
|
||||||
|
|
||||||
<% action = form.object %>
|
<% action = form.object %>
|
||||||
<% rule = action.rule %>
|
<% rule = action.rule %>
|
||||||
<% needs_value = action.executor.type == "select" %>
|
<% action_type = action.executor.type %>
|
||||||
|
|
||||||
<li data-controller="rule--actions" data-rule--actions-action-executors-value="<%= rule.action_executors.to_json %>" class="flex items-center gap-3">
|
<li data-controller="rule--actions" data-rule--actions-action-executors-value="<%= rule.action_executors.to_json %>" class="flex items-center gap-3">
|
||||||
<%= form.hidden_field :_destroy, value: false, data: { rule__actions_target: "destroyField" } %>
|
<%= form.hidden_field :_destroy, value: false, data: { rule__actions_target: "destroyField" } %>
|
||||||
|
|
||||||
<div class="grow flex gap-2 items-center h-full">
|
<div class="grow flex gap-2 items-center h-full">
|
||||||
|
|
||||||
<div class="grow">
|
<div class="grow">
|
||||||
<%= form.select :action_type, rule.action_executors.map { |executor| [ executor.label, executor.key ] }, {}, data: { action: "rule--actions#handleActionTypeChange" } %>
|
<%= form.select :action_type, rule.action_executors.map { |executor| [ executor.label, executor.key ] }, {}, data: { action: "rule--actions#handleActionTypeChange" } %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= tag.div class: class_names("min-w-1/2 flex items-center gap-2", "hidden" => !needs_value),
|
<%= tag.div class: class_names("min-w-1/2 flex items-center gap-2"),
|
||||||
data: { rule__actions_target: "actionValue" } do %>
|
data: { rule__actions_target: "actionValue" } do %>
|
||||||
<span class="font-medium uppercase text-xs">to</span>
|
<span class="font-medium uppercase text-xs">to</span>
|
||||||
<%= form.select :value, action.options || [], {}, disabled: !needs_value %>
|
<% case action_type
|
||||||
|
when "select" %>
|
||||||
|
<%= form.select :value, action.options || [], {} %>
|
||||||
|
<% when "text" %>
|
||||||
|
<%= form.text_field :value, placeholder: "Enter a value", class: "form-field__input" %>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button"
|
<button type="button"
|
||||||
|
|
|
@ -58,4 +58,25 @@ class Rule::ActionTest < ActiveSupport::TestCase
|
||||||
assert_equal [ tag ], transaction.reload.tags
|
assert_equal [ tag ], transaction.reload.tags
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "set_transaction_name" do
|
||||||
|
new_name = "Renamed Transaction"
|
||||||
|
|
||||||
|
# Does not modify transactions that are locked (user edited them)
|
||||||
|
@txn1.lock!(:name)
|
||||||
|
|
||||||
|
action = Rule::Action.new(
|
||||||
|
rule: @transaction_rule,
|
||||||
|
action_type: "set_transaction_name",
|
||||||
|
value: new_name
|
||||||
|
)
|
||||||
|
|
||||||
|
action.apply(@rule_scope)
|
||||||
|
|
||||||
|
assert_not_equal new_name, @txn1.reload.entry.name
|
||||||
|
|
||||||
|
[ @txn2, @txn3 ].each do |transaction|
|
||||||
|
assert_equal new_name, transaction.reload.entry.name
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue