2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 01:57:19 +08:00

feat: 清理代码

This commit is contained in:
2026-01-29 23:14:41 +08:00
parent eeb4aaee90
commit be7996969a
2 changed files with 232 additions and 422 deletions

View File

@@ -0,0 +1,118 @@
<script setup lang="ts">
/**
* 通用键值对编辑器组件
* 用于编辑 Object<string, string> 类型的数据
*/
defineOptions({
name: 'KeyValueEditor'
})
const props = withDefaults(
defineProps<{
/** 键值对数据 */
modelValue: Record<string, string>
/** 键的占位符 */
keyPlaceholder?: string
/** 值的占位符 */
valuePlaceholder?: string
/** 添加按钮文本 */
addButtonText?: string
/** 新增项的默认键前缀 */
defaultKeyPrefix?: string
/** 新增项的默认值 */
defaultValue?: string
/** 键值分隔符显示 */
separator?: string
/** 值输入框类型 */
valueType?: 'text' | 'password'
/** 是否显示密码切换按钮 */
showPasswordToggle?: boolean
}>(),
{
keyPlaceholder: 'Key',
valuePlaceholder: 'Value',
addButtonText: 'Add',
defaultKeyPrefix: 'key',
defaultValue: '',
separator: '=',
valueType: 'text',
showPasswordToggle: false
}
)
const emit = defineEmits<{
'update:modelValue': [value: Record<string, string>]
}>()
// 生成唯一键名
const generateUniqueKey = () => {
const data = props.modelValue || {}
const prefix = props.defaultKeyPrefix
let i = 1
while (data[`${prefix}${i}`] !== undefined) {
i++
}
return `${prefix}${i}`
}
// 添加新项
const addItem = () => {
const data = { ...(props.modelValue || {}) }
const key = generateUniqueKey()
data[key] = props.defaultValue
emit('update:modelValue', data)
}
// 更新键名(失焦时)
const updateKey = (oldKey: string, newKey: string) => {
if (!newKey || newKey === oldKey) return
if (props.modelValue[newKey] !== undefined) return // 键已存在
const data = { ...props.modelValue }
data[newKey] = data[oldKey]
delete data[oldKey]
emit('update:modelValue', data)
}
// 更新值(失焦时)
const updateValue = (key: string, value: string) => {
const data = { ...props.modelValue }
data[key] = value
emit('update:modelValue', data)
}
// 删除项
const removeItem = (key: string) => {
const data = { ...props.modelValue }
delete data[key]
emit('update:modelValue', data)
}
</script>
<template>
<n-flex vertical :size="8" w-full>
<n-flex v-for="(value, key) in modelValue" :key="String(key)" :size="8" align="center">
<n-input
:default-value="String(key)"
:placeholder="keyPlaceholder"
flex-1
@blur="(e: FocusEvent) => updateKey(String(key), (e.target as HTMLInputElement).value)"
/>
<span flex-shrink-0>{{ separator }}</span>
<n-input
:default-value="String(value)"
:type="valueType"
:show-password-on="showPasswordToggle ? 'click' : undefined"
:placeholder="valuePlaceholder"
flex-1
@blur="(e: FocusEvent) => updateValue(String(key), (e.target as HTMLInputElement).value)"
/>
<n-button type="error" secondary size="small" flex-shrink-0 @click="removeItem(String(key))">
{{ $gettext('Remove') }}
</n-button>
</n-flex>
<n-button dashed size="small" @click="addItem">
{{ addButtonText }}
</n-button>
</n-flex>
</template>

View File

