Add ability to delete invite codes (#153)

* Add ability to delete invite codes

Implemented destroy action in InviteCodesController and updated routes to support invite code deletion. Updated invite code partial to include a delete button and improved styling. Also refactored the generate tokens button in invite code settings to use DS::Button.

* Show advanced settings only to admin users

Updated the settings navigation to display the advanced section only for admin users. Also improved handling of hidden elements in the invite code CSS.
This commit is contained in:
Mark Hendriksen
2025-09-22 09:29:23 +02:00
committed by GitHub
parent b4aa5194e8
commit f3fecc40ba
6 changed files with 54 additions and 28 deletions

View File

@@ -172,4 +172,16 @@
&::-webkit-scrollbar-thumb:hover {
background: #a6a6a6;
}
}
.invite_code [data-clipboard-target="iconDefault"],
.invite_code [data-clipboard-target="iconSuccess"] {
transition: opacity 0.2s;
opacity: 1;
}
.invite_code .hidden {
display: none !important;
opacity: 0;
pointer-events: none;
position: absolute;
}

View File

@@ -11,6 +11,12 @@ class InviteCodesController < ApplicationController
redirect_back_or_to invite_codes_path, notice: "Code generated"
end
def destroy
code = InviteCode.find(params[:id])
code.destroy
redirect_back_or_to invite_codes_path, notice: "Code deleted"
end
private
def ensure_self_hosted

View File

@@ -1,16 +1,21 @@
<%# app/views/invite_codes/_invite_code.html.erb %>
<div class="invite_code pt-2">
<div class="flex items-center justify-between p-2 w-1/2 bg-gray-25 rounded-md" data-controller="clipboard">
<div class="flex items-center justify-between p-2 w-1/2 bg-inverse rounded-md" data-controller="clipboard">
<div>
<span data-clipboard-target="source" class="text-sm font-medium"><%= invite_code.token %></span>
<span data-clipboard-target="source" class="text-inverse text-sm font-medium"><%= invite_code.token %></span>
</div>
<div class="flex items-center gap-2">
<button data-action="clipboard#copy" class="shrink-0 z-10 inline-flex items-center px-1 text-sm text-secondary font-sm text-center" type="button">
<span data-clipboard-target="iconDefault">
<%= icon "copy" %>
</span>
<span class="hidden inline-flex items-center" data-clipboard-target="iconSuccess">
<%= icon "check" %>
</span>
</button>
<%= button_to invite_code_path(invite_code), method: :delete, data: { confirm: "Are you sure?" }, class: "ml-2 text-red-600 text-xs" do %>
<%= icon("trash-2", size: "sm", class: "inline mr-1") %>
<% end %>
</div>
<button data-action="clipboard#copy" class="shrink-0 z-10 inline-flex items-center px-1 text-sm text-secondary font-sm text-center" type="button">
<span data-clipboard-target="iconDefault">
<%= icon "copy" %>
</span>
<span class="hidden inline-flex items-center" data-clipboard-target="iconSuccess">
<%= icon "check" %>
</span>
</button>
</div>
</div>

View File

@@ -20,16 +20,18 @@ nav_sections = [
{ label: t(".merchants_label"), path: family_merchants_path, icon: "store" }
]
},
{
header: t(".advanced_section_title"),
items: [
{ label: t(".ai_prompts_label"), path: settings_ai_prompts_path, icon: "bot" },
{ label: t(".api_keys_label"), path: settings_api_key_path, icon: "key" },
{ label: t(".self_hosting_label"), path: settings_hosting_path, icon: "database", if: self_hosted? },
{ label: t(".imports_label"), path: imports_path, icon: "download" },
{ label: "SimpleFin", path: simplefin_items_path, icon: "building-2" }
]
},
(
Current.user.admin? ? {
header: t(".advanced_section_title"),
items: [
{ label: t(".ai_prompts_label"), path: settings_ai_prompts_path, icon: "bot" },
{ label: t(".api_keys_label"), path: settings_api_key_path, icon: "key" },
{ label: t(".self_hosting_label"), path: settings_hosting_path, icon: "database", if: self_hosted? },
{ label: t(".imports_label"), path: imports_path, icon: "download" },
{ label: "SimpleFin", path: simplefin_items_path, icon: "building-2" }
]
} : nil
),
{
header: t(".other_section_title"),
items: [
@@ -54,7 +56,7 @@ nav_sections = [
<% end %>
</div>
<nav class="space-y-4 hidden md:block">
<% nav_sections.each do |section| %>
<% nav_sections.compact.each do |section| %>
<section class="space-y-2">
<div class="flex items-center gap-2 px-3">
<h3 class="uppercase text-secondary font-medium text-xs"><%= section[:header] %></h3>
@@ -87,7 +89,7 @@ nav_sections = [
variant: "ghost",
) %>
</li>
<% nav_sections.each do |section| %>
<% nav_sections.compact.each do |section| %>
<% section[:items].each do |item| %>
<% next if item[:if] == false %>
<li>

View File

@@ -33,11 +33,12 @@
<span class="text-primary text-base font-medium"><%= t(".generated_tokens") %></span>
</div>
<div>
<%= button_to invite_codes_path,
method: :post,
class: "flex gap-1 bg-gray-50 text-primary text-sm rounded-lg px-3 py-2" do %>
<span><%= t(".generate_tokens") %></span>
<% end %>
<%= render DS::Button.new(
text: t(".generate_tokens"),
variant: "primary",
href: invite_codes_path,
method: :post
) %>
</div>
</div>

View File

@@ -197,7 +197,7 @@ Rails.application.routes.draw do
resources :securities, only: :index
resources :invite_codes, only: %i[index create]
resources :invite_codes, only: %i[index create destroy]
resources :invitations, only: [ :new, :create, :destroy ] do
get :accept, on: :member