feat: multi tenancy support

This commit is contained in:
Herculino Trotta
2025-03-08 12:03:17 -03:00
parent c7d70a1748
commit 020dd74f80
79 changed files with 2401 additions and 399 deletions
@@ -2,13 +2,13 @@
<div class="container px-md-3 py-3 column-gap-5">
<div class="tw-text-3xl fw-bold font-monospace tw-w-full mb-3">
{% spaceless %}
<div>{% translate 'Account Groups' %}<span>
<div>{% translate 'Account Groups' %}<span>
<a class="text-decoration-none tw-text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
hx-get="{% url 'account_group_add' %}"
hx-target="#generic-offcanvas">
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
hx-get="{% url 'account_group_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>
</span></div>
{% endspaceless %}
@@ -17,46 +17,64 @@
<div class="card">
<div class="card-body table-responsive">
{% if account_groups %}
<c-config.search></c-config.search>
<table class="table table-hover">
<thead>
<c-config.search></c-config.search>
<table class="table table-hover">
<thead>
<tr>
<th scope="col" class="col-auto"></th>
<th scope="col" class="col">{% translate 'Name' %}</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
{% for account_group in account_groups %}
<tr class="account_group">
<td class="col-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
hx-get="{% url 'account_group_edit' pk=account_group.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
hx-delete="{% url 'account_group_delete' pk=account_group.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
</div>
</td>
<td class="col">{{ account_group.name }}</td>
</tr>
<tr class="account_group">
<td class="col-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
hx-get="{% url 'account_group_edit' pk=account_group.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
hx-delete="{% url 'account_group_delete' pk=account_group.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
{% if not account_group.owner %}
<a class="btn btn-secondary btn-sm text-warning"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
hx-get="{% url 'account_group_take_ownership' pk=account_group.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
{% if user == account_group.owner %}
<a class="btn btn-secondary btn-sm text-primary"
role="button"
hx-target="#generic-offcanvas"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
hx-get="{% url 'account_group_share_settings' pk=account_group.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}
</div>
</td>
<td class="col">{{ account_group.name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</tbody>
</table>
{% else %}
<c-msg.empty title="{% translate "No account groups" %}" remove-padding></c-msg.empty>
<c-msg.empty title="{% translate "No account groups" %}" remove-padding></c-msg.empty>
{% endif %}
</div>
</div>
@@ -0,0 +1,11 @@
{% extends 'extends/offcanvas.html' %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{% translate 'Share settings' %}{% endblock %}
{% block body %}
<form hx-post="{% url "account_groups_share_settings" pk=object.id %}" hx-target="#generic-offcanvas" novalidate>
{% crispy form %}
</form>
{% endblock %}
@@ -53,6 +53,24 @@
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
{% if not account.owner %}
<a class="btn btn-secondary btn-sm text-primary"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
hx-get="{% url 'account_take_ownership' pk=account.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
{% if user == account.owner %}
<a class="btn btn-secondary btn-sm text-primary"
role="button"
hx-target="#generic-offcanvas"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
hx-get="{% url 'account_share_settings' pk=account.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}
</div>
</td>
<td class="col">{{ account.name }}</td>
@@ -0,0 +1,11 @@
{% extends 'extends/offcanvas.html' %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{% translate 'Share settings' %}{% endblock %}
{% block body %}
<form hx-post="{% url "account_share_settings" pk=object.id %}" hx-target="#generic-offcanvas" novalidate>
{% crispy form %}
</form>
{% endblock %}
@@ -0,0 +1,11 @@
{% extends 'extends/offcanvas.html' %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{% translate 'Share settings' %}{% endblock %}
{% block body %}
<form hx-post="{% url "category_share_settings" pk=object.id %}" hx-target="#generic-offcanvas" novalidate>
{% crispy form %}
</form>
{% endblock %}
@@ -42,6 +42,24 @@
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
{% if not category.owner %}
<a class="btn btn-secondary btn-sm text-primary"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
hx-get="{% url 'category_take_ownership' category_id=category.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
{% if user == category.owner %}
<a class="btn btn-secondary btn-sm text-primary"
role="button"
hx-target="#generic-offcanvas"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
hx-get="{% url 'category_share_settings' pk=category.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}
</div>
</td>
<td class="col">{{ category.name }}</td>
+52 -33
View File
@@ -17,40 +17,59 @@
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 row-cols-xl-4 gy-3 gx-3">
{% for strategy in strategies %}
<div class="col">
<div class="card h-100">
<div class="card-header">
<span class="badge rounded-pill text-bg-secondary">{{ strategy.payment_currency.name }}</span> x <span class="badge rounded-pill text-bg-secondary">{{ strategy.target_currency.name }}</span>
</div>
<a href="{% url 'dca_strategy_detail_index' strategy_id=strategy.id %}" hx-boost="true" class="text-decoration-none card-body">
<div class="">
<div class="card-title tw-text-xl">{{ strategy.name }}</div>
<div class="card-text tw-text-gray-400">{{ strategy.notes }}</div>
</div>
</a>
<div class="card-footer text-end">
<a class="text-decoration-none tw-text-gray-400 p-1"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
hx-get="{% url 'dca_strategy_edit' strategy_id=strategy.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i>
</a>
<a class="text-danger text-decoration-none p-1"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
hx-delete="{% url 'dca_strategy_delete' strategy_id=strategy.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal">
<i class="fa-solid fa-trash fa-fw"></i>
</a>
</div>
<div class="card h-100">
<div class="card-header">
<span class="badge rounded-pill text-bg-secondary">{{ strategy.payment_currency.name }}</span> x <span
class="badge rounded-pill text-bg-secondary">{{ strategy.target_currency.name }}</span>
</div>
<a href="{% url 'dca_strategy_detail_index' strategy_id=strategy.id %}" hx-boost="true"
class="text-decoration-none card-body">
<div class="">
<div class="card-title tw-text-xl">{{ strategy.name }}</div>
<div class="card-text tw-text-gray-400">{{ strategy.notes }}</div>
</div>
</a>
<div class="card-footer text-end">
<a class="text-decoration-none tw-text-gray-400 p-1"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
hx-get="{% url 'dca_strategy_edit' strategy_id=strategy.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i>
</a>
<a class="text-danger text-decoration-none p-1"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
hx-delete="{% url 'dca_strategy_delete' strategy_id=strategy.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal">
<i class="fa-solid fa-trash fa-fw"></i>
</a>
{% if not strategy.owner %}
<a class="text-primary text-decoration-none p-1"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
hx-get="{% url 'dca_strategy_take_ownership' strategy_id=strategy.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
{% if user == strategy.owner %}
<a class="text-primary text-decoration-none p-1"
role="button"
hx-target="#generic-offcanvas"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
hx-get="{% url 'dca_strategy_share_settings' pk=strategy.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
@@ -0,0 +1,11 @@
{% extends 'extends/offcanvas.html' %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{% translate 'Share settings' %}{% endblock %}
{% block body %}
<form hx-post="{% url "dca_strategy_share_settings" pk=object.id %}" hx-target="#generic-offcanvas" novalidate>
{% crispy form %}
</form>
{% endblock %}
@@ -0,0 +1,11 @@
{% extends 'extends/offcanvas.html' %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{% translate 'Share settings' %}{% endblock %}
{% block body %}
<form hx-post="{% url "entity_share_settings" pk=object.id %}" hx-target="#generic-offcanvas" novalidate>
{% crispy form %}
</form>
{% endblock %}
+63 -45
View File
@@ -6,50 +6,68 @@
<div class="show-loading" hx-get="{% url 'entities_table_archived' %}" hx-trigger="updated from:window"
hx-swap="outerHTML">
{% endif %}
{% if entities %}
<div class="table-responsive">
<c-config.search></c-config.search>
<table class="table table-hover">
<thead>
<tr>
<th scope="col" class="col-auto"></th>
<th scope="col" class="col">{% translate 'Name' %}</th>
{% if entities %}
<div class="table-responsive">
<c-config.search></c-config.search>
<table class="table table-hover">
<thead>
<tr>
<th scope="col" class="col-auto"></th>
<th scope="col" class="col">{% translate 'Name' %}</th>
</tr>
</thead>
<tbody>
{% for entity in entities %}
<tr class="entity">
<td class="col-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm"
role="button"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
hx-get="{% url 'entity_edit' entity_id=entity.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger"
role="button"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
hx-delete="{% url 'entity_delete' entity_id=entity.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
{% if not entity.owner %}
<a class="btn btn-secondary btn-sm text-warning"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
hx-get="{% url 'entity_take_ownership' entity_id=entity.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
{% if user == entity.owner %}
<a class="btn btn-secondary btn-sm text-primary"
role="button"
hx-target="#generic-offcanvas"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
hx-get="{% url 'entity_share_settings' pk=entity.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}
</div>
</td>
<td class="col">{{ entity.name }}</td>
</tr>
</thead>
<tbody>
{% for entity in entities %}
<tr class="entity">
<td class="col-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm"
role="button"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
hx-get="{% url 'entity_edit' entity_id=entity.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger"
role="button"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
hx-delete="{% url 'entity_delete' entity_id=entity.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
</div>
</td>
<td class="col">{{ entity.name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<c-msg.empty title="{% translate "No entities" %}" remove-padding></c-msg.empty>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<c-msg.empty title="{% translate "No entities" %}" remove-padding></c-msg.empty>
{% endif %}
</div>
+2
View File
@@ -132,8 +132,10 @@
href="{% url 'rules_index' %}">{% translate 'Rules' %}</a></li>
<li><a class="dropdown-item {% active_link views='import_profiles_index' %}"
href="{% url 'import_profiles_index' %}">{% translate 'Import' %} <span class="badge text-bg-primary">beta</span></a></li>
{% if user.is_superuser %}
<li><a class="dropdown-item {% active_link views='export_index' %}"
href="{% url 'export_index' %}">{% translate 'Export and Restore' %}</a></li>
{% endif %}
<li><a class="dropdown-item {% active_link views='automatic_exchange_rates_index' %}"
href="{% url 'automatic_exchange_rates_index' %}">{% translate 'Automatic Exchange Rates' %}</a></li>
<li>
+71 -51
View File
@@ -2,13 +2,13 @@
<div class="container px-md-3 py-3 column-gap-5">
<div class="tw-text-3xl fw-bold font-monospace tw-w-full mb-3">
{% spaceless %}
<div>{% translate 'Rules' %}<span>
<div>{% translate 'Rules' %}<span>
<a class="text-decoration-none tw-text-2xl p-1 category-action"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
hx-get="{% url 'transaction_rule_add' %}"
hx-target="#generic-offcanvas">
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Add" %}"
hx-get="{% url 'transaction_rule_add' %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-circle-plus fa-fw"></i></a>
</span></div>
{% endspaceless %}
@@ -17,59 +17,79 @@
<div class="card">
<div class="card-body table-responsive">
{% if transaction_rules %}
<c-config.search></c-config.search>
<table class="table table-hover">
<thead>
<c-config.search></c-config.search>
<table class="table table-hover">
<thead>
<tr>
<th scope="col" class="col-auto"></th>
<th scope="col" class="col-auto"></th>
<th scope="col" class="col">{% translate 'Name' %}</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
{% for rule in transaction_rules %}
<tr class="transaction_rule">
<td class="col-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "View" %}"
hx-get="{% url 'transaction_rule_view' transaction_rule_id=rule.id %}"
hx-target="#persistent-generic-offcanvas-left">
<i class="fa-solid fa-eye fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
hx-delete="{% url 'transaction_rule_delete' transaction_rule_id=rule.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
</div>
</td>
<td class="col-auto">
<a class="text-decoration-none"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% if rule.active %}{% translate "Deactivate" %}{% else %}{% translate "Activate" %}{% endif %}"
hx-get="{% url 'transaction_rule_toggle_activity' transaction_rule_id=rule.id %}">
{% if rule.active %}<i class="fa-solid fa-toggle-on tw-text-green-400"></i>{% else %}<i class="fa-solid fa-toggle-off tw-text-red-400"></i>{% endif %}
</a>
</td>
<td class="col">
<div>{{ rule.name }}</div>
<div class="tw-text-gray-400">{{ rule.description }}</div>
</td>
</tr>
<tr class="transaction_rule">
<td class="col-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "View" %}"
hx-get="{% url 'transaction_rule_view' transaction_rule_id=rule.id %}"
hx-target="#persistent-generic-offcanvas-left">
<i class="fa-solid fa-eye fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Delete" %}"
hx-delete="{% url 'transaction_rule_delete' transaction_rule_id=rule.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
{% if not rule.owner %}
<a class="btn btn-secondary btn-sm text-warning"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
hx-get="{% url 'transaction_rule_take_ownership' transaction_rule_id=rule.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
{% if user == rule.owner %}
<a class="btn btn-secondary btn-sm text-primary"
role="button"
hx-target="#generic-offcanvas"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
hx-get="{% url 'transaction_rule_share_settings' pk=rule.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}
</div>
</td>
<td class="col-auto">
<a class="text-decoration-none"
role="button"
data-bs-toggle="tooltip"
data-bs-title="
{% if rule.active %}{% translate "Deactivate" %}{% else %}{% translate "Activate" %}{% endif %}"
hx-get="{% url 'transaction_rule_toggle_activity' transaction_rule_id=rule.id %}">
{% if rule.active %}<i class="fa-solid fa-toggle-on tw-text-green-400"></i>{% else %}
<i class="fa-solid fa-toggle-off tw-text-red-400"></i>{% endif %}
</a>
</td>
<td class="col">
<div>{{ rule.name }}</div>
<div class="tw-text-gray-400">{{ rule.description }}</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</tbody>
</table>
{% else %}
<c-msg.empty title="{% translate "No rules" %}" remove-padding></c-msg.empty>
<c-msg.empty title="{% translate "No rules" %}" remove-padding></c-msg.empty>
{% endif %}
</div>
</div>
+11
View File
@@ -0,0 +1,11 @@
{% extends 'extends/offcanvas.html' %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{% translate 'Share settings' %}{% endblock %}
{% block body %}
<form hx-post="{% url "transaction_rule_share_settings" pk=object.id %}" hx-target="#generic-offcanvas" novalidate>
{% crispy form %}
</form>
{% endblock %}
+11
View File
@@ -0,0 +1,11 @@
{% extends 'extends/offcanvas.html' %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}{% translate 'Share settings' %}{% endblock %}
{% block body %}
<form hx-post="{% url "tag_share_settings" pk=object.id %}" hx-target="#generic-offcanvas" novalidate>
{% crispy form %}
</form>
{% endblock %}
+63 -45
View File
@@ -6,50 +6,68 @@
<div class="show-loading" hx-get="{% url 'tags_table_archived' %}" hx-trigger="updated from:window"
hx-swap="outerHTML">
{% endif %}
{% if tags %}
<div class="table-responsive">
<c-config.search></c-config.search>
<table class="table table-hover">
<thead>
<tr>
<th scope="col" class="col-auto"></th>
<th scope="col" class="col">{% translate 'Name' %}</th>
{% if tags %}
<div class="table-responsive">
<c-config.search></c-config.search>
<table class="table table-hover">
<thead>
<tr>
<th scope="col" class="col-auto"></th>
<th scope="col" class="col">{% translate 'Name' %}</th>
</tr>
</thead>
<tbody>
{% for tag in tags %}
<tr class="tag">
<td class="col-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm"
role="button"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
hx-get="{% url 'tag_edit' tag_id=tag.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger"
role="button"
data-bs-toggle="tooltip"
hx-swap="innerHTML"
data-bs-title="{% translate "Delete" %}"
hx-delete="{% url 'tag_delete' tag_id=tag.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
{% if not tag.owner %}
<a class="btn btn-secondary btn-sm text-warning"
role="button"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Take ownership" %}"
hx-get="{% url 'tag_take_ownership' tag_id=tag.id %}">
<i class="fa-solid fa-crown fa-fw"></i></a>
{% endif %}
{% if user == tag.owner %}
<a class="btn btn-secondary btn-sm text-primary"
role="button"
hx-target="#generic-offcanvas"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Share" %}"
hx-get="{% url 'tag_share_settings' pk=tag.id %}">
<i class="fa-solid fa-share fa-fw"></i></a>
{% endif %}
</div>
</td>
<td class="col">{{ tag.name }}</td>
</tr>
</thead>
<tbody>
{% for tag in tags %}
<tr class="tag">
<td class="col-auto">
<div class="btn-group" role="group" aria-label="{% translate 'Actions' %}">
<a class="btn btn-secondary btn-sm"
role="button"
hx-swap="innerHTML"
data-bs-toggle="tooltip"
data-bs-title="{% translate "Edit" %}"
hx-get="{% url 'tag_edit' tag_id=tag.id %}"
hx-target="#generic-offcanvas">
<i class="fa-solid fa-pencil fa-fw"></i></a>
<a class="btn btn-secondary btn-sm text-danger"
role="button"
data-bs-toggle="tooltip"
hx-swap="innerHTML"
data-bs-title="{% translate "Delete" %}"
hx-delete="{% url 'tag_delete' tag_id=tag.id %}"
hx-trigger='confirmed'
data-bypass-on-ctrl="true"
data-title="{% translate "Are you sure?" %}"
data-text="{% translate "You won't be able to revert this!" %}"
data-confirm-text="{% translate "Yes, delete it!" %}"
_="install prompt_swal"><i class="fa-solid fa-trash fa-fw"></i></a>
</div>
</td>
<td class="col">{{ tag.name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<c-msg.empty title="{% translate "No tags" %}" remove-padding></c-msg.empty>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<c-msg.empty title="{% translate "No tags" %}" remove-padding></c-msg.empty>
{% endif %}
</div>