@@ -11,6 +11,7 @@ import draggable from 'vuedraggable'
import cert from '@/api/panel/cert'
import home from '@/api/panel/home'
import website from '@/api/panel/website'
import KeyValueEditor from '@/components/common/KeyValueEditor.vue'
const { $gettext } = useGettext()
let messageReactive: MessageReactive | null = null
@@ -248,15 +249,6 @@ const removeUpstream = (index: number) => {
}
}
// 为上游添加服务器
const addServerToUpstream = (index: number) => {
const upstream = setting.value.upstreams[index]
if (!upstream.servers) {
upstream.servers = {}
}
upstream.servers[`127.0.0.1:${8080 + Object.keys(upstream.servers).length}`] = ''
}
// 更新上游超时时间值
const updateUpstreamTimeoutValue = (upstream: any, value: number) => {
const parsed = parseDuration(upstream.resolver_timeout)
@@ -373,61 +365,6 @@ const isCacheEnabled = (proxy: any) => {
return proxy.cache !== null && proxy.cache !== undefined
}
// 添加缓存有效期规则
const addCacheValidRule = (proxy: any) => {
if (!proxy.cache) return
if (!proxy.cache.valid) proxy.cache.valid = {}
proxy.cache.valid[`any`] = '5m'
}
// 删除缓存有效期规则
const removeCacheValidRule = (proxy: any, codes: string) => {
if (proxy.cache?.valid) {
delete proxy.cache.valid[codes]
}
}
// 不缓存条件选项
const noCacheConditionOptions = [
{ label: '$cookie_nocache', value: '$cookie_nocache' },
{ label: '$arg_nocache', value: '$arg_nocache' },
{ label: '$http_pragma', value: '$http_pragma' },
{ label: '$http_authorization', value: '$http_authorization' },
{ label: '$http_cache_control', value: '$http_cache_control' }
]
// 过期缓存使用策略选项
const useStaleOptions = [
{ label: 'error', value: 'error' },
{ label: 'timeout', value: 'timeout' },
{ label: 'updating', value: 'updating' },
{ label: 'http_500', value: 'http_500' },
{ label: 'http_502', value: 'http_502' },
{ label: 'http_503', value: 'http_503' },
{ label: 'http_504', value: 'http_504' }
]
// 缓存方法选项
const cacheMethodOptions = [
{ label: 'GET', value: 'GET' },
{ label: 'HEAD', value: 'HEAD' },
{ label: 'POST', value: 'POST' }
]
// HTTP 协议版本选项
const httpVersionOptions = [
{ label: 'HTTP/1.0', value: '1.0' },
{ label: 'HTTP/1.1', value: '1.1' },
{ label: 'HTTP/2', value: '2' }
]
// 大小单位选项
const sizeUnitOptions = [
{ label: 'KB', value: 'k' },
{ label: 'MB', value: 'm' },
{ label: 'GB', value: 'g' }
]
// 从字节解析为 {value, unit} 格式
const parseSize = (bytes: number): { value: number; unit: string } => {
if (!bytes || bytes <= 0) return { value: 0, unit: 'm' }
@@ -459,30 +396,6 @@ const buildSize = (value: number, unit: string): number => {
}
}
// 重试条件选项
const retryConditionOptions = [
{ label: 'error', value: 'error' },
{ label: 'timeout', value: 'timeout' },
{ label: 'invalid_header', value: 'invalid_header' },
{ label: 'http_500', value: 'http_500' },
{ label: 'http_502', value: 'http_502' },
{ label: 'http_503', value: 'http_503' },
{ label: 'http_504', value: 'http_504' },
{ label: 'http_429', value: 'http_429' },
{ label: 'non_idempotent', value: 'non_idempotent' },
{ label: 'off', value: 'off' }
]
// 常见隐藏响应头选项
const hideHeaderOptions = [
{ label: 'X-Powered-By', value: 'X-Powered-By' },
{ label: 'Server', value: 'Server' },
{ label: 'X-AspNet-Version', value: 'X-AspNet-Version' },
{ label: 'X-AspNetMvc-Version', value: 'X-AspNetMvc-Version' },
{ label: 'X-Runtime', value: 'X-Runtime' },
{ label: 'X-Version', value: 'X-Version' }
]
// 创建默认超时配置
const createDefaultTimeoutConfig = () => ({
connect: 60 * SECOND,
@@ -601,13 +514,6 @@ const updateRetryTimeoutUnit = (proxy: any, unit: string) => {
proxy.retry.timeout = buildDuration(parsed.value, unit)
}
// 添加响应头
const addResponseHeader = (proxy: any) => {
if (!proxy.response_headers) return
if (!proxy.response_headers.add) proxy.response_headers.add = {}
proxy.response_headers.add['X-Custom-Header'] = 'value'
}
// 删除代理
const removeProxy = (index: number) => {
if (setting.value.proxies) {
@@ -781,39 +687,7 @@ const realIPEnabled = computed({
}
})
// 真实 IP Header 选项
const realIPHeaderOptions = [
{ label: 'X-Real-IP', value: 'X-Real-IP' },
{ label: 'X-Forwarded-For', value: 'X-Forwarded-For' },
{ label: 'CF-Connecting-IP', value: 'CF-Connecting-IP' },
{ label: 'True-Client-IP', value: 'True-Client-IP' },
{ label: 'Ali-Cdn-Real-Ip', value: 'Ali-Cdn-Real-Ip' },
{ label: 'EO-Connecting-IP', value: 'EO-Connecting-IP' }
]
// 添加基本认证用户
const addBasicAuthUser = () => {
if (!setting.value.basic_auth) {
setting.value.basic_auth = {}
}
const index = Object.keys(setting.value.basic_auth).length + 1
setting.value.basic_auth[`user${index}`] = ''
}
// 删除基本认证用户
const removeBasicAuthUser = (username: string) => {
if (setting.value.basic_auth) {
delete setting.value.basic_auth[username]
}
}
// ========== 自定义配置相关 ==========
// 作用域选项
const scopeOptions = [
{ label: $gettext('This Website'), value: 'site' },
{ label: $gettext('Global'), value: 'shared' }
]
// 添加自定义配置
const addCustomConfig = () => {
if (!setting.value.custom_configs) {
@@ -1007,47 +881,13 @@ const removeCustomConfig = (index: number) => {
</n-form-item-gi>
</n-grid>
<n-form-item :label="$gettext('Backend Servers')">
<n-flex vertical :size="8" w-full>
<n-flex
v-for="(options, address) in upstream.servers"
:key="String(address)"
:size="8"
align="center"
>
<n-input
:default-value="String(address)"
:placeholder="$gettext('Server address, e.g., 127.0.0.1:8080')"
flex-1
@change="
(newAddr: string) => {
const oldAddr = String(address)
if (newAddr && newAddr !== oldAddr) {
upstream.servers[newAddr] = upstream.servers[oldAddr]
delete upstream.servers[oldAddr]
}
}
"
/>
<n-input
:value="String(options)"
:placeholder="$gettext('Options, e.g., weight=5 backup')"
flex-1
@update:value="(v: string) => (upstream.servers[String(address)] = v)"
/>
<n-button
type="error"
secondary
size="small"
flex-shrink-0
@click="delete upstream.servers[String(address)]"
>
{{ $gettext('Remove') }}
</n-button>
</n-flex>
<n-button dashed size="small" @click="addServerToUpstream(index)">
{{ $gettext('Add Server') }}
</n-button>
</n-flex>
<key-value-editor
v-model="upstream.servers"
:key-placeholder="$gettext('Server address, e.g., 127.0.0.1:8080')"
:value-placeholder="$gettext('Options, e.g., weight=5 backup')"
:add-button-text="$gettext('Add Server')"
default-key-prefix="127.0.0.1:8080"
/>
</n-form-item>
</n-form>
</n-card>
@@ -1178,59 +1018,26 @@ const removeCustomConfig = (index: number) => {
<n-grid :cols="24" :x-gap="16">
<!-- 缓存有效期 -->
<n-form-item-gi :span="24" :label="$gettext('Cache Valid')">
<n-flex vertical :size="8" w-full>
<n-flex
v-for="(duration, codes) in proxy.cache?.valid"
:key="String(codes)"
:size="8"
align="center"
>
<n-input
:value="String(codes)"
:placeholder="$gettext('Status codes, e.g., 200 302 or any')"
flex-1
@blur="
(e: FocusEvent) => {
const newCodes = (e.target as HTMLInputElement).value
const oldCodes = String(codes)
if (newCodes && newCodes !== oldCodes && proxy.cache?.valid) {
proxy.cache.valid[newCodes] = proxy.cache.valid[oldCodes]
delete proxy.cache.valid[oldCodes]
}
}
"
/>
<span flex-shrink-0>=</span>
<n-input
:value="String(duration)"
:placeholder="$gettext('Duration, e.g., 10m, 1h, 1d')"
style="width: 120px"
@update:value="
(v: string) => {
if (proxy.cache?.valid) proxy.cache.valid[String(codes)] = v
}
"
/>
<n-button
type="error"
secondary
size="small"
flex-shrink-0
@click="removeCacheValidRule(proxy, String(codes))"
>
{{ $gettext('Remove') }}
</n-button>
</n-flex>
<n-button dashed size="small" @click="addCacheValidRule(proxy)">
{{ $gettext('Add Cache Valid Rule') }}
</n-button>
</n-flex>
<key-value-editor
v-model="proxy.cache.valid"
:key-placeholder="$gettext('Status codes, e.g., 200 302 or any')"
:value-placeholder="$gettext('Duration, e.g., 10m, 1h, 1d')"
:add-button-text="$gettext('Add Cache Valid Rule')"
default-key-prefix="20"
default-value="10m"
/>
</n-form-item-gi>
<!-- 不缓存条件 -->
<n-form-item-gi :span="12" :label="$gettext('No Cache Conditions')">
<n-select
v-model:value="proxy.cache.no_cache_conditions"
:options="noCacheConditionOptions"
:options="[
{ label: '$cookie_nocache', value: '$cookie_nocache' },
{ label: '$arg_nocache', value: '$arg_nocache' },
{ label: '$http_pragma', value: '$http_pragma' },
{ label: '$http_authorization', value: '$http_authorization' },
{ label: '$http_cache_control', value: '$http_cache_control' }
]"
multiple
filterable
tag
@@ -1241,7 +1048,15 @@ const removeCustomConfig = (index: number) => {
<n-form-item-gi :span="12" :label="$gettext('Use Stale')">
<n-select
v-model:value="proxy.cache.use_stale"
:options="useStaleOptions"
:options="[
{ label: 'error', value: 'error' },
{ label: 'timeout', value: 'timeout' },
{ label: 'updating', value: 'updating' },
{ label: 'http_500', value: 'http_500' },
{ label: 'http_502', value: 'http_502' },
{ label: 'http_503', value: 'http_503' },
{ label: 'http_504', value: 'http_504' }
]"
multiple
:placeholder="$gettext('When to use stale cache')"
/>
@@ -1269,7 +1084,11 @@ const removeCustomConfig = (index: number) => {
<n-form-item-gi :span="6" :label="$gettext('Cache Methods')">
<n-select
v-model:value="proxy.cache.methods"
:options="cacheMethodOptions"
:options="[
{ label: 'GET', value: 'GET' },
{ label: 'HEAD', value: 'HEAD' },
{ label: 'POST', value: 'POST' }
]"
multiple
:placeholder="$gettext('Default: GET HEAD')"
/>
@@ -1288,58 +1107,13 @@ const removeCustomConfig = (index: number) => {
<!-- 自定义请求头 -->
<n-collapse-item :title="$gettext('Custom Request Headers')" name="headers">
<n-flex vertical :size="8">
<n-flex
v-for="(headerValue, headerName) in proxy.headers"
:key="String(headerName)"
:size="8"
align="center"
>
<n-input
:value="String(headerName)"
:placeholder="$gettext('Header name')"
flex-1
@blur="
(e: FocusEvent) => {
const newName = (e.target as HTMLInputElement).value
const oldName = String(headerName)
if (newName && newName !== oldName) {
proxy.headers[newName] = proxy.headers[oldName]
delete proxy.headers[oldName]
}
}
"
/>
<span flex-shrink-0>=</span>
<n-input
:value="String(headerValue)"
:placeholder="$gettext('Value or variable like $host, $remote_addr')"
flex-1
@update:value="(v: string) => (proxy.headers[String(headerName)] = v)"
/>
<n-button
type="error"
secondary
size="small"
flex-shrink-0
@click="delete proxy.headers[String(headerName)]"
>
{{ $gettext('Remove') }}
</n-button>
</n-flex>
<n-button
dashed
size="small"
@click="
() => {
if (!proxy.headers) proxy.headers = {}
proxy.headers[`X-Custom-${Object.keys(proxy.headers).length}`] = ''
}
"
>
{{ $gettext('Add Request Header') }}
</n-button>
</n-flex>
<key-value-editor
v-model="proxy.headers"
:key-placeholder="$gettext('Header name')"
:value-placeholder="$gettext('Value or variable like $host, $remote_addr')"
:add-button-text="$gettext('Add Request Header')"
default-key-prefix="X-Custom-Header"
/>
</n-collapse-item>
<!-- 响应内容替换 -->
@@ -1347,58 +1121,15 @@ const removeCustomConfig = (index: number) => {
:title="$gettext('Response Content Replacement')"
name="replaces"
>
<n-flex vertical :size="8">
<n-flex
v-for="(toValue, fromValue) in proxy.replaces"
:key="String(fromValue)"
:size="8"
align="center"
>
<n-input
:value="String(fromValue)"
:placeholder="$gettext('Original content')"
flex-1
@blur="
(e: FocusEvent) => {
const newFrom = (e.target as HTMLInputElement).value
const oldFrom = String(fromValue)
if (newFrom && newFrom !== oldFrom) {
proxy.replaces[newFrom] = proxy.replaces[oldFrom]
delete proxy.replaces[oldFrom]
}
}
"
/>
<span flex-shrink-0>=></span>
<n-input
:value="String(toValue)"
:placeholder="$gettext('Replacement content')"
flex-1
@update:value="(v: string) => (proxy.replaces[String(fromValue)] = v)"
/>
<n-button
type="error"
secondary
size="small"
flex-shrink-0
@click="delete proxy.replaces[String(fromValue)]"
>
{{ $gettext('Remove') }}
</n-button>
</n-flex>
<n-button
dashed
size="small"
@click="
() => {
if (!proxy.replaces) proxy.replaces = {}
proxy.replaces[`/old_${Object.keys(proxy.replaces).length}`] = '/new'
}
"
>
{{ $gettext('Add Replacement Rule') }}
</n-button>
</n-flex>
<key-value-editor
v-model="proxy.replaces"
:key-placeholder="$gettext('Original content')"
:value-placeholder="$gettext('Replacement content')"
:add-button-text="$gettext('Add Replacement Rule')"
default-key-prefix="/old_"
default-value="/new"
separator="=>"
/>
</n-collapse-item>
<!-- 高级配置 Nginx -->
@@ -1412,7 +1143,11 @@ const removeCustomConfig = (index: number) => {
<n-form-item-gi :span="8" :label="$gettext('HTTP Version')">
<n-select
v-model:value="proxy.http_version"
:options="httpVersionOptions"
:options="[
{ label: 'HTTP/1.0', value: '1.0' },
{ label: 'HTTP/1.1', value: '1.1' },
{ label: 'HTTP/2', value: '2' }
]"
:placeholder="$gettext('Select HTTP version')"
/>
</n-form-item-gi>
@@ -1437,7 +1172,11 @@ const removeCustomConfig = (index: number) => {
:value="
parseSize(proxy.client_max_body_size || 1024 * 1024).unit || 'm'
"
:options="sizeUnitOptions"
:options="[
{ label: 'KB', value: 'k' },
{ label: 'MB', value: 'm' },
{ label: 'GB', value: 'g' }
]"
style="width: 80px"
@update:value="(v: string) => updateClientMaxBodySizeUnit(proxy, v)"
/>
@@ -1558,7 +1297,18 @@ const removeCustomConfig = (index: number) => {
<n-form-item-gi :span="12" :label="$gettext('Retry Conditions')">
<n-select
v-model:value="proxy.retry.conditions"
:options="retryConditionOptions"
:options="[
{ label: 'error', value: 'error' },
{ label: 'timeout', value: 'timeout' },
{ label: 'invalid_header', value: 'invalid_header' },
{ label: 'http_500', value: 'http_500' },
{ label: 'http_502', value: 'http_502' },
{ label: 'http_503', value: 'http_503' },
{ label: 'http_504', value: 'http_504' },
{ label: 'http_429', value: 'http_429' },
{ label: 'non_idempotent', value: 'non_idempotent' },
{ label: 'off', value: 'off' }
]"
multiple
:placeholder="$gettext('Select retry conditions')"
/>
@@ -1629,7 +1379,14 @@ const removeCustomConfig = (index: number) => {
<n-form-item-gi :span="12" :label="$gettext('Hide Headers')">
<n-select
v-model:value="proxy.response_headers.hide"
:options="hideHeaderOptions"
:options="[
{ label: 'X-Powered-By', value: 'X-Powered-By' },
{ label: 'Server', value: 'Server' },
{ label: 'X-AspNet-Version', value: 'X-AspNet-Version' },
{ label: 'X-AspNetMvc-Version', value: 'X-AspNetMvc-Version' },
{ label: 'X-Runtime', value: 'X-Runtime' },
{ label: 'X-Version', value: 'X-Version' }
]"
multiple
filterable
tag
@@ -1637,53 +1394,13 @@ const removeCustomConfig = (index: number) => {
/>
</n-form-item-gi>
<n-form-item-gi :span="12" :label="$gettext('Add Headers')">
<n-flex vertical :size="8" w-full>
<n-flex
v-for="(headerValue, headerName) in proxy.response_headers.add"
:key="String(headerName)"
:size="8"
align="center"
>
<n-input
:value="String(headerName)"
:placeholder="$gettext('Header name')"
flex-1
@blur="
(e: FocusEvent) => {
const newName = (e.target as HTMLInputElement).value
const oldName = String(headerName)
if (newName && newName !== oldName) {
proxy.response_headers.add[newName] =
proxy.response_headers.add[oldName]
delete proxy.response_headers.add[oldName]
}
}
"
/>
<span flex-shrink-0>=</span>
<n-input
:value="String(headerValue)"
:placeholder="$gettext('Header value')"
flex-1
@update:value="
(v: string) =>
(proxy.response_headers.add[String(headerName)] = v)
"
/>
<n-button
type="error"
secondary
size="small"
flex-shrink-0
@click="delete proxy.response_headers.add[String(headerName)]"
>
{{ $gettext('Remove') }}
</n-button>
</n-flex>
<n-button dashed size="small" @click="addResponseHeader(proxy)">
{{ $gettext('Add Response Header') }}
</n-button>
</n-flex>
<key-value-editor
v-model="proxy.response_headers.add"
:key-placeholder="$gettext('Header name')"
:value-placeholder="$gettext('Header value')"
:add-button-text="$gettext('Add Response Header')"
default-key-prefix="X-Custom-Header"
/>
</n-form-item-gi>
</n-grid>
</template>
@@ -2046,7 +1763,14 @@ const removeCustomConfig = (index: number) => {
<n-form-item :label="$gettext('IP Header')">
<n-select
v-model:value="setting.real_ip.header"
:options="realIPHeaderOptions"
:options="[
{ label: 'X-Real-IP', value: 'X-Real-IP' },
{ label: 'X-Forwarded-For', value: 'X-Forwarded-For' },
{ label: 'CF-Connecting-IP', value: 'CF-Connecting-IP' },
{ label: 'True-Client-IP', value: 'True-Client-IP' },
{ label: 'Ali-Cdn-Real-Ip', value: 'Ali-Cdn-Real-Ip' },
{ label: 'EO-Connecting-IP', value: 'EO-Connecting-IP' }
]"
filterable
tag
/>
@@ -2065,53 +1789,15 @@ const removeCustomConfig = (index: number) => {
<n-card :title="$gettext('Basic Authentication')" mb-16>
<n-form label-placement="left" label-width="140px">
<n-form-item :label="$gettext('User Credentials')">
<n-flex vertical :size="8" w-full>
<n-flex
v-for="(password, username) in setting.basic_auth"
:key="String(username)"
:size="8"
align="center"
>
<n-input
:default-value="String(username)"
:placeholder="$gettext('Username')"
flex-1
@change="
(newUsername: string) => {
const oldUsername = String(username)
if (newUsername && newUsername !== oldUsername) {
// 检查新用户名是否已存在
if (setting.basic_auth[newUsername] !== undefined) {
return
}
setting.basic_auth[newUsername] = setting.basic_auth[oldUsername]
delete setting.basic_auth[oldUsername]
}
}
"
/>
<n-input
:value="String(password)"
type="password"
show-password-on="click"
:placeholder="$gettext('Password')"
flex-1
@update:value="(v: string) => (setting.basic_auth[String(username)] = v)"
/>
<n-button
type="error"
secondary
size="small"
flex-shrink-0
@click="removeBasicAuthUser(String(username))"
>
{{ $gettext('Remove') }}
</n-button>
</n-flex>
<n-button dashed size="small" @click="addBasicAuthUser">
{{ $gettext('Add User') }}
</n-button>
</n-flex>
<key-value-editor
v-model="setting.basic_auth"
:key-placeholder="$gettext('Username')"
:value-placeholder="$gettext('Password')"
:add-button-text="$gettext('Add User')"
default-key-prefix="user"
value-type="password"
:show-password-toggle="true"
/>
</n-form-item>
</n-form>
<n-alert v-if="Object.keys(setting.basic_auth || {}).length > 0" type="info">
@@ -2156,7 +1842,13 @@ const removeCustomConfig = (index: number) => {
/>
</n-form-item-gi>
<n-form-item-gi :span="12" :label="$gettext('Scope')">
<n-select v-model:value="config.scope" :options="scopeOptions" />
<n-select
v-model:value="config.scope"
:options="[
{ label: $gettext('This Website'), value: 'site' },
{ label: $gettext('Global'), value: 'shared' }
]"
/>
</n-form-item-gi>
</n-grid>
<n-form-item :label="$gettext('Content')">