feat: Add account suspension metadata in Super Admin (#15158)
## Description Super Admins can now record a category and reason when suspending an account, review the complete suspension history on the account details page, and correct the latest suspension metadata without losing its original timestamp. Suspension events are stored internally on the account without changing customer-facing account API payloads. ## Closes - [CW-7653](https://linear.app/chatwoot/issue/CW-7653/ability-to-add-notes-while-suspending-an-acocunt) - [Implementation plan](https://linear.app/chatwoot/document/super-admin-account-suspension-metadata-implementation-plan-e7e4eb79d078) ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality not to work as expected) - [ ] This change requires a documentation update ## What changed - Require a suspension category and a reason of up to 256 characters when an active account is suspended. - Store append-only suspension events in `accounts.internal_attributes`, while preserving unrelated internal metadata. - Allow corrections to the latest event for an already suspended account without changing its timestamp. - Show the full suspension history, newest first, on the Super Admin account details page. - Add visual dividers between top-level sections on the Super Admin account edit page. - Keep legacy suspended-account edits and new-account creation behavior unchanged. ## How to test 1. Open an active account in Super Admin and choose **Suspended**. 2. Confirm the category and reason controls appear, reject incomplete or invalid values, and enforce the 256-character reason limit. 3. Suspend the account with each supported category and confirm the event appears on the details page. 4. Reactivate and suspend the account again; confirm prior history is retained and a new event is added. 5. Edit a suspended account's latest category or reason; confirm its original timestamp is preserved. 6. Confirm a legacy suspended account without history can still be edited without supplying suspension metadata. ## Checklist - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
@@ -2,15 +2,15 @@
|
||||
<%= f.label field.attribute %>
|
||||
</div>
|
||||
|
||||
<div class="field-unit__field">
|
||||
<p class="text-gray-400 text-xs italic mb-4"><%= t('super_admin.captain_model_overrides.form.helper_text') %></p>
|
||||
<div class="field-unit__field max-w-5xl">
|
||||
<p class="mb-3 text-xs italic text-n-slate-10"><%= t('super_admin.captain_model_overrides.form.helper_text') %></p>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<div class="grid grid-cols-1 gap-2 lg:grid-cols-3">
|
||||
<% field.feature_rows.each do |feature| %>
|
||||
<div class="p-3 bg-white rounded-lg shadow-sm outline outline-1 outline-n-container">
|
||||
<div class="mb-2">
|
||||
<div class="text-sm font-medium text-slate-700"><%= feature[:name] %></div>
|
||||
<div class="text-xs text-slate-500"><%= feature[:key] %></div>
|
||||
<div class="rounded-md border border-n-weak bg-white p-2.5">
|
||||
<div class="mb-1.5">
|
||||
<div class="text-xs font-medium text-n-slate-12"><%= feature[:name] %></div>
|
||||
<div class="text-[11px] text-n-slate-10"><%= feature[:key] %></div>
|
||||
</div>
|
||||
|
||||
<%= select_tag(
|
||||
@@ -19,7 +19,7 @@
|
||||
[[t('super_admin.captain_model_overrides.form.use_default', model: feature[:default_model], model_id: feature[:default_model_id]), '']] + feature[:options],
|
||||
feature[:selected_override]
|
||||
),
|
||||
class: 'block w-full rounded-md border-slate-300 text-sm'
|
||||
class: 'block w-full rounded-md border-n-strong py-1.5 pl-2 pr-8 text-xs'
|
||||
) %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -7,29 +7,29 @@
|
||||
</summary>
|
||||
|
||||
<div class="mt-3 w-full">
|
||||
<div class="grid grid-cols-1 gap-3">
|
||||
<div class="grid grid-cols-1 gap-2 lg:grid-cols-3">
|
||||
<% field.feature_rows.each do |feature| %>
|
||||
<div class="p-3 bg-white rounded-md outline outline-n-container outline-1 shadow-sm">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div class="rounded-md border border-n-weak bg-white p-2.5">
|
||||
<div class="flex items-start justify-between gap-2">
|
||||
<div>
|
||||
<div class="text-sm font-medium text-n-slate-12"><%= feature[:name] %></div>
|
||||
<div class="text-xs text-n-slate-11"><%= feature[:key] %></div>
|
||||
<div class="text-xs font-medium text-n-slate-12"><%= feature[:name] %></div>
|
||||
<div class="text-[11px] text-n-slate-10"><%= feature[:key] %></div>
|
||||
</div>
|
||||
<span class="<%= feature[:source] == :account_override ? 'bg-green-400 text-white' : 'bg-slate-50 text-slate-800' %> rounded-full px-2 py-1 text-xs">
|
||||
<span class="<%= feature[:source] == :account_override ? 'bg-green-400 text-white' : 'bg-slate-50 text-slate-800' %> shrink-0 rounded-full px-2 py-1 text-[11px]">
|
||||
<%= feature[:source_label] %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
|
||||
<div class="mt-2 grid grid-cols-1 gap-2 text-xs">
|
||||
<div>
|
||||
<div class="text-xs uppercase text-n-slate-10"><%= t('super_admin.captain_model_overrides.show.provider') %></div>
|
||||
<div class="text-[11px] uppercase text-n-slate-10"><%= t('super_admin.captain_model_overrides.show.provider') %></div>
|
||||
<div class="text-n-slate-12">
|
||||
<%= feature[:provider] %>
|
||||
<span class="text-n-slate-10">(<%= feature[:provider_id] %>)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-xs uppercase text-n-slate-10"><%= t('super_admin.captain_model_overrides.show.model') %></div>
|
||||
<div class="text-[11px] uppercase text-n-slate-10"><%= t('super_admin.captain_model_overrides.show.model') %></div>
|
||||
<div class="text-n-slate-12">
|
||||
<%= feature[:model] %>
|
||||
<span class="text-n-slate-10">(<%= feature[:model_id] %>)</span>
|
||||
|
||||
Reference in New Issue
Block a user