fix(plugins): move plugin store toggle onto each khanegi tenant

Remove the global header switch and let SuperAdmin enable the store per project from the plugins list and tenant page.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-07 19:51:12 +03:30
co-authored by Cursor
parent 7eacb513cd
commit 8d0dfba60f
3 changed files with 122 additions and 37 deletions
+64 -1
View File
@@ -4,6 +4,7 @@ import { useRouter } from 'vue-router'
import { message } from 'ant-design-vue'
import { ArrowRightOutlined, AppstoreAddOutlined, SearchOutlined } from '@ant-design/icons-vue'
import api from '@/api/http'
import { useAuthStore } from '@/stores/auth'
type ExpiryLevel = 'healthy' | 'warning' | 'critical' | 'unknown' | 'none'
@@ -14,6 +15,7 @@ type TenantRow = {
domain: string
slug?: string
pluginCount: number
pluginStoreEnabled?: boolean
summary: {
expiryLevel: ExpiryLevel
expiryLabel: string
@@ -32,6 +34,9 @@ type RequestRow = {
}
const router = useRouter()
const auth = useAuthStore()
const canWrite = computed(() => auth.can('plugins:write'))
const storeBusyId = ref<string | null>(null)
const loadingList = ref(false)
const tenants = ref<TenantRow[]>([])
const q = ref('')
@@ -72,6 +77,27 @@ function openTenant(id: string) {
router.push({ name: 'plugin-tenant', params: { tenantId: id } })
}
async function onStoreToggle(tenant: TenantRow, checked: boolean) {
if (!canWrite.value) return
storeBusyId.value = tenant.id
const previous = tenant.pluginStoreEnabled === true
tenant.pluginStoreEnabled = checked
try {
const { data } = await api.patch(`/plugins/tenants/${tenant.id}/store-enabled`, {
enabled: checked,
})
tenant.pluginStoreEnabled = data.pluginStoreEnabled === true
message.success(
tenant.pluginStoreEnabled ? 'فروشگاه افزونه روشن شد' : 'فروشگاه افزونه خاموش شد',
)
} catch (e: any) {
tenant.pluginStoreEnabled = previous
message.error(e?.response?.data?.message || 'تغییر فروشگاه افزونه ناموفق')
} finally {
storeBusyId.value = null
}
}
async function loadTenants() {
loadingList.value = true
try {
@@ -306,6 +332,21 @@ onMounted(() => {
:class="toneClass(t.summary?.expiryLevel)"
@click="openTenant(t.id)"
>
<div
v-if="canWrite"
class="sms-toggle"
:class="{ off: !t.pluginStoreEnabled }"
@click.stop
>
<span class="sms-toggle-label">فروشگاه افزونه</span>
<a-switch
:checked="t.pluginStoreEnabled === true"
:loading="storeBusyId === t.id"
checked-children="روشن"
un-checked-children="خاموش"
@change="(v: boolean) => onStoreToggle(t, v)"
/>
</div>
<strong>{{ t.nameFa }}</strong>
<span>{{ t.summary?.expiryLabel }}</span>
<small>{{ t.pluginCount }} افزونه</small>
@@ -409,7 +450,7 @@ onMounted(() => {
.tenant-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 160px), 1fr));
grid-template-columns: repeat(auto-fill, minmax(min(100%, 210px), 1fr));
gap: 10px;
}
@@ -426,6 +467,28 @@ onMounted(() => {
color: #17324d;
}
.sms-toggle {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 6px 10px;
border-radius: 999px;
background: #e8f8f1;
border: 1px solid #b7ebd4;
margin-bottom: 6px;
}
.sms-toggle.off {
background: #fff1f0;
border-color: #ffccc7;
}
.sms-toggle-label {
font-size: 0.75rem;
font-weight: 700;
color: #334155;
white-space: nowrap;
}
.tenant-card strong { font-size: 0.95rem; }
.tenant-card span,
.tenant-card small { opacity: 0.92; font-size: 0.82rem; }