diff options
| author | MHSanaei <ho3ein.sanaei@gmail.com> | 2023-12-13 18:57:36 +0300 |
|---|---|---|
| committer | MHSanaei <ho3ein.sanaei@gmail.com> | 2023-12-13 19:03:11 +0300 |
| commit | 8d18c8e98f1b6531d1997feb6933419d71401968 (patch) | |
| tree | 1283d10c68f3a9b9b2cbeeec95fb34a84e9689e3 | |
| parent | 82e2241bdd9552f57d24c8de4fce6c5320efba4c (diff) | |
[gui] redesign forms
Co-Authored-By: Alireza Ahmadi <alireza7@gmail.com>
32 files changed, 1442 insertions, 2385 deletions
diff --git a/web/assets/css/custom.css b/web/assets/css/custom.css index ae2dbf16..b633d644 100644 --- a/web/assets/css/custom.css +++ b/web/assets/css/custom.css @@ -55,7 +55,7 @@ style attribute { } .ant-table-tbody > tr > td, .ant-table-thead > tr > th { - padding: 12px 16px; + padding: 12px 8px; overflow-wrap: break-word; } .ant-table-thead > tr > th { @@ -93,7 +93,6 @@ style attribute { .ant-table-body { overflow-x: auto !important; } - .ant-card-hoverable { cursor: auto; cursor: pointer; @@ -133,6 +132,13 @@ style attribute { margin: 0.5rem; padding: 0.5rem; } + .ant-modal-body { + padding: 10px; + } + .ant-form-item-label { + line-height: 1.5; + padding: 8px 0 0; + } } .ant-layout-content { @@ -410,6 +416,10 @@ style attribute { background-color: white; } +.ant-form-item { + margin-bottom: 0; +} + .ant-setting-textarea { margin-top: 1.5rem; } @@ -802,12 +812,6 @@ style attribute { border-color: #fec093; } -.ant-modal-confirm-confirm .ant-modal-confirm-body>.anticon, .ant-modal-confirm-warning .ant-modal-confirm-body>.anticon, -.ant-alert-warning .ant-alert-icon, -.has-warning.has-feedback .ant-form-item-children-icon { - color: #f37b24; -} - .dark .has-warning .ant-input, .dark .has-warning .ant-input:hover { border-color: #784e1d; @@ -1045,53 +1049,3 @@ li.ant-select-dropdown-menu-item:empty:after { .ant-input-number { overflow: clip; } - -.tag-of-wrap { - text-wrap: pretty; - overflow-wrap: anywhere; - max-width: 200px; -} - -.tag-of-wrap-l { - text-wrap: pretty; - overflow-wrap: anywhere; - max-width: 350px; -} - -.ant-modal-body, -.ant-collapse-content>.ant-collapse-content-box { - overflow-x: auto; -} - -.ant-calendar-year-panel-year:hover, -.ant-calendar-decade-panel-decade:hover, -.ant-calendar-month-panel-month:hover, -.ant-dropdown-menu-item:hover, -.ant-dropdown-menu-submenu-title:hover, -.ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled), -.ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled), -.ant-table-tbody - > tr.ant-table-row-hover:not(.ant-table-expanded-row):not( - .ant-table-row-selected - ) - > td, -.ant-table-tbody - > tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) - > td, -.ant-table-thead - > tr.ant-table-row-hover:not(.ant-table-expanded-row):not( - .ant-table-row-selected - ) - > td, -.ant-table-thead - > tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) - > td { - background-color: rgb(232 244 242); -} - -.dark .ant-dropdown-menu-item:hover, -.dark .ant-dropdown-menu-submenu-title:hover, -.dark .ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled), -.dark .ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled) { - background-color: #313f5a; -} diff --git a/web/assets/js/model/outbound.js b/web/assets/js/model/outbound.js index 75d3b878..5aad52dd 100644 --- a/web/assets/js/model/outbound.js +++ b/web/assets/js/model/outbound.js @@ -476,7 +476,7 @@ class Outbound extends CommonClass { if(data.length !=2) return null; switch(data[0].toLowerCase()){ case Protocols.VMess: - return this.fromVmessLink(JSON.parse(atob(data[1]))); + return this.fromVmessLink(JSON.parse(Base64.decode(data[1]))); case Protocols.VLESS: case Protocols.Trojan: case 'ss': @@ -493,8 +493,8 @@ class Outbound extends CommonClass { if (network === 'tcp') { stream.tcp = new TcpStreamSettings( json.type, - json.host ? json.host.split(','): [], - json.path ? json.path.split(','): []); + json.host ?? '', + json.path ?? ''); } else if (network === 'kcp') { stream.kcp = new KcpStreamSettings(); stream.type = json.type; @@ -505,7 +505,7 @@ class Outbound extends CommonClass { stream.network = 'http' stream.http = new HttpStreamSettings( json.path, - json.host ? json.host.split(',') : []); + json.host); } else if (network === 'quic') { stream.quic = new QuicStreamSettings( json.host ? json.host : 'none', @@ -570,7 +570,7 @@ class Outbound extends CommonClass { let sni=url.searchParams.get('sni') ?? ''; let sid=url.searchParams.get('sid') ?? ''; let spx=url.searchParams.get('spx') ?? ''; - stream.tls = new RealityStreamSettings(pbk, fp, sni, sid, spx); + stream.reality = new RealityStreamSettings(pbk, fp, sni, sid, spx); } let data = link.split('?'); diff --git a/web/assets/js/model/xray.js b/web/assets/js/model/xray.js index 9478312e..e0c8a912 100644 --- a/web/assets/js/model/xray.js +++ b/web/assets/js/model/xray.js @@ -602,7 +602,7 @@ class XtlsStreamSettings extends XrayCommonClass { alpn=[ALPN_OPTION.H2,ALPN_OPTION.HTTP1], settings=new XtlsStreamSettings.Settings()) { super(); - this.server = serverName; + this.sni = serverName; this.certs = certificates; this.alpn = alpn; this.settings = settings; @@ -636,7 +636,7 @@ class XtlsStreamSettings extends XrayCommonClass { toJson() { return { - serverName: this.server, + serverName: this.sni, certificates: XtlsStreamSettings.toJsonArray(this.certs), alpn: this.alpn, settings: this.settings, @@ -1081,7 +1081,7 @@ class Inbound extends XrayCommonClass { get serverName() { if (this.stream.isTls) return this.stream.tls.sni; - if (this.stream.isXtls) return this.stream.xtls.server; + if (this.stream.isXtls) return this.stream.xtls.sni; if (this.stream.isReality) return this.stream.reality.serverNames; return ""; } @@ -1326,8 +1326,8 @@ class Inbound extends XrayCommonClass { if(this.stream.xtls.settings.allowInsecure){ params.set("allowInsecure", "1"); } - if (!ObjectUtil.isEmpty(this.stream.xtls.server)){ - params.set("sni", this.stream.xtls.server); + if (!ObjectUtil.isEmpty(this.stream.xtls.sni)){ + params.set("sni", this.stream.xtls.sni); } params.set("flow", flow); } @@ -1533,8 +1533,8 @@ class Inbound extends XrayCommonClass { if(this.stream.xtls.settings.allowInsecure){ params.set("allowInsecure", "1"); } - if (this.stream.xtls.settings.serverName !== ''){ - params.set("sni", this.stream.xtls.settings.serverName); + if (!ObjectUtil.isEmpty(this.stream.xtls.sni)){ + params.set("sni", this.stream.xtls.sni); } params.set("flow", flow); } diff --git a/web/html/login.html b/web/html/login.html index 900dd176..520bbcb4 100644 --- a/web/html/login.html +++ b/web/html/login.html @@ -27,6 +27,7 @@ text-align: center; align-items: center; justify-content: center; + width: 100%; } .title { font-size: 32px; @@ -92,6 +93,10 @@ .dark h1 { color: rgba(255, 255, 255, 0.85); } + .ant-form-item { + margin-bottom: 16px; + } + .ant-btn-primary-login { color: #008771; background-color: #e8f4f2; diff --git a/web/html/xui/client_bulk_modal.html b/web/html/xui/client_bulk_modal.html index e0295110..1fa64306 100644 --- a/web/html/xui/client_bulk_modal.html +++ b/web/html/xui/client_bulk_modal.html @@ -2,206 +2,123 @@ <a-modal id="client-bulk-modal" v-model="clientsBulkModal.visible" :title="clientsBulkModal.title" @ok="clientsBulkModal.ok" :confirm-loading="clientsBulkModal.confirmLoading" :closable="true" :mask-closable="false" :ok-text="clientsBulkModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme"> - <a-form layout="inline"> - <table width="100%" class="ant-table-tbody"> - <tr> - <td>{{ i18n "pages.client.method" }}</td> - <td> - <a-form-item> - <a-select v-model="clientsBulkModal.emailMethod" buttonStyle="solid" style="width: 250px" - :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option :value="0">Random</a-select-option> - <a-select-option :value="1">Random+Prefix</a-select-option> - <a-select-option :value="2">Random+Prefix+Num</a-select-option> - <a-select-option :value="3">Random+Prefix+Num+Postfix</a-select-option> - <a-select-option :value="4">Prefix+Num+Postfix</a-select-option> - </a-select> - </a-form-item> - </td> - </tr> - <tr v-if="clientsBulkModal.emailMethod>1"> - <td>{{ i18n "pages.client.first" }}</td> - <td> - <a-form-item> - <a-input-number v-model="clientsBulkModal.firstNum" :min="1"></a-input-number> - </a-form-item> - </td> - </tr> - <tr v-if="clientsBulkModal.emailMethod>1"> - <td>{{ i18n "pages.client.last" }}</td> - <td> - <a-form-item> - <a-input-number v-model="clientsBulkModal.lastNum" - :min="clientsBulkModal.firstNum"></a-input-number> - </a-form-item> - </td> - </tr> - <tr v-if="clientsBulkModal.emailMethod>0"> - <td>{{ i18n "pages.client.prefix" }}</td> - <td> - <a-form-item> - <a-input v-model="clientsBulkModal.emailPrefix" style="width: 250px"></a-input> - </a-form-item> - </td> - </tr> - <tr v-if="clientsBulkModal.emailMethod>2"> - <td>{{ i18n "pages.client.postfix" }}</td> - <td> - <a-form-item> - <a-input v-model="clientsBulkModal.emailPostfix" style="width: 250px"></a-input> - </a-form-item> - </td> - </tr> - <tr v-if="clientsBulkModal.emailMethod < 2"> - <td>{{ i18n "pages.client.clientCount" }}</td> - <td> - <a-form-item> - <a-input-number v-model="clientsBulkModal.quantity" :min="1" :max="100"></a-input-number> - </a-form-item> - </td> - </tr> - <tr v-if="clientsBulkModal.inbound.canEnableTlsFlow()"> - <td>Flow</td> - <td> - <a-form-item> - <a-select v-model="clientsBulkModal.flow" style="width: 250px" - :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option value="" selected>{{ i18n "none" }}</a-select-option> - <a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> - </a-select> - </a-form-item> - </td> - </tr> - <tr v-if="app.subSettings.enable"> - <td>Subscription - <a-tooltip> - <template slot="title"> - <span>{{ i18n "pages.inbounds.subscriptionDesc" }}</span> - </template> - <a-icon @click="client.subId = RandomUtil.randomLowerAndNum(16)" type="sync"></a-icon> - </a-tooltip> - </td> - <td> - <a-form-item> - <a-input v-model.trim="clientsBulkModal.subId" style="width: 250px"></a-input> - </a-form-item> - </td> - </tr> - <tr v-if="app.tgBotEnable"> - <td>Telegram ID - <a-tooltip> - <template slot="title"> - <span>{{ i18n "pages.inbounds.telegramDesc" }}</span> - </template> - <a-icon type="question-circle" theme="filled"></a-icon> - </a-tooltip> - </td> - <td> - <a-form-item> - <a-input v-model.trim="clientsBulkModal.tgId" style="width: 250px"></a-input> - </a-form-item> - </td> - </tr> - <tr> - <td> - <label> - <span>{{ i18n "pages.inbounds.IPLimit" }}</span> - <a-tooltip> - <template slot="title"> - <span>{{ i18n "pages.inbounds.IPLimitDesc" }}</span> - </template> - <a-icon type="question-circle" theme="filled"></a-icon> - </a-tooltip> - </label> - </td> - <td> - <a-form-item> - <a-input-number v-model="clientsBulkModal.limitIp" min="0"></a-input-number> - </a-form-item> - </td> - </tr> - <tr> - <td v-if="clientsBulkModal.inbound.xtls"> - <label>Flow</label> - </td> - <td v-if="clientsBulkModal.inbound.xtls"> - <a-form-item> - <a-select v-model="clientsBulkModal.flow" style="width: 200px" - :dropdown-class-name="themeSwitcher.currentTheme"> - <a-select-option value="">{{ i18n "none" }}</a-select-option> - <a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> - </a-select> - </a-form-item> - </td> - </tr> - <tr> - <td> - <span>{{ i18n "pages.inbounds.totalFlow" }}</span>(GB) - <a-tooltip> - <template slot="title"> - 0 <span>{{ i18n "pages.inbounds.meansNoLimit" }}</span> - </template> - <a-icon type="question-circle" theme="filled"></a-icon> - </a-tooltip> - </td> - <td> - <a-form-item> - <a-input-number v-model="clientsBulkModal.totalGB" :min="0"></a-input-number> - </a-form-item> - </td> - </tr> - <tr> - <td>{{ i18n "pages.client.delayedStart" }}</td> - <td> - <a-form-item> - <a-switch v-model="clientsBulkModal.delayedStart" - @click="clientsBulkModal.expiryTime=0"></a-switch> - </a-form-item> - </td> - </tr> - <tr v-if="clientsBulkModal.delayedStart"> - <td>{{ i18n "pages.client.expireDays" }}</td> - <td> - <a-form-item> - <a-input-number v-model.number="delayedExpireDays" :min="0"></a-input-number> - </a-form-item> - </td> - </tr> - <tr v-else> - <td> - <span>{{ i18n "pages.inbounds.expireDate" }}</span> - <a-tooltip> - <template slot="title"> - <span>{{ i18n "pages.inbounds.leaveBlankToNeverExpire" }}</span> - </template> - <a-icon type="question-circle" theme="filled"></a-icon> - </a-tooltip> - </td> - <td> - <a-form-item> - <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" - :dropdown-class-name="themeSwitcher.currentTheme" v-model="clientsBulkModal.expiryTime" - style="width: 250px;"></a-date-picker> - </a-form-item> - </td> - </tr> - <tr v-if="clientsBulkModal.expiryTime != 0"> - <td> - <span>{{ i18n "pages.client.renew" }}</span> - <a-tooltip> - <template slot="title"> - <span>{{ i18n "pages.client.renewDesc" }}</span> - </template> - <a-icon type="question-circle" theme="filled"></a-icon> - </a-tooltip> - </td> - <td> - <a-form-item> - <a-input-number v-model.number="clientsBulkModal.reset" :min="0"></a-input-number> - </a-form-item> - </td> - </tr> - </table> + <a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> + <a-form-item label='{{ i18n "pages.client.method" }}'> + <a-select v-model="clientsBulkModal.emailMethod" buttonStyle="solid" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option :value="0">Random</a-select-option> + <a-select-option :value="1">Random+Prefix</a-select-option> + <a-select-option :value="2">Random+Prefix+Num</a-select-option> + <a-select-option :value="3">Random+Prefix+Num+Postfix</a-select-option> + <a-select-option :value="4">Prefix+Num+Postfix</a-select-option> + </a-select> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.first" }}' v-if="clientsBulkModal.emailMethod>1"> + <a-input-number v-model="clientsBulkModal.firstNum" :min="1"></a-input-number> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.last" }}' v-if="clientsBulkModal.emailMethod>1"> + <a-input-number v-model="clientsBulkModal.lastNum" :min="clientsBulkModal.firstNum"></a-input-number> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.prefix" }}' v-if="clientsBulkModal.emailMethod>0"> + <a-input v-model="clientsBulkModal.emailPrefix"></a-input> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.postfix" }}' v-if="clientsBulkModal.emailMethod>2"> + <a-input v-model="clientsBulkModal.emailPostfix"></a-input> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.clientCount" }}' v-if="clientsBulkModal.emailMethod < 2"> + <a-input-number v-model="clientsBulkModal.quantity" :min="1" :max="100"></a-input-number> + </a-form-item> + <a-form-item label='Flow' v-if="clientsBulkModal.inbound.canEnableTlsFlow()"> + <a-select v-model="clientsBulkModal.flow" :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option value="" selected>{{ i18n "none" }}</a-select-option> + <a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> + </a-select> + </a-form-item> + <a-form-item label='Flow' v-if="clientsBulkModal.inbound.xtls"> + <a-select v-model="clientsBulkModal.flow" :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option value="" selected>{{ i18n "none" }}</a-select-option> + <a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> + </a-select> + </a-form-item> + <a-form-item v-if="app.subSettings.enable"> + <template slot="label"> + <a-tooltip> + <template slot="title"> + <span>{{ i18n "pages.inbounds.subscriptionDesc" }}</span> + </template> + Subscription + <a-icon @click="clientsBulkModal.subId = RandomUtil.randomLowerAndNum(16)" type="sync"></a-icon> + </a-tooltip> + </template> + <a-input v-model.trim="clientsBulkModal.subId"></a-input> + </a-form-item> + <a-form-item v-if="app.tgBotEnable"> + <template slot="label"> + <a-tooltip> + <template slot="title"> + <span>{{ i18n "pages.inbounds.telegramDesc" }}</span> + </template> + Telegram ID + <a-icon type="question-circle" theme="filled"></a-icon> + </a-tooltip> + </template> + <a-input v-model.trim="clientsBulkModal.tgId"></a-input> + </a-form-item> + <a-form-item> + <template slot="label"> + <a-tooltip> + <template slot="title"> + <span>{{ i18n "pages.inbounds.IPLimitDesc" }}</span> + </template> + <span>{{ i18n "pages.inbounds.IPLimit" }} </span> + <a-icon type="question-circle" theme="filled"></a-icon> + </a-tooltip> + </template> + <a-input-number v-model="clientsBulkModal.limitIp" min="0"></a-input-number> + </a-form-item> + <a-form-item> + <template slot="label"> + <a-tooltip> + <template slot="title"> + 0 <span>{{ i18n "pages.inbounds.meansNoLimit" }}</span> + </template> + {{ i18n "pages.inbounds.totalFlow" }} (GB) + <a-icon type="question-circle" theme="filled"></a-icon> + </a-tooltip> + </template> + <a-input-number v-model="clientsBulkModal.totalGB" :min="0"></a-input-number> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.delayedStart" }}'> + <a-switch v-model="clientsBulkModal.delayedStart" @click="clientsBulkModal.expiryTime=0"></a-switch> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.expireDays" }}' v-if="clientsBulkModal.delayedStart"> + <a-input-number v-model.number="delayedExpireDays" :min="0"></a-input-number> + </a-form-item> + <a-form-item v-else> + <template slot="label"> + <a-tooltip> + <template slot="title"> + <span>{{ i18n "pages.inbounds.leaveBlankToNeverExpire" }}</span> + </template> + {{ i18n "pages.inbounds.expireDate" }} + <a-icon type="question-circle" theme="filled"></a-icon> + </a-tooltip> + </template> + <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" + :dropdown-class-name="themeSwitcher.currentTheme" v-model="clientsBulkModal.expiryTime"></a-date-picker> + </a-form-item> + <a-form-item v-if="clientsBulkModal.expiryTime != 0"> + <template slot="label"> + <span>{{ i18n "pages.client.renew" }}</span> + <a-tooltip> + <template slot="title"> + <span>{{ i18n "pages.client.renewDesc" }}</span> + </template> + <a-icon type="question-circle" theme="filled"></a-icon> + </a-tooltip> + </template> + <a-input-number v-model.number="clientsBulkModal.reset" :min="0"></a-input-number> + </a-form-item> </a-form> </a-modal> <script> diff --git a/web/html/xui/form/client.html b/web/html/xui/form/client.html index 0ade5241..e5236acc 100644 --- a/web/html/xui/form/client.html +++ b/web/html/xui/form/client.html @@ -1,223 +1,173 @@ {{define "form/client"}} -<a-form layout="inline" v-if="client"> - <table width="100%" class="ant-table-tbody"> - <tr> - <td>{{ i18n "pages.inbounds.enable" }}</td> - <td> - <a-form-item> - <a-switch v-model="client.enable"></a-switch> - </a-form-item> - </td> - </tr> - <tr> - <td> - <span>{{ i18n "pages.inbounds.email" }}</span> - <a-tooltip> - <template slot="title"> - <span>{{ i18n "pages.inbounds.emailDesc" }}</span> - </template> - <a-icon type="sync" @click="client.email = RandomUtil.randomLowerAndNum(9)"></a-icon> - </a-tooltip> - </td> - <td> - <a-form-item> - <a-input v-model.trim="client.email" style="width: 250px"></a-input> - </a-form-item> - </td> - </tr> - <tr v-if="inbound.protocol === Protocols.TROJAN || inbound.protocol === Protocols.SHADOWSOCKS"> - <td>password - <a-icon v-if="inbound.protocol === Protocols.SHADOWSOCKS" @click="client.password = RandomUtil.randomShadowsocksPassword()" type="sync"> </a-icon> - <a-icon v-if="inbound.protocol === Protocols.TROJAN" @click="client.password = RandomUtil.randomSeq(10)" type="sync"> </a-icon> - </td> - <td> - <a-form-item> - <a-input v-model.trim="client.password" style="width: 250px"></a-input> - </a-form-item> - </td> - </tr> - <tr v-if="inbound.protocol === Protocols.VMESS || inbound.protocol === Protocols.VLESS"> - <td>ID <a-icon @click="client.id = RandomUtil.randomUUID()" type="sync"></a-icon></td> - <td> - <a-input v-model.trim="client.id" style="width: 250px;"></a-input> - </td> - </tr> - <tr v-if="client.email && app.subSettings.enable"> - <td>Subscription <a-icon @click="client.subId = RandomUtil.randomLowerAndNum(16)" type="sync"></a-icon></td> - <td> - <a-tooltip> - <template slot="title"> -
|
