mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-01 03:24:14 +08:00
feat: Support custom display of the global menu (#8023)
This commit is contained in:
parent
50979f69eb
commit
189ba73f51
@ -33,7 +33,7 @@ type SettingInfo struct {
|
|||||||
AppStoreLastModified string `json:"appStoreLastModified"`
|
AppStoreLastModified string `json:"appStoreLastModified"`
|
||||||
AppStoreSyncStatus string `json:"appStoreSyncStatus"`
|
AppStoreSyncStatus string `json:"appStoreSyncStatus"`
|
||||||
|
|
||||||
XpackHideMenu string `json:"xpackHideMenu"`
|
HideMenu string `json:"hideMenu"`
|
||||||
NoAuthSetting string `json:"noAuthSetting"`
|
NoAuthSetting string `json:"noAuthSetting"`
|
||||||
|
|
||||||
ProxyUrl string `json:"proxyUrl"`
|
ProxyUrl string `json:"proxyUrl"`
|
||||||
@ -179,13 +179,14 @@ type Clean struct {
|
|||||||
Size uint64 `json:"size"`
|
Size uint64 `json:"size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type XpackHideMenu struct {
|
type ShowMenu struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
IsCheck bool `json:"isCheck"`
|
Disabled bool `json:"disabled"`
|
||||||
Title string `json:"title"`
|
IsShow bool `json:"isShow"`
|
||||||
Path string `json:"path,omitempty"`
|
Title string `json:"title"`
|
||||||
Children []XpackHideMenu `json:"children,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
|
Children []ShowMenu `json:"children,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApiInterfaceConfig struct {
|
type ApiInterfaceConfig struct {
|
||||||
|
@ -97,6 +97,21 @@ func (u *SettingService) Update(key, value string) error {
|
|||||||
_ = settingRepo.Create("AppStoreLastModified", value)
|
_ = settingRepo.Create("AppStoreLastModified", value)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
case "HideMenu":
|
||||||
|
var menus []dto.ShowMenu
|
||||||
|
if err := json.Unmarshal([]byte(value), &menus); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := 0; i < len(menus); i++ {
|
||||||
|
if menus[i].Label == "Home-Menu" || menus[i].Label == "App-Menu" || menus[i].Label == "Setting-Menu" {
|
||||||
|
menus[i].IsShow = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menuItem, err := json.Marshal(&menus)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value = string(menuItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := settingRepo.Update(key, value); err != nil {
|
if err := settingRepo.Update(key, value); err != nil {
|
||||||
|
51
core/init/migration/helper/menu.go
Normal file
51
core/init/migration/helper/menu.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/core/app/dto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LoadMenus() string {
|
||||||
|
item := []dto.ShowMenu{
|
||||||
|
{ID: "1", Disabled: true, Title: "menu.home", IsShow: true, Label: "Home-Menu", Path: "/"},
|
||||||
|
{ID: "2", Disabled: true, Title: "menu.apps", IsShow: true, Label: "App-Menu", Path: "/apps/all"},
|
||||||
|
{ID: "3", Disabled: false, Title: "menu.website", IsShow: true, Label: "Website-Menu", Path: "/websites",
|
||||||
|
Children: []dto.ShowMenu{
|
||||||
|
{ID: "31", Disabled: false, Title: "menu.website", IsShow: true, Label: "Website", Path: "/websites"},
|
||||||
|
{ID: "32", Disabled: false, Title: "menu.ssl", IsShow: true, Label: "SSL", Path: "/websites/ssl"},
|
||||||
|
{ID: "33", Disabled: false, Title: "menu.runtime", IsShow: true, Label: "PHP", Path: "/websites/runtimes/php"},
|
||||||
|
}},
|
||||||
|
{ID: "4", Disabled: false, Title: "menu.aiTools", IsShow: true, Label: "AI-Menu", Path: "/ai/model",
|
||||||
|
Children: []dto.ShowMenu{
|
||||||
|
{ID: "41", Disabled: false, Title: "aiTools.model.model", IsShow: true, Label: "OllamaModel", Path: "/ai/model"},
|
||||||
|
{ID: "42", Disabled: false, Title: "aiTools.gpu.gpu", IsShow: true, Label: "GPU", Path: "/ai/gpu"},
|
||||||
|
}},
|
||||||
|
{ID: "5", Disabled: false, Title: "menu.database", IsShow: true, Label: "Database-Menu", Path: "/databases"},
|
||||||
|
{ID: "6", Disabled: false, Title: "menu.container", IsShow: true, Label: "Container-Menu", Path: "/containers"},
|
||||||
|
{ID: "7", Disabled: false, Title: "menu.system", IsShow: true, Label: "System-Menu", Path: "/hosts/files",
|
||||||
|
Children: []dto.ShowMenu{
|
||||||
|
{ID: "71", Disabled: false, Title: "menu.files", IsShow: true, Label: "File", Path: "/hosts/files"},
|
||||||
|
{ID: "72", Disabled: false, Title: "menu.monitor", IsShow: true, Label: "Monitorx", Path: "/hosts/monitor/monitor"},
|
||||||
|
{ID: "74", Disabled: false, Title: "menu.firewall", IsShow: true, Label: "FirewallPort", Path: "/hosts/firewall/port"},
|
||||||
|
{ID: "75", Disabled: false, Title: "menu.supervisor", IsShow: true, Label: "Process", Path: "/hosts/process/process"},
|
||||||
|
{ID: "76", Disabled: false, Title: "menu.ssh", IsShow: true, Label: "SSH", Path: "/hosts/ssh/ssh"},
|
||||||
|
}},
|
||||||
|
{ID: "8", Disabled: false, Title: "menu.terminal", IsShow: true, Label: "Terminal-Menu", Path: "/hosts/terminal"},
|
||||||
|
{ID: "9", Disabled: false, Title: "menu.toolbox", IsShow: true, Label: "Toolbox-Menu", Path: "/toolbox"},
|
||||||
|
{ID: "10", Disabled: false, Title: "menu.cronjob", IsShow: true, Label: "Cronjob-Menu", Path: "/cronjobs"},
|
||||||
|
{ID: "11", Disabled: false, Title: "xpack.menu", IsShow: true, Label: "Xpack-Menu",
|
||||||
|
Children: []dto.ShowMenu{
|
||||||
|
{ID: "112", Disabled: false, Title: "xpack.waf.name", IsShow: true, Label: "Dashboard", Path: "/xpack/waf/dashboard"},
|
||||||
|
{ID: "111", Disabled: false, Title: "xpack.node.nodeManagement", IsShow: true, Label: "Node", Path: "/xpack/node"},
|
||||||
|
{ID: "113", Disabled: false, Title: "xpack.monitor.name", IsShow: true, Label: "MonitorDashboard", Path: "/xpack/monitor/dashboard"},
|
||||||
|
{ID: "114", Disabled: false, Title: "xpack.tamper.tamper", IsShow: true, Label: "Tamper", Path: "/xpack/tamper"},
|
||||||
|
{ID: "116", Disabled: false, Title: "xpack.alert.alert", IsShow: true, Label: "XAlertDashboard", Path: "/xpack/alert/dashboard"},
|
||||||
|
{ID: "115", Disabled: false, Title: "xpack.setting.setting", IsShow: true, Label: "XSetting", Path: "/xpack/setting"},
|
||||||
|
}},
|
||||||
|
{ID: "12", Disabled: false, Title: "menu.logs", IsShow: true, Label: "Log-Menu", Path: "/logs"},
|
||||||
|
{ID: "13", Disabled: true, Title: "menu.settings", IsShow: true, Label: "Setting-Menu", Path: "/settings"},
|
||||||
|
}
|
||||||
|
menu, _ := json.Marshal(item)
|
||||||
|
return string(menu)
|
||||||
|
}
|
@ -21,6 +21,7 @@ func Init() {
|
|||||||
migrations.UpdateSettingStatus,
|
migrations.UpdateSettingStatus,
|
||||||
migrations.RemoveLocalBackup,
|
migrations.RemoveLocalBackup,
|
||||||
migrations.AddMFAInterval,
|
migrations.AddMFAInterval,
|
||||||
|
migrations.UpdateXpackHideMemu,
|
||||||
})
|
})
|
||||||
if err := m.Migrate(); err != nil {
|
if err := m.Migrate(); err != nil {
|
||||||
global.LOG.Error(err)
|
global.LOG.Error(err)
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/core/app/model"
|
"github.com/1Panel-dev/1Panel/core/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/core/constant"
|
"github.com/1Panel-dev/1Panel/core/constant"
|
||||||
"github.com/1Panel-dev/1Panel/core/global"
|
"github.com/1Panel-dev/1Panel/core/global"
|
||||||
|
"github.com/1Panel-dev/1Panel/core/init/migration/helper"
|
||||||
"github.com/1Panel-dev/1Panel/core/utils/common"
|
"github.com/1Panel-dev/1Panel/core/utils/common"
|
||||||
"github.com/1Panel-dev/1Panel/core/utils/encrypt"
|
"github.com/1Panel-dev/1Panel/core/utils/encrypt"
|
||||||
"github.com/go-gormigrate/gormigrate/v2"
|
"github.com/go-gormigrate/gormigrate/v2"
|
||||||
@ -307,3 +308,13 @@ var AddMFAInterval = &gormigrate.Migration{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var UpdateXpackHideMemu = &gormigrate.Migration{
|
||||||
|
ID: "20250227-update-xpack-hide-menu",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
if err := tx.Model(&model.Setting{}).Where("key = ?", "XpackHideMenu").Updates(map[string]interface{}{"key": "HideMenu", "value": helper.LoadMenus()}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -48,7 +48,7 @@ export namespace Setting {
|
|||||||
weChatVars: string;
|
weChatVars: string;
|
||||||
dingVars: string;
|
dingVars: string;
|
||||||
snapshotIgnore: string;
|
snapshotIgnore: string;
|
||||||
xpackHideMenu: string;
|
hideMenu: string;
|
||||||
noAuthSetting: string;
|
noAuthSetting: string;
|
||||||
|
|
||||||
proxyUrl: string;
|
proxyUrl: string;
|
||||||
@ -191,7 +191,7 @@ export namespace Setting {
|
|||||||
key: string;
|
key: string;
|
||||||
name: string;
|
name: string;
|
||||||
size: number;
|
size: number;
|
||||||
isCheck: boolean;
|
isShow: boolean;
|
||||||
isDisable: boolean;
|
isDisable: boolean;
|
||||||
|
|
||||||
path: string;
|
path: string;
|
||||||
|
@ -1829,9 +1829,8 @@ const message = {
|
|||||||
|
|
||||||
license: 'License',
|
license: 'License',
|
||||||
bindNode: 'Bind Node',
|
bindNode: 'Bind Node',
|
||||||
advancedMenuHide: 'Advanced Menu Hide',
|
menuSetting: 'Menu Settings',
|
||||||
showMainAdvancedMenu:
|
menuSettingHelper: 'If only 1 menu is kept, the sidebar will directly display that menu.',
|
||||||
'If only one menu is retained, only the main advanced menu will be displayed in the sidebar',
|
|
||||||
showAll: 'Show All',
|
showAll: 'Show All',
|
||||||
hideALL: 'Hide All',
|
hideALL: 'Hide All',
|
||||||
ifShow: 'Whether to Show',
|
ifShow: 'Whether to Show',
|
||||||
|
@ -1694,9 +1694,8 @@ const message = {
|
|||||||
|
|
||||||
license: 'ライセンス',
|
license: 'ライセンス',
|
||||||
bindNode: 'ノードをバインド',
|
bindNode: 'ノードをバインド',
|
||||||
advancedMenuHide: '高度なメニューを非表示にします',
|
menuSetting: 'メニュー設定',
|
||||||
showMainAdvancedMenu:
|
menuSettingHelper: '1つのメニューだけを保持する場合、サイドバーにはそのメニューが直接表示されます。',
|
||||||
'メニューが1つしか保持されていない場合、メインの詳細メニューのみがサイドバーに表示されます',
|
|
||||||
showAll: 'すべてを表示します',
|
showAll: 'すべてを表示します',
|
||||||
hideALL: 'すべてを隠します',
|
hideALL: 'すべてを隠します',
|
||||||
ifShow: '表示するかどうか',
|
ifShow: '表示するかどうか',
|
||||||
|
@ -1667,8 +1667,8 @@ const message = {
|
|||||||
|
|
||||||
license: '라이선스',
|
license: '라이선스',
|
||||||
bindNode: '노드 바인딩',
|
bindNode: '노드 바인딩',
|
||||||
advancedMenuHide: '고급 메뉴 숨기기',
|
menuSetting: '메뉴 설정',
|
||||||
showMainAdvancedMenu: '하나의 메뉴만 유지하면 사이드바에 주 고급 메뉴만 표시됩니다.',
|
menuSettingHelper: '메뉴를 1개만 유지하면 사이드바에 해당 메뉴가 직접 표시됩니다.',
|
||||||
showAll: '모두 표시',
|
showAll: '모두 표시',
|
||||||
hideALL: '모두 숨기기',
|
hideALL: '모두 숨기기',
|
||||||
ifShow: '표시 여부',
|
ifShow: '표시 여부',
|
||||||
|
@ -1751,8 +1751,8 @@ const message = {
|
|||||||
|
|
||||||
license: 'Lesen',
|
license: 'Lesen',
|
||||||
bindNode: 'Ikatan Nod',
|
bindNode: 'Ikatan Nod',
|
||||||
advancedMenuHide: 'Sembunyikan menu lanjutan',
|
menuSetting: 'Tetapan Menu',
|
||||||
showMainAdvancedMenu: 'Jika hanya satu menu dikekalkan, hanya menu lanjutan utama akan dipaparkan di bar sisi',
|
menuSettingHelper: 'Jika hanya 1 menu yang disimpan, bar sisi akan langsung menampilkan menu tersebut.',
|
||||||
showAll: 'Papar Semua',
|
showAll: 'Papar Semua',
|
||||||
hideALL: 'Sembunyikan Semua',
|
hideALL: 'Sembunyikan Semua',
|
||||||
ifShow: 'Sama ada untuk Dipaparkan',
|
ifShow: 'Sama ada untuk Dipaparkan',
|
||||||
|
@ -1736,9 +1736,8 @@ const message = {
|
|||||||
|
|
||||||
license: 'Licença',
|
license: 'Licença',
|
||||||
bindNode: 'Vincular Nó',
|
bindNode: 'Vincular Nó',
|
||||||
advancedMenuHide: 'Ocultar menu avançado',
|
menuSetting: 'Configurações do Menu',
|
||||||
showMainAdvancedMenu:
|
menuSettingHelper: 'Se apenas 1 menu for mantido, a barra lateral exibirá diretamente esse menu.',
|
||||||
'Se apenas um menu for mantido, somente o menu avançado principal será exibido na barra lateral',
|
|
||||||
showAll: 'Mostrar Tudo',
|
showAll: 'Mostrar Tudo',
|
||||||
hideALL: 'Ocultar Tudo',
|
hideALL: 'Ocultar Tudo',
|
||||||
ifShow: 'Exibir?',
|
ifShow: 'Exibir?',
|
||||||
|
@ -1735,9 +1735,8 @@ const message = {
|
|||||||
|
|
||||||
license: 'Лицензия',
|
license: 'Лицензия',
|
||||||
bindNode: 'Привязать Узел',
|
bindNode: 'Привязать Узел',
|
||||||
advancedMenuHide: 'Скрыть расширенное меню',
|
menuSetting: 'Настройки меню',
|
||||||
showMainAdvancedMenu:
|
menuSettingHelper: 'Если оставить только 1 меню, боковая панель будет напрямую отображать это меню.',
|
||||||
'Если сохранено только одно меню, в боковой панели будет отображаться только основное расширенное меню',
|
|
||||||
showAll: 'Показать все',
|
showAll: 'Показать все',
|
||||||
hideALL: 'Скрыть все',
|
hideALL: 'Скрыть все',
|
||||||
ifShow: 'Показывать',
|
ifShow: 'Показывать',
|
||||||
|
@ -1697,8 +1697,8 @@ const message = {
|
|||||||
|
|
||||||
license: '許可證',
|
license: '許可證',
|
||||||
bindNode: '綁定節點',
|
bindNode: '綁定節點',
|
||||||
advancedMenuHide: '高級功能選單隱藏',
|
menuSetting: '菜單設定',
|
||||||
showMainAdvancedMenu: '如果只保留 1 個選單,則側邊欄只會顯示高級功能主選單',
|
menuSettingHelper: '如果只保留 1 個菜單,則側邊欄會直接顯示該菜單。',
|
||||||
showAll: '全部顯示',
|
showAll: '全部顯示',
|
||||||
hideALL: '全部隱藏',
|
hideALL: '全部隱藏',
|
||||||
ifShow: '是否顯示',
|
ifShow: '是否顯示',
|
||||||
|
@ -1689,8 +1689,8 @@ const message = {
|
|||||||
|
|
||||||
license: '许可证',
|
license: '许可证',
|
||||||
bindNode: '绑定节点',
|
bindNode: '绑定节点',
|
||||||
advancedMenuHide: '高级功能菜单隐藏',
|
menuSetting: '菜单设置',
|
||||||
showMainAdvancedMenu: '如果只保留 1 个菜单,则侧边栏只会显示高级功能主菜单',
|
menuSettingHelper: '如果只保留 1 个菜单,则侧边栏会直接显示该菜单',
|
||||||
showAll: '全部显示',
|
showAll: '全部显示',
|
||||||
hideALL: '全部隐藏',
|
hideALL: '全部隐藏',
|
||||||
ifShow: '是否显示',
|
ifShow: '是否显示',
|
||||||
|
@ -117,15 +117,6 @@ const loadCurrentName = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const screenWidth = ref(0);
|
const screenWidth = ref(0);
|
||||||
|
|
||||||
interface Node {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
path?: string;
|
|
||||||
label: string;
|
|
||||||
isCheck: boolean;
|
|
||||||
children?: Node[];
|
|
||||||
}
|
|
||||||
const listeningWindow = () => {
|
const listeningWindow = () => {
|
||||||
window.onresize = () => {
|
window.onresize = () => {
|
||||||
return (() => {
|
return (() => {
|
||||||
@ -204,68 +195,46 @@ const changeNode = (command: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function extractLabels(node: Node, result: string[]): void {
|
function getCheckedLabels(menu: any, showMap: any) {
|
||||||
if (node.isCheck) {
|
for (const item of menu) {
|
||||||
result.push(node.label);
|
if (item.isShow) {
|
||||||
}
|
showMap[item.label] = true;
|
||||||
if (node.children) {
|
}
|
||||||
for (const childNode of node.children) {
|
if (item.children) {
|
||||||
extractLabels(childNode, result);
|
getCheckedLabels(item.children, showMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCheckedLabels(json: Node): string[] {
|
|
||||||
let result: string[] = [];
|
|
||||||
extractLabels(json, result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const search = async () => {
|
const search = async () => {
|
||||||
let checkedLabels: any[] = [];
|
|
||||||
const res = await getSettingInfo();
|
const res = await getSettingInfo();
|
||||||
version.value = res.data.systemVersion;
|
version.value = res.data.systemVersion;
|
||||||
const json: Node = JSON.parse(res.data.xpackHideMenu);
|
const menuItem = JSON.parse(res.data.hideMenu);
|
||||||
checkedLabels = getCheckedLabels(json);
|
const showMap = new Map();
|
||||||
|
getCheckedLabels(menuItem, showMap);
|
||||||
let rstMenuList: RouteRecordRaw[] = [];
|
let rstMenuList: RouteRecordRaw[] = [];
|
||||||
menuStore.menuList.forEach((item) => {
|
for (const menu of menuStore.menuList) {
|
||||||
let menuItem = JSON.parse(JSON.stringify(item));
|
let menuItem = JSON.parse(JSON.stringify(menu));
|
||||||
let menuChildren: RouteRecordRaw[] = [];
|
if (!showMap[menuItem.name]) {
|
||||||
if (menuItem.path === '/xpack') {
|
continue;
|
||||||
if (checkedLabels.length) {
|
} else if (menuItem.name === 'Xpack-Menu') {
|
||||||
menuItem.children = menuItem.children.filter((child: any) => {
|
menuItem.meta.hideInSidebar = false;
|
||||||
return !(globalStore.isIntl && child.path.includes('/xpack/alert'));
|
|
||||||
});
|
|
||||||
menuItem.children.forEach((child: any) => {
|
|
||||||
for (const str of checkedLabels) {
|
|
||||||
if (child.name === str) {
|
|
||||||
child.hidden = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (child.hidden === false) {
|
|
||||||
menuChildren.push(child);
|
|
||||||
if (checkedLabels.length === 2) {
|
|
||||||
menuItem.meta.title = child.meta.title;
|
|
||||||
} else {
|
|
||||||
menuItem.meta.title = 'xpack.menu';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
menuItem.meta.hideInSidebar = false;
|
|
||||||
}
|
|
||||||
menuItem.children = menuChildren as RouteRecordRaw[];
|
|
||||||
rstMenuList.push(menuItem);
|
|
||||||
} else {
|
|
||||||
menuItem.children.forEach((child: any) => {
|
|
||||||
if (!child.hidden) {
|
|
||||||
menuChildren.push(child);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
menuItem.children = menuChildren as RouteRecordRaw[];
|
|
||||||
rstMenuList.push(menuItem);
|
|
||||||
}
|
}
|
||||||
});
|
let itemChildren = [];
|
||||||
|
for (const item of menuItem.children) {
|
||||||
|
if (item.name === 'XAlertDashboard' && globalStore.isIntl) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (showMap[item.name]) {
|
||||||
|
itemChildren.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (itemChildren.length === 1) {
|
||||||
|
menuItem.meta.title = itemChildren[0].meta.title;
|
||||||
|
}
|
||||||
|
menuItem.children = itemChildren;
|
||||||
|
rstMenuList.push(menuItem);
|
||||||
|
}
|
||||||
menuStore.menuList = rstMenuList;
|
menuStore.menuList = rstMenuList;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import { Layout } from '@/routers/constant';
|
|||||||
const databaseRouter = {
|
const databaseRouter = {
|
||||||
sort: 4,
|
sort: 4,
|
||||||
path: '/ai',
|
path: '/ai',
|
||||||
|
name: 'AI-Menu',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/ai/model',
|
redirect: '/ai/model',
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -3,6 +3,7 @@ import { Layout } from '@/routers/constant';
|
|||||||
const appStoreRouter = {
|
const appStoreRouter = {
|
||||||
sort: 2,
|
sort: 2,
|
||||||
path: '/apps',
|
path: '/apps',
|
||||||
|
name: 'App-Menu',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/apps/all',
|
redirect: '/apps/all',
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -3,6 +3,7 @@ import { Layout } from '@/routers/constant';
|
|||||||
const containerRouter = {
|
const containerRouter = {
|
||||||
sort: 6,
|
sort: 6,
|
||||||
path: '/containers',
|
path: '/containers',
|
||||||
|
name: 'Container-Menu',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/containers/container',
|
redirect: '/containers/container',
|
||||||
meta: {
|
meta: {
|
||||||
@ -12,7 +13,7 @@ const containerRouter = {
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/containers',
|
path: '/containers',
|
||||||
name: 'Containers',
|
name: 'Container',
|
||||||
redirect: '/containers/dashboard',
|
redirect: '/containers/dashboard',
|
||||||
component: () => import('@/views/container/index.vue'),
|
component: () => import('@/views/container/index.vue'),
|
||||||
meta: {},
|
meta: {},
|
||||||
@ -30,7 +31,7 @@ const containerRouter = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'container',
|
path: 'container',
|
||||||
name: 'Container',
|
name: 'ContainerItem',
|
||||||
component: () => import('@/views/container/container/index.vue'),
|
component: () => import('@/views/container/container/index.vue'),
|
||||||
props: true,
|
props: true,
|
||||||
hidden: true,
|
hidden: true,
|
||||||
|
@ -3,6 +3,7 @@ import { Layout } from '@/routers/constant';
|
|||||||
const cronRouter = {
|
const cronRouter = {
|
||||||
sort: 9,
|
sort: 9,
|
||||||
path: '/cronjobs',
|
path: '/cronjobs',
|
||||||
|
name: 'Cronjob-Menu',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/cronjobs',
|
redirect: '/cronjobs',
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -3,6 +3,7 @@ import { Layout } from '@/routers/constant';
|
|||||||
const databaseRouter = {
|
const databaseRouter = {
|
||||||
sort: 5,
|
sort: 5,
|
||||||
path: '/databases',
|
path: '/databases',
|
||||||
|
name: 'Database-Menu',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/databases/mysql',
|
redirect: '/databases/mysql',
|
||||||
meta: {
|
meta: {
|
||||||
@ -12,7 +13,7 @@ const databaseRouter = {
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/databases',
|
path: '/databases',
|
||||||
name: 'Databases',
|
name: 'Database',
|
||||||
redirect: '/databases/mysql',
|
redirect: '/databases/mysql',
|
||||||
component: () => import('@/views/database/index.vue'),
|
component: () => import('@/views/database/index.vue'),
|
||||||
meta: {},
|
meta: {},
|
||||||
|
@ -3,6 +3,7 @@ import { Layout } from '@/routers/constant';
|
|||||||
const hostRouter = {
|
const hostRouter = {
|
||||||
sort: 7,
|
sort: 7,
|
||||||
path: '/hosts',
|
path: '/hosts',
|
||||||
|
name: 'System-Menu',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/hosts/security',
|
redirect: '/hosts/security',
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -3,6 +3,7 @@ import { Layout } from '@/routers/constant';
|
|||||||
const logsRouter = {
|
const logsRouter = {
|
||||||
sort: 11,
|
sort: 11,
|
||||||
path: '/logs',
|
path: '/logs',
|
||||||
|
name: 'Log-Menu',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/logs/operation',
|
redirect: '/logs/operation',
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -3,6 +3,7 @@ import { Layout } from '@/routers/constant';
|
|||||||
const settingRouter = {
|
const settingRouter = {
|
||||||
sort: 12,
|
sort: 12,
|
||||||
path: '/settings',
|
path: '/settings',
|
||||||
|
name: 'Setting-Menu',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/settings/panel',
|
redirect: '/settings/panel',
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -3,6 +3,7 @@ import { Layout } from '@/routers/constant';
|
|||||||
const terminalRouter = {
|
const terminalRouter = {
|
||||||
sort: 8,
|
sort: 8,
|
||||||
path: '/terminal',
|
path: '/terminal',
|
||||||
|
name: 'Terminal-Menu',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/terminal',
|
redirect: '/terminal',
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -3,6 +3,7 @@ import { Layout } from '@/routers/constant';
|
|||||||
const toolboxRouter = {
|
const toolboxRouter = {
|
||||||
sort: 9,
|
sort: 9,
|
||||||
path: '/toolbox',
|
path: '/toolbox',
|
||||||
|
name: 'Toolbox-Menu',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/toolbox/supervisor',
|
redirect: '/toolbox/supervisor',
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -3,6 +3,7 @@ import { Layout } from '@/routers/constant';
|
|||||||
const webSiteRouter = {
|
const webSiteRouter = {
|
||||||
sort: 3,
|
sort: 3,
|
||||||
path: '/websites',
|
path: '/websites',
|
||||||
|
name: 'Website-Menu',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/websites',
|
redirect: '/websites',
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -7,6 +7,7 @@ modules = { ...modules, ...xpackModules };
|
|||||||
|
|
||||||
const homeRouter: RouteRecordRaw = {
|
const homeRouter: RouteRecordRaw = {
|
||||||
path: '/',
|
path: '/',
|
||||||
|
name: 'Home-Menu',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/',
|
redirect: '/',
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -1,25 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<DrawerPro v-model="drawerVisible" :header="$t('setting.advancedMenuHide')" :back="handleClose" size="small">
|
<DrawerPro v-model="drawerVisible" :header="$t('setting.menuSetting')" :back="handleClose" size="small">
|
||||||
<template #content>
|
<el-alert :closable="false" :title="$t('setting.menuSettingHelper')" type="warning" />
|
||||||
<ComplexTable
|
<ComplexTable :heightDiff="1" :data="treeData.hideMenu" :show-header="false" row-key="id">
|
||||||
class="mb-5 w-full"
|
<el-table-column prop="title" :label="$t('setting.menu')">
|
||||||
:data="treeData.hideMenu"
|
<template #default="{ row }">
|
||||||
:show-header="false"
|
{{ i18n.global.t(row.title) }}
|
||||||
row-key="id"
|
</template>
|
||||||
default-expand-all
|
</el-table-column>
|
||||||
>
|
<el-table-column prop="isShow" :label="$t('setting.ifShow')">
|
||||||
<el-table-column prop="title" :label="$t('setting.menu')">
|
<template #default="{ row }">
|
||||||
<template #default="{ row }">
|
<el-switch v-if="!row.disabled" v-model="row.isShow" @change="onChangeShow(row)" />
|
||||||
{{ i18n.global.t(row.title) }}
|
<span v-else>-</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="isCheck" :label="$t('setting.ifShow')">
|
</ComplexTable>
|
||||||
<template #default="{ row }">
|
|
||||||
<el-switch v-model="row.isCheck" @change="onSaveStatus(row)" />
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</ComplexTable>
|
|
||||||
</template>
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
|
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||||
@ -42,36 +36,22 @@ const globalStore = GlobalStore();
|
|||||||
|
|
||||||
const drawerVisible = ref();
|
const drawerVisible = ref();
|
||||||
const loading = ref();
|
const loading = ref();
|
||||||
const defaultCheck = ref([]);
|
|
||||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
|
||||||
interface DialogProps {
|
interface DialogProps {
|
||||||
menuList: string;
|
hideMenu: string;
|
||||||
}
|
}
|
||||||
const menuList = ref();
|
const acceptParams = (params: DialogProps): void => {
|
||||||
|
drawerVisible.value = true;
|
||||||
|
treeData.hideMenu = JSON.parse(params.hideMenu) || [];
|
||||||
|
if (globalStore.isIntl) {
|
||||||
|
treeData.hideMenu = removeXAlertDashboard(treeData.hideMenu);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const treeData = reactive({
|
const treeData = reactive({
|
||||||
hideMenu: [],
|
hideMenu: [],
|
||||||
checkedData: [],
|
checkedData: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
function loadCheck(data: any, checkList: any) {
|
|
||||||
if (data.children === null) {
|
|
||||||
if (data.isCheck) {
|
|
||||||
checkList.push(data.id);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const item of data) {
|
|
||||||
if (item.isCheck) {
|
|
||||||
checkList.push(item.id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (item.children) {
|
|
||||||
loadCheck(item.children, checkList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const removeXAlertDashboard = (data: any): any => {
|
const removeXAlertDashboard = (data: any): any => {
|
||||||
return data
|
return data
|
||||||
.filter((item: { label: string }) => item.label !== 'XAlertDashboard')
|
.filter((item: { label: string }) => item.label !== 'XAlertDashboard')
|
||||||
@ -83,70 +63,30 @@ const removeXAlertDashboard = (data: any): any => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSaveStatus = async (row: any) => {
|
const onChangeShow = async (row: any) => {
|
||||||
if (row.label === '/xpack') {
|
if (row.children) {
|
||||||
if (!row.isCheck) {
|
for (const item of row.children) {
|
||||||
for (const item of treeData.hideMenu[0].children) {
|
item.isShow = row.isShow;
|
||||||
item.isCheck = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let flag = false;
|
|
||||||
for (const item of treeData.hideMenu[0].children) {
|
|
||||||
if (item.isCheck) {
|
|
||||||
flag = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!flag && row.isCheck) {
|
|
||||||
for (const item of treeData.hideMenu[0].children) {
|
|
||||||
item.isCheck = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let flag = false;
|
|
||||||
if (row.isCheck) {
|
|
||||||
treeData.hideMenu[0].isCheck = true;
|
|
||||||
}
|
|
||||||
for (const item of treeData.hideMenu[0].children) {
|
|
||||||
if (item.isCheck) {
|
|
||||||
flag = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!flag) {
|
|
||||||
treeData.hideMenu[0].isCheck = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const acceptParams = (params: DialogProps): void => {
|
|
||||||
menuList.value = params.menuList;
|
|
||||||
drawerVisible.value = true;
|
|
||||||
treeData.hideMenu = [];
|
|
||||||
defaultCheck.value = [];
|
|
||||||
treeData.hideMenu.push(JSON.parse(menuList.value));
|
|
||||||
if (globalStore.isIntl) {
|
|
||||||
treeData.hideMenu = removeXAlertDashboard(treeData.hideMenu);
|
|
||||||
}
|
|
||||||
loadCheck(treeData.hideMenu, defaultCheck.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
drawerVisible.value = false;
|
drawerVisible.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveHideMenus = async () => {
|
const saveHideMenus = async () => {
|
||||||
ElMessageBox.confirm(i18n.global.t('setting.confirmMessage'), i18n.global.t('setting.advancedMenuHide'), {
|
ElMessageBox.confirm(i18n.global.t('setting.confirmMessage'), i18n.global.t('setting.menuSetting'), {
|
||||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||||
type: 'info',
|
type: 'info',
|
||||||
}).then(async () => {
|
}).then(async () => {
|
||||||
const updateJson = JSON.stringify(treeData.hideMenu[0]);
|
const updateJson = JSON.stringify(treeData.hideMenu);
|
||||||
await updateMenu({ key: 'XpackHideMenu', value: updateJson })
|
await updateMenu({ key: 'HideMenu', value: updateJson })
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
drawerVisible.value = false;
|
drawerVisible.value = false;
|
||||||
emit('search');
|
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
@ -160,14 +160,10 @@
|
|||||||
<span class="input-help">{{ $t('setting.developerModeHelper') }}</span>
|
<span class="input-help">{{ $t('setting.developerModeHelper') }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="$t('setting.advancedMenuHide')">
|
<el-form-item :label="$t('setting.menuSetting')">
|
||||||
<el-input disabled v-model="form.proHideMenus">
|
<el-button v-show="!show" @click="onChangeHideMenus" icon="Setting">
|
||||||
<template #append>
|
{{ $t('commons.button.set') }}
|
||||||
<el-button v-show="!show" @click="onChangeHideMenus" icon="Setting">
|
</el-button>
|
||||||
{{ $t('commons.button.set') }}
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -252,8 +248,7 @@ const form = reactive({
|
|||||||
ipWhiteList: '',
|
ipWhiteList: '',
|
||||||
apiKeyValidityTime: 120,
|
apiKeyValidityTime: 120,
|
||||||
|
|
||||||
proHideMenus: ref(i18n.t('setting.unSetting')),
|
hideMenu: '',
|
||||||
hideMenuList: '',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const show = ref();
|
const show = ref();
|
||||||
@ -268,15 +263,6 @@ const themeColorRef = ref();
|
|||||||
const apiInterfaceRef = ref();
|
const apiInterfaceRef = ref();
|
||||||
const unset = ref(i18n.t('setting.unSetting'));
|
const unset = ref(i18n.t('setting.unSetting'));
|
||||||
|
|
||||||
interface Node {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
path?: string;
|
|
||||||
label: string;
|
|
||||||
isCheck: boolean;
|
|
||||||
children?: Node[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const languageOptions = ref([
|
const languageOptions = ref([
|
||||||
{ value: 'zh', label: '中文(简体)' },
|
{ value: 'zh', label: '中文(简体)' },
|
||||||
{ value: 'zh-Hant', label: '中文(繁體)' },
|
{ value: 'zh-Hant', label: '中文(繁體)' },
|
||||||
@ -312,19 +298,7 @@ const search = async () => {
|
|||||||
form.apiKey = res.data.apiKey;
|
form.apiKey = res.data.apiKey;
|
||||||
form.ipWhiteList = res.data.ipWhiteList;
|
form.ipWhiteList = res.data.ipWhiteList;
|
||||||
form.apiKeyValidityTime = res.data.apiKeyValidityTime;
|
form.apiKeyValidityTime = res.data.apiKeyValidityTime;
|
||||||
|
form.hideMenu = res.data.hideMenu;
|
||||||
const json: Node = JSON.parse(res.data.xpackHideMenu);
|
|
||||||
if (json.isCheck === false) {
|
|
||||||
json.children.forEach((child: any) => {
|
|
||||||
if (child.isCheck === true) {
|
|
||||||
child.isCheck = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
form.proHideMenus = JSON.stringify(json);
|
|
||||||
form.hideMenuList = JSON.stringify(json);
|
|
||||||
const checkedTitles = getCheckedTitles(json);
|
|
||||||
form.proHideMenus = checkedTitles.toString();
|
|
||||||
|
|
||||||
if (isMasterProductPro.value) {
|
if (isMasterProductPro.value) {
|
||||||
const xpackRes = await getXpackSetting();
|
const xpackRes = await getXpackSetting();
|
||||||
@ -342,30 +316,6 @@ const search = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function extractTitles(node: Node, result: string[]): void {
|
|
||||||
if (!node.isCheck && !node.children) {
|
|
||||||
result.push(i18n.t(node.title));
|
|
||||||
}
|
|
||||||
if (node.children) {
|
|
||||||
for (const childNode of node.children) {
|
|
||||||
extractTitles(childNode, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCheckedTitles(json: Node): string[] {
|
|
||||||
let result: string[] = [];
|
|
||||||
extractTitles(json, result);
|
|
||||||
if (result.length === 0) {
|
|
||||||
result.push(i18n.t('setting.unSetting'));
|
|
||||||
}
|
|
||||||
if (result.length === json.children.length) {
|
|
||||||
result = [];
|
|
||||||
result.push(i18n.t('setting.hideALL'));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onChangePassword = () => {
|
const onChangePassword = () => {
|
||||||
passwordRef.value.acceptParams({ complexityVerification: form.complexityVerification });
|
passwordRef.value.acceptParams({ complexityVerification: form.complexityVerification });
|
||||||
};
|
};
|
||||||
@ -391,7 +341,7 @@ const onChangeProxy = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onChangeHideMenus = () => {
|
const onChangeHideMenus = () => {
|
||||||
hideMenuRef.value.acceptParams({ menuList: form.hideMenuList });
|
hideMenuRef.value.acceptParams({ hideMenu: form.hideMenu });
|
||||||
};
|
};
|
||||||
|
|
||||||
const onChangeThemeColor = () => {
|
const onChangeThemeColor = () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user