Option to mass delete tags #2064

This commit is contained in:
James Cole 2019-12-28 09:59:41 +01:00
parent 156e2e79c7
commit 58c6ec8a8c
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
5 changed files with 110 additions and 74 deletions

View File

@ -62,6 +62,31 @@ class TagController extends Controller
); );
} }
/**
*
*/
public function massDestroy(Request $request)
{
$tags = $request->get('tags');
if (null === $tags || !is_array($tags)) {
session()->flash('info', (string)trans('firefly.select_tags_to_delete'));
return redirect(route('tags.index'));
}
$count = 0;
foreach ($tags as $tagId) {
$tagId = (int)$tagId;
$tag = $this->repository->findNull($tagId);
if (null !== $tag) {
$this->repository->destroy($tag);
$count++;
}
}
session()->flash('success', (string)trans('firefly.deleted_x_tags', ['count' => $count]));
return redirect(route('tags.index'));
}
/** /**
* Create a new tag. * Create a new tag.
* *

View File

@ -38,7 +38,7 @@ return [
| File extension for Twig view files. | File extension for Twig view files.
| |
*/ */
'extension' => 'twig', 'extension' => 'twig',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -53,11 +53,11 @@ return [
// When set to true, the generated templates have a __toString() method // When set to true, the generated templates have a __toString() method
// that you can use to display the generated nodes. // that you can use to display the generated nodes.
// default: false // default: false
'debug' => env('APP_DEBUG', false), 'debug' => env('APP_DEBUG', false),
// The charset used by the templates. // The charset used by the templates.
// default: utf-8 // default: utf-8
'charset' => 'utf-8', 'charset' => 'utf-8',
// The base template class to use for generated templates. // The base template class to use for generated templates.
// default: TwigBridge\Twig\Template // default: TwigBridge\Twig\Template
@ -66,26 +66,26 @@ return [
// An absolute path where to store the compiled templates, or false to disable caching. If null // An absolute path where to store the compiled templates, or false to disable caching. If null
// then the cache file path is used. // then the cache file path is used.
// default: cache file storage path // default: cache file storage path
'cache' => null, 'cache' => null,
// When developing with Twig, it's useful to recompile the template // When developing with Twig, it's useful to recompile the template
// whenever the source code changes. If you don't provide a value // whenever the source code changes. If you don't provide a value
// for the auto_reload option, it will be determined automatically based on the debug value. // for the auto_reload option, it will be determined automatically based on the debug value.
'auto_reload' => true, 'auto_reload' => true,
// If set to false, Twig will silently ignore invalid variables // If set to false, Twig will silently ignore invalid variables
// (variables and or attributes/methods that do not exist) and // (variables and or attributes/methods that do not exist) and
// replace them with a null value. When set to true, Twig throws an exception instead. // replace them with a null value. When set to true, Twig throws an exception instead.
// default: false // default: false
'strict_variables' => false, 'strict_variables' => false,
// If set to true, auto-escaping will be enabled by default for all templates. // If set to true, auto-escaping will be enabled by default for all templates.
// default: 'html' // default: 'html'
'autoescape' => 'html', 'autoescape' => 'html',
// A flag that indicates which optimizations to apply // A flag that indicates which optimizations to apply
// (default to -1 -- all optimizations are enabled; set it to 0 to disable) // (default to -1 -- all optimizations are enabled; set it to 0 to disable)
'optimizations' => -1, 'optimizations' => -1,
], ],
/* /*
@ -97,7 +97,7 @@ return [
| NOTE: these will be overwritten if you pass data into the view with the same key. | NOTE: these will be overwritten if you pass data into the view with the same key.
| |
*/ */
'globals' => [], 'globals' => [],
], ],
'extensions' => [ 'extensions' => [

View File

@ -482,49 +482,52 @@ return [
'rule_action_convert_transfer_choice' => 'Convert the transaction to a transfer', 'rule_action_convert_transfer_choice' => 'Convert the transaction to a transfer',
'rule_action_convert_transfer' => 'Convert the transaction to a transfer with ":action_value"', 'rule_action_convert_transfer' => 'Convert the transaction to a transfer with ":action_value"',
'rules_have_read_warning' => 'Have you read the warning?', 'rules_have_read_warning' => 'Have you read the warning?',
'apply_rule_warning' => 'Warning: running a rule(group) on a large selection of transactions could take ages, and it could time-out. If it does, the rule(group) will only be applied to an unknown subset of your transactions. This might leave your financial administration in tatters. Please be careful.', 'apply_rule_warning' => 'Warning: running a rule(group) on a large selection of transactions could take ages, and it could time-out. If it does, the rule(group) will only be applied to an unknown subset of your transactions. This might leave your financial administration in tatters. Please be careful.',
'rulegroup_for_bills_title' => 'Rule group for bills', 'rulegroup_for_bills_title' => 'Rule group for bills',
'rulegroup_for_bills_description' => 'A special rule group for all the rules that involve bills.', 'rulegroup_for_bills_description' => 'A special rule group for all the rules that involve bills.',
'rule_for_bill_title' => 'Auto-generated rule for bill ":name"', 'rule_for_bill_title' => 'Auto-generated rule for bill ":name"',
'rule_for_bill_description' => 'This rule is auto-generated to try to match bill ":name".', 'rule_for_bill_description' => 'This rule is auto-generated to try to match bill ":name".',
'create_rule_for_bill' => 'Create a new rule for bill ":name"', 'create_rule_for_bill' => 'Create a new rule for bill ":name"',
'create_rule_for_bill_txt' => 'You have just created a new bill called ":name", congratulations! Firefly III can automagically match new withdrawals to this bill. For example, whenever you pay your rent, the bill "rent" will be linked to the expense. This way, Firefly III can accurately show you which bills are due and which ones aren\'t. In order to do so, a new rule must be created. Firefly III has filled in some sensible defaults for you. Please make sure these are correct. If these values are correct, Firefly III will automatically link the correct withdrawal to the correct bill. Please check out the triggers to see if they are correct, and add some if they\'re wrong.', 'create_rule_for_bill_txt' => 'You have just created a new bill called ":name", congratulations! Firefly III can automagically match new withdrawals to this bill. For example, whenever you pay your rent, the bill "rent" will be linked to the expense. This way, Firefly III can accurately show you which bills are due and which ones aren\'t. In order to do so, a new rule must be created. Firefly III has filled in some sensible defaults for you. Please make sure these are correct. If these values are correct, Firefly III will automatically link the correct withdrawal to the correct bill. Please check out the triggers to see if they are correct, and add some if they\'re wrong.',
'new_rule_for_bill_title' => 'Rule for bill ":name"', 'new_rule_for_bill_title' => 'Rule for bill ":name"',
'new_rule_for_bill_description' => 'This rule marks transactions for bill ":name".', 'new_rule_for_bill_description' => 'This rule marks transactions for bill ":name".',
// tags // tags
'store_new_tag' => 'Store new tag', 'store_new_tag' => 'Store new tag',
'update_tag' => 'Update tag', 'update_tag' => 'Update tag',
'no_location_set' => 'No location set.', 'no_location_set' => 'No location set.',
'meta_data' => 'Meta data', 'meta_data' => 'Meta data',
'location' => 'Location', 'location' => 'Location',
'without_date' => 'Without date', 'without_date' => 'Without date',
'result' => 'Result', 'result' => 'Result',
'sums_apply_to_range' => 'All sums apply to the selected range', 'sums_apply_to_range' => 'All sums apply to the selected range',
'mapbox_api_key' => 'To use map, get an API key from <a href="https://www.mapbox.com/">Mapbox</a>. Open your <code>.env</code> file and enter this code after <code>MAPBOX_API_KEY=</code>.', 'mapbox_api_key' => 'To use map, get an API key from <a href="https://www.mapbox.com/">Mapbox</a>. Open your <code>.env</code> file and enter this code after <code>MAPBOX_API_KEY=</code>.',
'press_tag_location' => 'Right click or long press to set the tag\'s location.', 'press_tag_location' => 'Right click or long press to set the tag\'s location.',
'clear_location' => 'Clear location', 'clear_location' => 'Clear location',
'delete_all_selected_tags' => 'Delete all selected tags',
'select_tags_to_delete' => 'Don\'t forget to select some tags.',
'deleted_x_tags' => 'Deleted :count tag(s).',
// preferences // preferences
'pref_home_screen_accounts' => 'Home screen accounts', 'pref_home_screen_accounts' => 'Home screen accounts',
'pref_home_screen_accounts_help' => 'Which accounts should be displayed on the home page?', 'pref_home_screen_accounts_help' => 'Which accounts should be displayed on the home page?',
'pref_view_range' => 'View range', 'pref_view_range' => 'View range',
'pref_view_range_help' => 'Some charts are automatically grouped in periods. Your budgets will also be grouped in periods. What period would you prefer?', 'pref_view_range_help' => 'Some charts are automatically grouped in periods. Your budgets will also be grouped in periods. What period would you prefer?',
'pref_1D' => 'One day', 'pref_1D' => 'One day',
'pref_1W' => 'One week', 'pref_1W' => 'One week',
'pref_1M' => 'One month', 'pref_1M' => 'One month',
'pref_3M' => 'Three months (quarter)', 'pref_3M' => 'Three months (quarter)',
'pref_6M' => 'Six months', 'pref_6M' => 'Six months',
'pref_1Y' => 'One year', 'pref_1Y' => 'One year',
'pref_languages' => 'Languages', 'pref_languages' => 'Languages',
'pref_languages_help' => 'Firefly III supports several languages. Which one do you prefer?', 'pref_languages_help' => 'Firefly III supports several languages. Which one do you prefer?',
'pref_custom_fiscal_year' => 'Fiscal year settings', 'pref_custom_fiscal_year' => 'Fiscal year settings',
'pref_custom_fiscal_year_label' => 'Enabled', 'pref_custom_fiscal_year_label' => 'Enabled',
'pref_custom_fiscal_year_help' => 'In countries that use a financial year other than January 1 to December 31, you can switch this on and specify start / end days of the fiscal year', 'pref_custom_fiscal_year_help' => 'In countries that use a financial year other than January 1 to December 31, you can switch this on and specify start / end days of the fiscal year',
'pref_fiscal_year_start_label' => 'Fiscal year start date', 'pref_fiscal_year_start_label' => 'Fiscal year start date',
'pref_two_factor_auth' => '2-step verification', 'pref_two_factor_auth' => '2-step verification',
'pref_two_factor_auth_help' => 'When you enable 2-step verification (also known as two-factor authentication), you add an extra layer of security to your account. You sign in with something you know (your password) and something you have (a verification code). Verification codes are generated by an application on your phone, such as Authy or Google Authenticator.', 'pref_two_factor_auth_help' => 'When you enable 2-step verification (also known as two-factor authentication), you add an extra layer of security to your account. You sign in with something you know (your password) and something you have (a verification code). Verification codes are generated by an application on your phone, such as Authy or Google Authenticator.',
'pref_enable_two_factor_auth' => 'Enable 2-step verification', 'pref_enable_two_factor_auth' => 'Enable 2-step verification',
'pref_two_factor_auth_disabled' => '2-step verification code removed and disabled', 'pref_two_factor_auth_disabled' => '2-step verification code removed and disabled',
'pref_two_factor_auth_remove_it' => 'Don\'t forget to remove the account from your authentication app!', 'pref_two_factor_auth_remove_it' => 'Don\'t forget to remove the account from your authentication app!',

View File

@ -15,37 +15,44 @@
</p> </p>
</div> </div>
</div> </div>
{% for period,entries in clouds %} <form action="{{ route('tags.mass-destroy') }}" method="post">
{% if entries|length > 0 %} <input type="hidden" name="_token" value="{{ csrf_token() }}"/>
<div class="row"> {% for period,entries in clouds %}
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> {% if entries|length > 0 %}
<div class="box"> <div class="row">
<div class="box-header with-border"> <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<h3 class="box-title"> <div class="box">
{% if period == 'no-date' %}{{ 'without_date'|_ }}{% else %}{{ period }}{% endif %} <div class="box-header with-border">
</h3> <h3 class="box-title">
</div> {% if period == 'no-date' %}{{ 'without_date'|_ }}{% else %}{{ period }}{% endif %}
<div class="box-body"> </h3>
<p class="tagcloud"> </div>
{% for tagInfo in entries %} <div class="box-body">
<a style="font-size:{{ tagInfo.size }}px;" class="label label-success" <p class="tagcloud">
title="{{ tagInfo.created_at.formatLocalized(monthAndDayFormat) }}" {% for tagInfo in entries %}
href="{{ route('tags.show',tagInfo.id) }}"><i class="fa fa-fw fa-tag"></i> {{ tagInfo.tag }}</a> <input type="checkbox" name="tags[]" value="{{ tagInfo.id }}">
{% endfor %} <a style="font-size:{{ tagInfo.size }}px;" class="label label-success"
</p> title="{{ tagInfo.created_at.formatLocalized(monthAndDayFormat) }}"
href="{{ route('tags.show',tagInfo.id) }}"><i class="fa fa-fw fa-tag"></i> {{ tagInfo.tag }}</a>
{% endfor %}
</p>
</div>
</div> </div>
</div> </div>
</div> </div>
{% endif %}
{% endfor %}
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<p>
<a class="btn btn-success" href="{{ route('tags.create') }}"><i class="fa fa-plus fa-fw"></i> {{ ('no_tags_create_default')|_ }}</a>
<button type="submit" class="btn pull-right btn-danger" onclick="return confirm('{{ 'are_you_sure'|_|escape('js') }}');">
<i class="fa fa-fw fa-trash"></i> {{ 'delete_all_selected_tags'|_ }}
</button>
</p>
</div> </div>
{% endif %}
{% endfor %}
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<p>
<a class="btn btn-success" href="{{ route('tags.create') }}"><i class="fa fa-plus fa-fw"></i> {{ ('no_tags_create_default')|_ }}</a>
</p>
</div> </div>
</div> </form>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -937,6 +937,7 @@ Route::group(
Route::post('store', ['uses' => 'TagController@store', 'as' => 'store']); Route::post('store', ['uses' => 'TagController@store', 'as' => 'store']);
Route::post('update/{tag}', ['uses' => 'TagController@update', 'as' => 'update']); Route::post('update/{tag}', ['uses' => 'TagController@update', 'as' => 'update']);
Route::post('destroy/{tag}', ['uses' => 'TagController@destroy', 'as' => 'destroy']); Route::post('destroy/{tag}', ['uses' => 'TagController@destroy', 'as' => 'destroy']);
Route::post('mass-destroy', ['uses' => 'TagController@massDestroy', 'as' => 'mass-destroy']);
} }
); );