diff options
Diffstat (limited to 'web/html/index.html')
| -rw-r--r-- | web/html/index.html | 113 |
1 files changed, 103 insertions, 10 deletions
diff --git a/web/html/index.html b/web/html/index.html index 0a36b9cb..62e9453b 100644 --- a/web/html/index.html +++ b/web/html/index.html @@ -139,7 +139,7 @@ <a-icon type="reload"></a-icon> <span v-if="!isMobile">{{ i18n "pages.index.restartXray" }}</span> </a-space> - <a-space direction="horizontal" @click="openSelectV2rayVersion" class="jc-center"> + <a-space direction="horizontal" @click="openSelectV2rayVersion()" class="jc-center"> <a-icon type="tool"></a-icon> <span v-if="!isMobile"> [[ status.xray.version != 'Unknown' ? `v${status.xray.version}` : '{{ i18n @@ -169,6 +169,14 @@ </a-col> <a-col :sm="24" :lg="12"> <a-card title='3X-UI' hoverable> + <template v-if="panelUpdateModal.info.updateAvailable" #extra> + <a-tooltip :overlay-class-name="themeSwitcher.currentTheme" :title='`{{ i18n "pages.index.updatePanel" }}: ${panelUpdateModal.info.latestVersion}`'> + <a-tag color="orange" style="cursor:pointer;margin:0" @click="openPanelUpdate"> + <a-icon type="cloud-download"></a-icon>[[ panelUpdateModal.info.latestVersion ]] + <span v-if="!isMobile">{{ i18n "pages.index.updatePanel" }}</span> + </a-tag> + </a-tooltip> + </template> <a rel="noopener" href="https://github.com/MHSanaei/3x-ui/releases" target="_blank"> <a-tag color="green"> <span>v{{ .cur_ver }}</span> @@ -317,9 +325,36 @@ </a-spin> </a-layout-content> </a-layout> - <a-modal id="version-modal" v-model="versionModal.visible" title='{{ i18n "pages.index.xraySwitch" }}' + <a-modal id="panel-update-modal" v-model="panelUpdateModal.visible" title='{{ i18n "pages.index.updatePanel" }}' + :closable="true" @ok="() => panelUpdateModal.visible = false" :class="themeSwitcher.currentTheme" footer=""> + <a-alert type="warning" class="mb-12 w-100" message='{{ i18n "pages.index.panelUpdateDesc" }}' + show-icon></a-alert> + <a-list class="ant-version-list w-100" bordered> + <a-list-item class="ant-version-list-item"> + <span>{{ i18n "pages.index.currentPanelVersion" }}</span> + <a-tag color="green">v[[ panelUpdateModal.info.currentVersion || '{{ .cur_ver }}' ]]</a-tag> + </a-list-item> + <a-list-item class="ant-version-list-item" v-if="panelUpdateModal.info.updateAvailable"> + <span>{{ i18n "pages.index.latestPanelVersion" }}</span> + <a-tag color="purple"> + [[ panelUpdateModal.info.latestVersion || '-' ]] + </a-tag> + </a-list-item> + <a-list-item class="ant-version-list-item" v-else> + <span>{{ i18n "pages.index.panelUpToDate" }}</span> + <a-tag color="green">{{ i18n "pages.index.upToDate" }}</a-tag> + </a-list-item> + </a-list> + <div class="mt-5 d-flex justify-end"> + <a-button type="primary" icon="cloud-download" :disabled="!panelUpdateModal.info.updateAvailable" + @click="updatePanel"> + {{ i18n "pages.index.updatePanel" }} + </a-button> + </div> + </a-modal> + <a-modal id="version-modal" v-model="versionModal.visible" title='{{ i18n "pages.index.xrayUpdates" }}' :closable="true" @ok="() => versionModal.visible = false" :class="themeSwitcher.currentTheme" footer=""> - <a-collapse default-active-key="1"> + <a-collapse accordion :active-key="versionModal.activeKey" @change="key => versionModal.activeKey = key"> <a-collapse-panel key="1" header='Xray'> <a-alert type="warning" class="mb-12 w-100" message='{{ i18n "pages.index.xraySwitchClickDesk" }}' show-icon></a-alert> @@ -799,9 +834,11 @@ const versionModal = { visible: false, + activeKey: '1', versions: [], - show(versions) { + show(versions, activeKey = '1') { this.visible = true; + this.activeKey = activeKey; this.versions = versions; }, hide() { @@ -809,6 +846,24 @@ }, }; + const panelUpdateModal = { + visible: false, + info: { + currentVersion: '{{ .cur_ver }}', + latestVersion: '', + updateAvailable: false, + }, + show(info) { + this.visible = true; + if (info) { + this.info = info; + } + }, + hide() { + this.visible = false; + }, + }; + const logModal = { visible: false, logs: [], @@ -958,11 +1013,12 @@ spinning: false }, status: new Status(), - cpuHistory: [], // small live widget history - cpuHistoryLong: [], // aggregated points from backend - cpuHistoryLabels: [], - cpuHistoryModal: { visible: false, bucket: 2 }, + cpuHistory: [], // small live widget history + cpuHistoryLong: [], // aggregated points from backend + cpuHistoryLabels: [], + cpuHistoryModal: { visible: false, bucket: 2 }, versionModal, + panelUpdateModal, logModal, xraylogModal, backupModal, @@ -1049,16 +1105,25 @@ console.error('Failed to fetch bucketed cpu history', e) } }, - async openSelectV2rayVersion() { + async openSelectV2rayVersion(activeKey = '1') { this.loading(true); const msg = await HttpUtil.get('/panel/api/server/getXrayVersion'); this.loading(false); if (!msg.success) { return; } - versionModal.show(msg.obj); + versionModal.show(msg.obj, activeKey); this.loadCustomGeo(); }, + async openPanelUpdate() { + this.loading(true); + const msg = await HttpUtil.get('/panel/api/server/getPanelUpdateInfo'); + this.loading(false); + if (!msg.success) { + return; + } + panelUpdateModal.show(msg.obj); + }, customGeoFormatTime(ts) { if (!ts) return ''; return typeof moment !== 'undefined' ? moment(ts * 1000).format('YYYY-MM-DD HH:mm') : String(ts); @@ -1195,6 +1260,27 @@ }, }); }, + updatePanel() { + this.$confirm({ + title: '{{ i18n "pages.index.panelUpdateDialog" }}', + content: '{{ i18n "pages.index.panelUpdateDialogDesc" }}' + .replace('#version#', panelUpdateModal.info.latestVersion || ''), + okText: '{{ i18n "confirm"}}', + class: themeSwitcher.currentTheme, + cancelText: '{{ i18n "cancel"}}', + onOk: async () => { + panelUpdateModal.hide(); + this.loading(true, '{{ i18n "pages.index.dontRefresh"}}'); + const msg = await HttpUtil.post('/panel/api/server/updatePanel'); + if (!msg.success) { + this.loading(false); + return; + } + await PromiseUtil.sleep(15000); + window.location.reload(); + }, + }); + }, updateGeofile(fileName) { const isSingleFile = !!fileName; this.$confirm({ @@ -1346,6 +1432,13 @@ // Initial status fetch await this.getStatus(); + // Silently check for panel updates so the indicator shows on load + HttpUtil.get('/panel/api/server/getPanelUpdateInfo').then(msg => { + if (msg && msg.success && msg.obj) { + panelUpdateModal.info = msg.obj; + } + }); + // Setup WebSocket for real-time updates if (window.wsClient) { window.wsClient.connect(); |
