diff options
| author | Alireza Ahmadi <alireza7@gmail.com> | 2023-12-08 19:18:51 +0300 |
|---|---|---|
| committer | Alireza Ahmadi <alireza7@gmail.com> | 2023-12-08 19:18:51 +0300 |
| commit | 5e47b4e94925c2272a7f0a4cc355cede72c671a4 (patch) | |
| tree | 1cc0b2f5c8cea380b65c6d8bb1294e9c5eeb83a7 | |
| parent | 549f230221d7139270efefd76ac81f37e1a747f9 (diff) | |
pagination and sub URI support #1300
| -rw-r--r-- | web/controller/setting.go | 41 | ||||
| -rw-r--r-- | web/entity/entity.go | 8 | ||||
| -rw-r--r-- | web/html/common/qrcode_modal.html | 3 | ||||
| -rw-r--r-- | web/html/xui/component/setting.html | 6 | ||||
| -rw-r--r-- | web/html/xui/inbound_info_modal.html | 3 | ||||
| -rw-r--r-- | web/html/xui/inbounds.html | 40 | ||||
| -rw-r--r-- | web/html/xui/settings.html | 2 | ||||
| -rw-r--r-- | web/service/setting.go | 68 | ||||
| -rw-r--r-- | web/translation/translate.en_US.toml | 4 | ||||
| -rw-r--r-- | web/translation/translate.es_ES.toml | 4 | ||||
| -rw-r--r-- | web/translation/translate.fa_IR.toml | 4 | ||||
| -rw-r--r-- | web/translation/translate.ru_RU.toml | 10 | ||||
| -rw-r--r-- | web/translation/translate.vi_VN.toml | 4 | ||||
| -rw-r--r-- | web/translation/translate.zh_Hans.toml | 4 |
14 files changed, 142 insertions, 59 deletions
diff --git a/web/controller/setting.go b/web/controller/setting.go index 96223c28..64cae71b 100644 --- a/web/controller/setting.go +++ b/web/controller/setting.go @@ -56,44 +56,11 @@ func (a *SettingController) getAllSetting(c *gin.Context) { } func (a *SettingController) getDefaultSettings(c *gin.Context) { - type settingFunc func() (interface{}, error) - - settings := map[string]settingFunc{ - "expireDiff": func() (interface{}, error) { return a.settingService.GetExpireDiff() }, - "trafficDiff": func() (interface{}, error) { return a.settingService.GetTrafficDiff() }, - "defaultCert": func() (interface{}, error) { return a.settingService.GetCertFile() }, - "defaultKey": func() (interface{}, error) { return a.settingService.GetKeyFile() }, - "tgBotEnable": func() (interface{}, error) { return a.settingService.GetTgbotenabled() }, - "subEnable": func() (interface{}, error) { return a.settingService.GetSubEnable() }, - "subPort": func() (interface{}, error) { return a.settingService.GetSubPort() }, - "subPath": func() (interface{}, error) { return a.settingService.GetSubPath() }, - "subDomain": func() (interface{}, error) { return a.settingService.GetSubDomain() }, - "subKeyFile": func() (interface{}, error) { return a.settingService.GetSubKeyFile() }, - "subCertFile": func() (interface{}, error) { return a.settingService.GetSubCertFile() }, - "subEncrypt": func() (interface{}, error) { return a.settingService.GetSubEncrypt() }, - "subShowInfo": func() (interface{}, error) { return a.settingService.GetSubShowInfo() }, - } - - result := make(map[string]interface{}) - - for key, fn := range settings { - value, err := fn() - if err != nil { - jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err) - return - } - result[key] = value - } - - subTLS := false - if result["subKeyFile"] != "" || result["subCertFile"] != "" { - subTLS = true + result, err := a.settingService.GetDefaultSettings(c.Request.Host) + if err != nil { + jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err) + return } - result["subTLS"] = subTLS - - delete(result, "subKeyFile") - delete(result, "subCertFile") - jsonObj(c, result, nil) } diff --git a/web/entity/entity.go b/web/entity/entity.go index 2c7b39ca..94f0171f 100644 --- a/web/entity/entity.go +++ b/web/entity/entity.go @@ -22,6 +22,7 @@ type AllSetting struct { WebKeyFile string `json:"webKeyFile" form:"webKeyFile"` WebBasePath string `json:"webBasePath" form:"webBasePath"` SessionMaxAge int `json:"sessionMaxAge" form:"sessionMaxAge"` + PageSize int `json:"pageSize" form:"pageSize"` ExpireDiff int `json:"expireDiff" form:"expireDiff"` TrafficDiff int `json:"trafficDiff" form:"trafficDiff"` TgBotEnable bool `json:"tgBotEnable" form:"tgBotEnable"` @@ -44,6 +45,7 @@ type AllSetting struct { SubUpdates int `json:"subUpdates" form:"subUpdates"` SubEncrypt bool `json:"subEncrypt" form:"subEncrypt"` SubShowInfo bool `json:"subShowInfo" form:"subShowInfo"` + SubURI string `json:"subURI" form:"subURI"` } func (s *AllSetting) CheckValid() error { @@ -93,6 +95,12 @@ func (s *AllSetting) CheckValid() error { if !strings.HasSuffix(s.WebBasePath, "/") { s.WebBasePath += "/" } + if !strings.HasPrefix(s.SubPath, "/") { + s.SubPath = "/" + s.SubPath + } + if !strings.HasSuffix(s.SubPath, "/") { + s.SubPath += "/" + } _, err := time.LoadLocation(s.TimeLocation) if err != nil { diff --git a/web/html/common/qrcode_modal.html b/web/html/common/qrcode_modal.html index 2db1948b..85ada3d4 100644 --- a/web/html/common/qrcode_modal.html +++ b/web/html/common/qrcode_modal.html @@ -86,8 +86,7 @@ }); }, genSubLink(subID) { - const { domain: host, port, tls: isTLS, path: base } = app.subSettings; - return buildURL({ host, port, isTLS, base, path: subID+'?name='+remark }); + return app.subSettings.subURI+subID+'?name='+subID; } }, updated() { diff --git a/web/html/xui/component/setting.html b/web/html/xui/component/setting.html index 568f03de..82c0ae75 100644 --- a/web/html/xui/component/setting.html +++ b/web/html/xui/component/setting.html @@ -13,10 +13,10 @@ </a-col> <a-col :lg="24" :xl="12"> <template v-if="type === 'text'"> - <a-input :value="value" @input="$emit('input', $event.target.value)"></a-input> + <a-input :value="value" @input="$emit('input', $event.target.value)" :placeholder="placeholder"></a-input> </template> <template v-else-if="type === 'number'"> - <a-input-number :value="value" @change="value => $emit('input', value)" :min="min" style="width: 100%;"></a-input-number> + <a-input-number :value="value" :step="step" @change="value => $emit('input', value)" :min="min" style="width: 100%;"></a-input-number> </template> <template v-else-if="type === 'switch'"> <a-switch :checked="value" @change="value => $emit('input', value)"></a-switch> @@ -29,7 +29,7 @@ {{define "component/setting"}} <script> Vue.component('setting-list-item', { - props: ["type", "title", "desc", "value", "min"], + props: ["type", "title", "desc", "value", "min", "step", "placeholder"], template: `{{template "component/settingListItem"}}`, }); </script> diff --git a/web/html/xui/inbound_info_modal.html b/web/html/xui/inbound_info_modal.html index e1f11b45..554d10a3 100644 --- a/web/html/xui/inbound_info_modal.html +++ b/web/html/xui/inbound_info_modal.html @@ -300,8 +300,7 @@ infoModal.visible = false; }, genSubLink(subID) { - const { domain: host, port, tls: isTLS, path: base } = app.subSettings; - return buildURL({ host, port, isTLS, base, path: subID+'?name='+remark }); + return app.subSettings.subURI+subID+'?name='+subID; } }; diff --git a/web/html/xui/inbounds.html b/web/html/xui/inbounds.html index c61104d5..e73e5f5d 100644 --- a/web/html/xui/inbounds.html +++ b/web/html/xui/inbounds.html @@ -173,14 +173,13 @@ <a-table :columns="isMobile ? mobileColums : columns" :row-key="dbInbound => dbInbound.id" :data-source="searchedInbounds" :scroll="isMobile ? {} : { x: 1000 }" - :pagination="false" + :pagination=pagination(searchedInbounds) :expand-icon-as-cell="false" :expand-row-by-click="false" :expand-icon-column-index="0" :indent-size="0" :row-class-name="dbInbound => (dbInbound.isMultiUser() ? '' : 'hideExpandIcon')" - style="margin-top: 10px" - @change="() => getDBInbounds()"> + style="margin-top: 10px"> <template slot="action" slot-scope="text, dbInbound"> <a-icon type="edit" style="font-size: 22px" @click="openEditInbound(dbInbound.id);"></a-icon> <a-dropdown :trigger="['click']"> @@ -416,7 +415,7 @@ :row-key="client => client.id" :columns="isMobile ? innerMobileColumns : innerColumns" :data-source="getInboundClients(record)" - :pagination="false" + :pagination=pagination(getInboundClients(record)) :style="isMobile ? 'margin: -16px -5px -17px;' : 'margin-left: 10px;'"> {{template "client_table"}} </a-table> @@ -547,12 +546,10 @@ refreshInterval: Number(localStorage.getItem("refreshInterval")) || 5000, subSettings: { enable : false, - port: 0, - path: '', - domain: '', - tls: false + subURI : '' }, tgBotEnable: false, + pageSize: 0, isMobile: window.innerWidth <= 768, }, methods: { @@ -592,11 +589,9 @@ this.tgBotEnable = tgBotEnable; this.subSettings = { enable : subEnable, - port: subPort, - path: subPath, - domain: subDomain, - tls: subTLS + subURI: subURI }; + this.pageSize = pageSize; } }, setInbounds(dbInbounds) { @@ -1216,6 +1211,27 @@ this.spinning = false; } }, + pagination(obj){ + if (this.pageSize > 0 && obj.length>this.pageSize) { + // Set page options based on object size + sizeOptions = [] + for (i=this.pageSize;i<=obj.length;i=i+this.pageSize) { + sizeOptions.push(i.toString()); + } + // Add option to see all in one page + sizeOptions.push(i.toString()); + + p = { + showSizeChanger: true, + size: 'small', + position: 'bottom', + pageSize: this.pageSize, + pageSizeOptions: sizeOptions + } + return p + } + return false + }, onResize() { this.isMobile = window.innerWidth <= 768; } diff --git a/web/html/xui/settings.html b/web/html/xui/settings.html index 59d20716..24cef2af 100644 --- a/web/html/xui/settings.html +++ b/web/html/xui/settings.html @@ -112,6 +112,7 @@ <setting-list-item type="text" title='{{ i18n "pages.settings.privateKeyPath"}}' desc='{{ i18n "pages.settings.privateKeyPathDesc"}}' v-model="allSetting.webKeyFile"></setting-list-item> <setting-list-item type="text" title='{{ i18n "pages.settings.panelUrlPath"}}' desc='{{ i18n "pages.settings.panelUrlPathDesc"}}' v-model="allSetting.webBasePath"></setting-list-item> <setting-list-item type="number" title='{{ i18n "pages.settings.sessionMaxAge" }}' desc='{{ i18n "pages.settings.sessionMaxAgeDesc" }}' v-model="allSetting.sessionMaxAge" :min="0"></setting-list-item> + <setting-list-item type="number" title='{{ i18n "pages.settings.pageSize" }}' desc='{{ i18n "pages.settings.pageSizeDesc" }}' v-model="allSetting.pageSize" :min="0" :step="5"></setting-list-item> <setting-list-item type="number" title='{{ i18n "pages.settings.expireTimeDiff" }}' desc='{{ i18n "pages.settings.expireTimeDiffDesc" }}' v-model="allSetting.expireDiff" :min="0"></setting-list-item> <setting-list-item type="number" title='{{ i18n "pages.settings.trafficDiff" }}' desc='{{ i18n "pages.settings.trafficDiffDesc" }}' v-model="allSetting.trafficDiff" :min="0"></setting-list-item> <setting-list-item type="text" title='{{ i18n "pages.settings.timeZone"}}' desc='{{ i18n "pages.settings.timeZoneDesc"}}' v-model="allSetting.timeLocation"></setting-list-item> @@ -243,6 +244,7 @@ <setting-list-item type="text" title='{{ i18n "pages.settings.subPath"}}' desc='{{ i18n "pages.settings.subPathDesc"}}' v-model="allSetting.subPath"></setting-list-item> <setting-list-item type="text" title='{{ i18n "pages.settings.subCertPath"}}' desc='{{ i18n "pages.settings.subCertPathDesc"}}' v-model="allSetting.subCertFile"></setting-list-item> <setting-list-item type="text" title='{{ i18n "pages.settings.subKeyPath"}}' desc='{{ i18n "pages.settings.subKeyPathDesc"}}' v-model="allSetting.subKeyFile"></setting-list-item> + <setting-list-item type="text" title='{{ i18n "pages.settings.subURI"}}' desc='{{ i18n "pages.settings.subURIDesc"}}' v-model="allSetting.subURI" placeholder="(http|https)://domain[:port]/path/"></setting-list-item> <setting-list-item type="number" title='{{ i18n "pages.settings.subUpdates"}}' desc='{{ i18n "pages.settings.subUpdatesDesc"}}' v-model="allSetting.subUpdates"></setting-list-item> </a-list> </a-tab-pane> diff --git a/web/service/setting.go b/web/service/setting.go index 933fff1b..d6cf193e 100644 --- a/web/service/setting.go +++ b/web/service/setting.go @@ -31,6 +31,7 @@ var defaultValueMap = map[string]string{ "secret": random.Seq(32), "webBasePath": "/", "sessionMaxAge": "0", + "pageSize": "0", "expireDiff": "0", "trafficDiff": "0", "timeLocation": "Asia/Tehran", @@ -53,6 +54,7 @@ var defaultValueMap = map[string]string{ "subUpdates": "12", "subEncrypt": "true", "subShowInfo": "true", + "subURI": "", } type SettingService struct { @@ -406,6 +408,14 @@ func (s *SettingService) GetSubShowInfo() (bool, error) { return s.getBool("subShowInfo") } +func (s *SettingService) GetSubURI() (string, error) { + return s.getString("subURI") +} + +func (s *SettingService) GetPageSize() (int, error) { + return s.getInt("pageSize") +} + func (s *SettingService) UpdateAllSetting(allSetting *entity.AllSetting) error { if err := allSetting.CheckValid(); err != nil { return err @@ -435,3 +445,61 @@ func (s *SettingService) GetDefaultXrayConfig() (interface{}, error) { } return jsonData, nil } + +func (s *SettingService) GetDefaultSettings(host string) (interface{}, error) { + type settingFunc func() (interface{}, error) + settings := map[string]settingFunc{ + "expireDiff": func() (interface{}, error) { return s.GetExpireDiff() }, + "trafficDiff": func() (interface{}, error) { return s.GetTrafficDiff() }, + "pageSize": func() (interface{}, error) { return s.GetPageSize() }, + "defaultCert": func() (interface{}, error) { return s.GetCertFile() }, + "defaultKey": func() (interface{}, error) { return s.GetKeyFile() }, + "tgBotEnable": func() (interface{}, error) { return s.GetTgbotenabled() }, + "subEnable": func() (interface{}, error) { return s.GetSubEnable() }, + "subURI": func() (interface{}, error) { return s.GetSubURI() }, + } + + result := make(map[string]interface{}) + + for key, fn := range settings { + value, err := fn() + if err != nil { + return "", err + } + result[key] = value + } + + if result["subEnable"].(bool) && result["subURI"].(string) == "" { + subURI := "" + subPort, _ := s.GetSubPort() + subPath, _ := s.GetSubPath() + subDomain, _ := s.GetSubDomain() + subKeyFile, _ := s.GetSubKeyFile() + subCertFile, _ := s.GetSubCertFile() + subTLS := false + if subKeyFile != "" && subCertFile != "" { + subTLS = true + } + if subDomain == "" { + subDomain = strings.Split(host, ":")[0] + } + if subTLS { + subURI = "https://" + } else { + subURI = "http://" + } + if (subPort == 443 && subTLS) || (subPort == 80 && !subTLS) { + subURI += subDomain + } else { + subURI += fmt.Sprintf("%s:%d", subDomain, subPort) + } + if subPath[0] == byte('/') { + subURI += subPath + } else { + subURI += "/" + subPath + } + result["subURI"] = subURI + } + + return result, nil +} diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml index a90f703d..86d8ef0b 100644 --- a/web/translation/translate.en_US.toml +++ b/web/translation/translate.en_US.toml @@ -238,6 +238,8 @@ "privateKeyPathDesc" = "Fill in an absolute path starting with." "panelUrlPath" = "Panel URL Root Path" "panelUrlPathDesc" = "Must start with '/' and end with." +"pageSize" = "Pagination size" +"pageSizeDesc" = "Define page size for inbounds table. Set 0 to disable" "oldUsername" = "Current Username" "currentPassword" = "Current Password" "newUsername" = "New Username" @@ -285,6 +287,8 @@ "subEncryptDesc" = "Encrypt the returned configs in subscription" "subShowInfo" = "Show usage info" "subShowInfoDesc" = "Show remianed traffic and date after config name" +"subURI" = "Reverse Proxy URI" +"subURIDesc" = "Change base URI of subscription URL for using on behind of proxies" [pages.xray] "title" = "Xray Settings" diff --git a/web/translation/translate.es_ES.toml b/web/translation/translate.es_ES.toml index c33d6ba9..dd189aae 100644 --- a/web/translation/translate.es_ES.toml +++ b/web/translation/translate.es_ES.toml @@ -238,6 +238,8 @@ "privateKeyPathDesc" = "Complete con una ruta absoluta que comience con." "panelUrlPath" = "Ruta Raíz de la URL del Panel" "panelUrlPathDesc" = "Debe empezar con '/' y terminar con." +"pageSize" = "Tamaño de paginación" +"pageSizeDesc" = "Defina el tamaño de página para la tabla de entradas. Establezca 0 para desactivar" "oldUsername" = "Nombre de Usuario Actual" "currentPassword" = "Contraseña Actual" "newUsername" = "Nuevo Nombre de Usuario" @@ -285,6 +287,8 @@ "subEncryptDesc" = "Encriptar las configuraciones devueltas en la suscripción." "subShowInfo" = "Mostrar información de uso" "subShowInfoDesc" = "Mostrar tráfico restante y fecha después del nombre de configuración." +"subURI" = "URI de proxy inverso" +"subURIDesc" = "Cambiar el URI base de la URL de suscripción para usar detrás de los servidores proxy" [pages.xray] "title" = "Xray Configuración" diff --git a/web/translation/translate.fa_IR.toml b/web/translation/translate.fa_IR.toml index 3dfb18c4..8d5001bd 100644 --- a/web/translation/translate.fa_IR.toml +++ b/web/translation/translate.fa_IR.toml @@ -238,6 +238,8 @@ "privateKeyPathDesc" = "باید یک مسیر مطلق باشد که با / شروع می شود " "panelUrlPath" = "آدرس روت پنل" "panelUrlPathDesc" = "باید با '/' شروع شود و با '/' تمام شود" +"pageSize" = "اندازه صفحه بندی جدول" +"pageSizeDesc" = "اندازه صفحه را برای جدول سرویس ها تعریف کنید. 0: غیرفعال" "oldUsername" = "نام کاربری فعلی" "currentPassword" = "رمز عبور فعلی" "newUsername" = "نام کاربری جدید" @@ -285,6 +287,8 @@ "subEncryptDesc" = "رمزگذاری کانفیگ های بازگشتی سابسکریپشن" "subShowInfo" = "نمایش اطلاعات مصرف" "subShowInfoDesc" = "ترافیک و زمان باقیمانده را در هر کانفیگ نمایش میدهد" +"subURI" = "آدرس پایه پروکسی معکوس" +"subURIDesc" = "آدرس پایه سابسکریپشن را برای استفاده در پشت پراکسی ها تغییر میدهد" [pages.xray] "title" = "الگوها" diff --git a/web/translation/translate.ru_RU.toml b/web/translation/translate.ru_RU.toml index 2b3de7a5..460dfa36 100644 --- a/web/translation/translate.ru_RU.toml +++ b/web/translation/translate.ru_RU.toml @@ -233,11 +233,13 @@ "panelPort" = "Порт панели" "panelPortDesc" = "Порт, используемый для отображения этой панели" "publicKeyPath" = "Путь к файлу публичного ключа сертификата панели" -"publicKeyPathDesc" = "Введите полный путь, начинающийся с " +"publicKeyPathDesc" = "Введите полный путь, начинающийся с" "privateKeyPath" = "Путь к файлу приватного ключа сертификата панели" -"privateKeyPathDesc" = "Введите полный путь, начинающийся с " +"privateKeyPathDesc" = "Введите полный путь, начинающийся с" "panelUrlPath" = "Корневой путь URL адреса панели" -"panelUrlPathDesc" = "Должен начинаться с '/' и заканчиваться на " +"panelUrlPathDesc" = "Должен начинаться с '/' и заканчиваться на" +"pageSize" = "Размер нумерации страниц" +"pageSizeDesc" = "Определить размер страницы для входящей таблицы. Установите 0, чтобы отключить" "oldUsername" = "Текущее имя пользователя" "currentPassword" = "Текущий пароль" "newUsername" = "Новое имя пользователя" @@ -285,6 +287,8 @@ "subEncryptDesc" = "Шифровать возвращенные конфиги в подписке" "subShowInfo" = "Показать информацию об использовании" "subShowInfoDesc" = "Показывать восстановленный трафик и дату после имени конфигурации" +"subURI" = "URI обратного прокси" +"subURIDesc" = "Изменить базовый URI URL-адреса подписки для использования за прокси-серверами" [pages.xray] "title" = "Xray Настройки" diff --git a/web/translation/translate.vi_VN.toml b/web/translation/translate.vi_VN.toml index f15f25a1..6c51b0e8 100644 --- a/web/translation/translate.vi_VN.toml +++ b/web/translation/translate.vi_VN.toml @@ -238,6 +238,8 @@ "privateKeyPathDesc" = "Điền vào đường dẫn tuyệt đối bắt đầu với."
"panelUrlPath" = "Đường dẫn gốc URL Bảng điều khiển"
"panelUrlPathDesc" = "Phải bắt đầu bằng '/' và kết thúc bằng."
+"pageSize" = "Kích thước phân trang"
+"pageSizeDesc" = "Xác định kích thước trang cho bảng gửi đến. Đặt 0 để tắt"
"oldUsername" = "Tên người dùng hiện tại"
"currentPassword" = "Mật khẩu hiện tại"
"newUsername" = "Tên người dùng mới"
@@ -285,6 +287,8 @@ "subEncryptDesc" = "Mã hóa các cấu hình được trả về trong đăng ký"
"subShowInfo" = "Hiển thị thông tin sử dụng"
"subShowInfoDesc" = "Hiển thị lưu lượng truy cập còn lại và ngày sau tên cấu hình"
+"subURI" = "URI proxy ngược"
+"subURIDesc" = "Thay đổi URI cơ sở của URL đăng ký để sử dụng ở phía sau proxy"
[pages.xray]
"title" = "Xray Cài đặt"
diff --git a/web/translation/translate.zh_Hans.toml b/web/translation/translate.zh_Hans.toml index e60f8964..2eeced8f 100644 --- a/web/translation/translate.zh_Hans.toml +++ b/web/translation/translate.zh_Hans.toml @@ -238,6 +238,8 @@ "privateKeyPathDesc" = "填写一个 '/' 开头的绝对路径" "panelUrlPath" = "面板 url 根路径" "panelUrlPathDesc" = "必须以 '/' 开头,以 '/' 结尾" +"pageSize" = "分页大小" +"pageSizeDesc" = "定义入站表的页面大小。设置 0 表示禁用" "oldUsername" = "原用户名" "currentPassword" = "原密码" "newUsername" = "新用户名" @@ -285,6 +287,8 @@ "subEncryptDesc" = "在订阅中加密返回的配置" "subShowInfo" = "显示使用信息" "subShowInfoDesc" = "在配置名称后显示剩余流量和日期" +"subURI" = "反向代理 URI" +"subURIDesc" = "更改订阅 URL 的基本 URI 以在代理后面使用" [pages.xray] "title" = "Xray 设置" |
