Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion core/app/api/v2/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,29 @@ func (b *BaseApi) GetUpgradeInfo(c *gin.Context) {
helper.SuccessWithData(c, info)
}

// @Tags System Setting
// @Summary Load upgrade notes
// @Success 200 {array} dto.ReleasesNotes
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /core/settings/upgrade/releases [get]
func (b *BaseApi) LoadRelease(c *gin.Context) {
notes, err := upgradeService.LoadRelease()
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, notes)
}

// @Tags System Setting
// @Summary Load release notes by version
// @Accept json
// @Param request body dto.Upgrade true "request"
// @Success 200 {string} notes
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /core/settings/upgrade [get]
// @Router /core/settings/upgrade/notes [post]
func (b *BaseApi) GetNotesByVersion(c *gin.Context) {
var req dto.Upgrade
if err := helper.CheckBindAndValidate(&req, c); err != nil {
Expand Down
9 changes: 9 additions & 0 deletions core/app/dto/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,15 @@ type Upgrade struct {
Version string `json:"version" validate:"required"`
}

type ReleasesNotes struct {
Version string `json:"version"`
CreatedAt string `json:"createdAt"`
Content string `json:"content"`
NewCount int `json:"newCount"`
OptimizationCount int `json:"optimizationCount"`
FixCount int `json:"fixCount"`
}

type ProxyUpdate struct {
ProxyUrl string `json:"proxyUrl"`
ProxyType string `json:"proxyType"`
Expand Down
62 changes: 62 additions & 0 deletions core/app/service/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package service
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path"
Expand All @@ -29,6 +30,7 @@ type IUpgradeService interface {
Rollback(req dto.OperateByID) error
LoadNotes(req dto.Upgrade) (string, error)
SearchUpgrade() (*dto.UpgradeInfo, error)
LoadRelease() ([]dto.ReleasesNotes, error)
}

func NewIUpgradeService() IUpgradeService {
Expand Down Expand Up @@ -208,6 +210,66 @@ func (u *UpgradeService) Rollback(req dto.OperateByID) error {
return nil
}

type noteHelper struct {
Docs []noteDetailHelper `json:"docs"`
}
type noteDetailHelper struct {
Location string `json:"location"`
Text string `json:"text"`
Title string `json:"title"`
}

func (u *UpgradeService) LoadRelease() ([]dto.ReleasesNotes, error) {
var notes []dto.ReleasesNotes
resp, err := req_helper.HandleGet("https://1panel.cn/docs/v2/search/search_index.json")
if err != nil {
return notes, err
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return notes, err
}
defer resp.Body.Close()
var nodeItem noteHelper
if err := json.Unmarshal(body, &nodeItem); err != nil {
return notes, err
}
for _, item := range nodeItem.Docs {
if !strings.HasPrefix(item.Location, "changelog/#v") {
continue
}
itemNote := analyzeDoc(item.Title, item.Text)
if len(itemNote.CreatedAt) != 0 {
notes = append(notes, analyzeDoc(item.Title, item.Text))
}
}

return notes, nil
}

func analyzeDoc(version, content string) dto.ReleasesNotes {
var item dto.ReleasesNotes
parts := strings.Split(content, "<p>")
if len(parts) < 3 {
return item
}
item.CreatedAt = strings.ReplaceAll(strings.TrimSpace(parts[1]), "</p>", "")
for i := 1; i < len(parts); i++ {
if strings.Contains(parts[i], "问题修复") {
item.FixCount = strings.Count(parts[i], "<li>")
}
if strings.Contains(parts[i], "新增功能") {
item.NewCount = strings.Count(parts[i], "<li>")
}
if strings.Contains(parts[i], "功能优化") {
item.OptimizationCount = strings.Count(parts[i], "<li>")
}
}
item.Content = strings.Replace(content, fmt.Sprintf("<p>%s</p>", item.CreatedAt), "", 1)
item.Version = version
return item
}

func (u *UpgradeService) handleBackup(originalDir string) error {
if err := files.CopyItem(false, true, "/usr/local/bin/1panel-core", originalDir); err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions core/router/ro_setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func (s *SettingRouter) InitRouter(Router *gin.RouterGroup) {

settingRouter.POST("/upgrade", baseApi.Upgrade)
settingRouter.POST("/upgrade/notes", baseApi.GetNotesByVersion)
settingRouter.GET("/upgrade/releases", baseApi.LoadRelease)
settingRouter.GET("/upgrade", baseApi.GetUpgradeInfo)
settingRouter.POST("/api/config/generate/key", baseApi.GenerateApiKey)
settingRouter.POST("/api/config/update", baseApi.UpdateApiConfig)
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/api/interface/setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,14 @@ export namespace Setting {
isBound: boolean;
name: string;
}
export interface ReleasesNotes {
Version: string;
CreatedAt: string;
Content: string;
NewCount: number;
OptimizationCount: number;
FixCount: number;
}

export interface LicenseBind {
nodeID: number;
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/api/modules/setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ export const loadUpgradeInfo = () => {
export const loadReleaseNotes = (version: string) => {
return http.post<string>(`/core/settings/upgrade/notes`, { version: version });
};
export const listReleases = () => {
return http.get<Array<Setting.ReleasesNotes>>(`/core/settings/upgrade/releases`);
};
export const upgrade = (version: string) => {
return http.post(`/core/settings/upgrade`, { version: version });
};
Expand Down
16 changes: 12 additions & 4 deletions frontend/src/assets/iconfont/iconfont.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
@font-face {
font-family: "iconfont"; /* Project id 4776196 */
src: url('iconfont.woff2?t=1752473267421') format('woff2'),
url('iconfont.woff?t=1752473267421') format('woff'),
url('iconfont.ttf?t=1752473267421') format('truetype'),
url('iconfont.svg?t=1752473267421#iconfont') format('svg');
src: url('iconfont.woff2?t=1755181498446') format('woff2'),
url('iconfont.woff?t=1755181498446') format('woff'),
url('iconfont.ttf?t=1755181498446') format('truetype'),
url('iconfont.svg?t=1755181498446#iconfont') format('svg');
}

.iconfont {
Expand All @@ -14,6 +14,14 @@
-moz-osx-font-smoothing: grayscale;
}

.p-featureshitu:before {
content: "\e63e";
}

.p-youhuawendang:before {
content: "\e7c4";
}

.p-cluster-3:before {
content: "\e706";
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/assets/iconfont/iconfont.js

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions frontend/src/assets/iconfont/iconfont.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@
"css_prefix_text": "p-",
"description": "",
"glyphs": [
{
"icon_id": "18536446",
"name": "feature视图",
"font_class": "featureshitu",
"unicode": "e63e",
"unicode_decimal": 58942
},
{
"icon_id": "18133027",
"name": "优化文档",
"font_class": "youhuawendang",
"unicode": "e7c4",
"unicode_decimal": 59332
},
{
"icon_id": "88609",
"name": "cluster-3",
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/assets/iconfont/iconfont.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/iconfont/iconfont.ttf
Binary file not shown.
Binary file modified frontend/src/assets/iconfont/iconfont.woff
Binary file not shown.
Binary file modified frontend/src/assets/iconfont/iconfont.woff2
Binary file not shown.
6 changes: 4 additions & 2 deletions frontend/src/components/system-upgrade/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<el-link underline="never" type="primary" @click="toLxware">
{{ $t(!isMasterPro ? 'license.community' : 'license.pro') }}
</el-link>
<el-link underline="never" class="version" type="primary" @click="copyText(version)">
<el-link underline="never" class="version" type="primary" @click="releasesRef.acceptParams()">
{{ version }}
</el-link>
<el-badge is-dot class="-mt-0.5" :hidden="version === 'Waiting' || !globalStore.hasNewVersion">
Expand All @@ -36,22 +36,24 @@
</div>

<Upgrade ref="upgradeRef" @search="search" />
<Releases ref="releasesRef" />
</div>
</template>

<script setup lang="ts">
import { getSettingInfo, loadUpgradeInfo } from '@/api/modules/setting';
import Upgrade from '@/components/system-upgrade/upgrade/index.vue';
import Releases from '@/components/system-upgrade/releases/index.vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { copyText } from '@/utils/util';
import { onMounted, ref } from 'vue';
import { GlobalStore } from '@/store';
import { storeToRefs } from 'pinia';

const globalStore = GlobalStore();
const { docsUrl } = storeToRefs(globalStore);
const upgradeRef = ref();
const releasesRef = ref();
const isMasterPro = computed(() => {
return globalStore.isMasterPro();
});
Expand Down
104 changes: 104 additions & 0 deletions frontend/src/components/system-upgrade/releases/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<template>
<DrawerPro v-model="drawerVisible" :header="$t('app.version')" @close="handleClose" size="large">
<div class="note">
<el-collapse v-model="currentVersion" :accordion="true" v-loading="loading">
<div v-for="(item, index) in notes" :key="index">
<el-collapse-item :name="index">
<template #title>
<div>
<span class="version">{{ item.version }}</span>
<span class="date">{{ item.createdAt }}</span>
</div>
<svg-icon class="icon" iconName="p-featureshitu"></svg-icon>
<span class="icon-span">{{ item.newCount }}</span>
<svg-icon class="icon" iconName="p-youhuawendang"></svg-icon>
<span class="icon-span">{{ item.optimizationCount }}</span>
<svg-icon class="icon" iconName="p-bug"></svg-icon>
<span class="icon-span">{{ item.fixCount }}</span>
</template>
<div class="panel-MdEditor">
<MdEditor v-model="item.content" previewOnly :theme="isDarkTheme ? 'dark' : 'light'" />
</div>
</el-collapse-item>
</div>
</el-collapse>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
</span>
</template>
</DrawerPro>
</template>

<script setup lang="ts">
import { listReleases } from '@/api/modules/setting';
import MdEditor from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';
import { ref } from 'vue';
import { GlobalStore } from '@/store';
import { storeToRefs } from 'pinia';

const globalStore = GlobalStore();
const { isDarkTheme } = storeToRefs(globalStore);

const drawerVisible = ref(false);
const currentVersion = ref(0);
const notes = ref([]);
const loading = ref();

const acceptParams = (): void => {
search();
drawerVisible.value = true;
};

const handleClose = () => {
drawerVisible.value = false;
};

const search = async () => {
loading.value = true;
await listReleases()
.then((res) => {
notes.value = res.data;
loading.value = false;
})
.catch(() => {
loading.value = false;
});
};

defineExpose({
acceptParams,
});
</script>

<style lang="scss" scoped>
.version {
margin-left: 10px;
display: inline-block;
width: 50px;
}
.date {
margin-left: 20px;
margin-right: 40px;
display: inline-block;
width: 100px;
}
.icon-span {
display: inline-block;
width: 10px;
}
.panel-MdEditor {
:deep(.md-editor-preview) {
font-size: 12px;
}
}
:deep(.md-editor-dark) {
background-color: var(--panel-main-bg-color-9);
}
.icon {
font-size: 7px;
margin-left: 50px;
}
</style>
3 changes: 2 additions & 1 deletion frontend/src/styles/element-dark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,8 @@ html.dark {

.el-collapse-item__header {
color: #ffffff;
background-color: var(--panel-main-bg-color-10) !important;
border: 1px solid var(--panel-main-bg-color-10);
background-color: var(--panel-main-bg-color-9) !important;
}

.el-checkbox__input.is-checked .el-checkbox__inner::after {
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/styles/element.scss
Original file line number Diff line number Diff line change
Expand Up @@ -270,4 +270,10 @@ html {
color: var(--el-color-primary) !important;
background-color: var(--el-color-primary-light-9) !important;
border-color: var(--el-button-border-color) !important;
}

.el-collapse-item__header {
color: var(--el-text-color-regular) !important;
border: 1px solid var(--panel-main-bg-color-10);
background-color: var(--panel-main-bg-color-10) !important;
}
Loading