diff --git a/agent/app/api/v2/container.go b/agent/app/api/v2/container.go index e436ae54f..f24e84338 100644 --- a/agent/app/api/v2/container.go +++ b/agent/app/api/v2/container.go @@ -881,6 +881,26 @@ func (b *BaseApi) ComposeUpdate(c *gin.Context) { helper.Success(c) } +// @Tags Container Compose +// @Summary Pin compose +// @Accept json +// @Param request body dto.ComposePin true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /containers/compose/pin [post] +func (b *BaseApi) ComposePin(c *gin.Context) { + var req dto.ComposePin + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + if err := containerService.ComposePin(req); err != nil { + helper.InternalServer(c, err) + return + } + helper.Success(c) +} + // @Tags Container Compose // @Summary Load compose environment variables // @Accept json diff --git a/agent/app/dto/container.go b/agent/app/dto/container.go index 6f433ab6d..56195a2c5 100644 --- a/agent/app/dto/container.go +++ b/agent/app/dto/container.go @@ -300,6 +300,7 @@ type ComposeInfo struct { ConfigFile string `json:"configFile"` Workdir string `json:"workdir"` ComposeFileExists bool `json:"composeFileExists"` + IsPinned bool `json:"isPinned"` Path string `json:"path"` Containers []ComposeContainer `json:"containers"` Env string `json:"env"` @@ -337,6 +338,10 @@ type ComposeUpdate struct { Env string `json:"env"` ForcePull bool `json:"forcePull"` } +type ComposePin struct { + Name string `json:"name" validate:"required"` + IsPinned bool `json:"isPinned"` +} type ComposeLogClean struct { Name string `json:"name" validate:"required"` Path string `json:"path" validate:"required"` diff --git a/agent/app/model/compose_template.go b/agent/app/model/compose_template.go index aa127f2ac..b45648dd6 100644 --- a/agent/app/model/compose_template.go +++ b/agent/app/model/compose_template.go @@ -11,6 +11,7 @@ type ComposeTemplate struct { type Compose struct { BaseModel - Name string `json:"name"` - Path string `json:"path"` + Name string `json:"name"` + Path string `json:"path"` + IsPinned bool `json:"isPinned"` } diff --git a/agent/app/service/container.go b/agent/app/service/container.go index 59c89a4c1..2cc7d6564 100644 --- a/agent/app/service/container.go +++ b/agent/app/service/container.go @@ -71,6 +71,7 @@ type IContainerService interface { ComposeOperation(req dto.ComposeOperation) error TestCompose(req dto.ComposeCreate) (bool, error) ComposeUpdate(req dto.ComposeUpdate) error + ComposePin(req dto.ComposePin) error ComposeLogClean(req dto.ComposeLogClean) error ContainerCreate(req dto.ContainerOperate, inThread bool) error @@ -2025,6 +2026,9 @@ func loadComposeCount(client *client.Client) int { } } for _, compose := range composeCreatedByLocal { + if len(compose.Path) == 0 { + continue + } if _, has := composeMap[compose.Name]; !has { composeMap[compose.Name] = struct{}{} } diff --git a/agent/app/service/container_compose.go b/agent/app/service/container_compose.go index 88b3b124d..d5c0cd6b6 100644 --- a/agent/app/service/container_compose.go +++ b/agent/app/service/container_compose.go @@ -52,7 +52,15 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface return 0, nil, err } - composeCreatedByLocal, _ := composeRepo.ListRecord() + composeRecords, _ := composeRepo.ListRecord() + pinnedByName := make(map[string]bool, len(composeRecords)) + composeCreatedByLocal := make([]model.Compose, 0, len(composeRecords)) + for _, record := range composeRecords { + pinnedByName[record.Name] = record.IsPinned + if len(record.Path) != 0 { + composeCreatedByLocal = append(composeCreatedByLocal, record) + } + } composeLocalMap := make(map[string]dto.ComposeInfo) for _, localItem := range composeCreatedByLocal { composeItemLocal := dto.ComposeInfo{ @@ -136,6 +144,7 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface for key, value := range mergedMap { value.Name = key value.ComposeFileExists = composeFileExists(value.Workdir, value.ConfigFile) + value.IsPinned = pinnedByName[key] records = append(records, value) } if len(req.Info) != 0 { @@ -150,6 +159,9 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface } } sort.Slice(records, func(i, j int) bool { + if records[i].IsPinned != records[j].IsPinned { + return records[i].IsPinned + } return records[i].CreatedAt > records[j].CreatedAt }) total, start, end := len(records), (req.Page-1)*req.PageSize, req.Page*req.PageSize @@ -193,7 +205,7 @@ func (u *ContainerService) TestCompose(req dto.ComposeCreate) (bool, error) { return false, buserr.New("ErrCmdIllegal") } composeItem, _ := composeRepo.GetRecord(repo.WithByName(req.Name)) - if composeItem.ID != 0 { + if composeItem.ID != 0 && len(composeItem.Path) != 0 { return false, buserr.New("ErrRecordExist") } if err := u.loadPath(&req); err != nil { @@ -235,7 +247,13 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) error { _, _ = compose.Down(req.Path) return err } - _ = composeRepo.CreateRecord(&model.Compose{Name: strings.ToLower(req.Name), Path: req.Path}) + recordName := strings.ToLower(req.Name) + record, _ := composeRepo.GetRecord(repo.WithByName(recordName)) + if record.ID == 0 { + _ = composeRepo.CreateRecord(&model.Compose{Name: recordName, Path: req.Path}) + } else { + _ = composeRepo.UpdateRecord(recordName, map[string]interface{}{"path": req.Path}) + } return nil }, nil) _ = taskItem.Execute() @@ -327,6 +345,20 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error { return nil } +func (u *ContainerService) ComposePin(req dto.ComposePin) error { + record, _ := composeRepo.GetRecord(repo.WithByName(req.Name)) + if record.ID == 0 { + if !req.IsPinned { + return nil + } + return composeRepo.CreateRecord(&model.Compose{Name: req.Name, IsPinned: true}) + } + if !req.IsPinned && len(record.Path) == 0 { + return composeRepo.DeleteRecord(repo.WithByName(req.Name)) + } + return composeRepo.UpdateRecord(req.Name, map[string]interface{}{"is_pinned": req.IsPinned}) +} + func (u *ContainerService) ComposeLogClean(req dto.ComposeLogClean) error { client, err := docker.NewDockerClient() if err != nil { diff --git a/agent/init/migration/migrate.go b/agent/init/migration/migrate.go index 4803e028c..7f887461e 100644 --- a/agent/init/migration/migrate.go +++ b/agent/init/migration/migrate.go @@ -95,6 +95,7 @@ func InitAgentDB() { migrations.AddDatabaseUserTable, migrations.AddBackupRecordArgs, migrations.AddFtpIdentity, + migrations.AddComposePinned, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/agent/init/migration/migrations/init.go b/agent/init/migration/migrations/init.go index 29d295782..26a95f432 100644 --- a/agent/init/migration/migrations/init.go +++ b/agent/init/migration/migrations/init.go @@ -1698,3 +1698,10 @@ var AddFtpIdentity = &gormigrate.Migration{ }).Error }, } + +var AddComposePinned = &gormigrate.Migration{ + ID: "20260729-add-compose-pinned", + Migrate: func(tx *gorm.DB) error { + return tx.AutoMigrate(&model.Compose{}) + }, +} diff --git a/agent/router/ro_container.go b/agent/router/ro_container.go index 906abab72..8a715a18c 100644 --- a/agent/router/ro_container.go +++ b/agent/router/ro_container.go @@ -55,6 +55,7 @@ func (s *ContainerRouter) InitRouter(Router *gin.RouterGroup) { baRouter.POST("/compose/operate", baseApi.OperatorCompose) baRouter.POST("/compose/clean/log", baseApi.CleanComposeLog) baRouter.POST("/compose/update", baseApi.ComposeUpdate) + baRouter.POST("/compose/pin", baseApi.ComposePin) baRouter.GET("/template", baseApi.ListComposeTemplate) baRouter.POST("/template/search", baseApi.SearchComposeTemplate) diff --git a/frontend/src/api/interface/container.ts b/frontend/src/api/interface/container.ts index 7b66ffb2f..fd5b12d2f 100644 --- a/frontend/src/api/interface/container.ts +++ b/frontend/src/api/interface/container.ts @@ -337,6 +337,7 @@ export namespace Container { configFile: string; workdir: string; composeFileExists: boolean; + isPinned: boolean; path: string; containers: Array; expand: boolean; @@ -374,6 +375,10 @@ export namespace Container { forcePull: boolean; createdBy: string; } + export interface ComposePin { + name: string; + isPinned: boolean; + } export interface TemplateCreate { name: string; diff --git a/frontend/src/api/modules/container.ts b/frontend/src/api/modules/container.ts index cdec3d304..a7dc42db2 100644 --- a/frontend/src/api/modules/container.ts +++ b/frontend/src/api/modules/container.ts @@ -240,6 +240,9 @@ export const composeOperate = (params: Container.ComposeOperation) => { export const composeUpdate = (params: Container.ComposeUpdate) => { return http.post(`/containers/compose/update`, params, TimeoutEnum.T_10M); }; +export const composePin = (params: Container.ComposePin) => { + return http.post(`/containers/compose/pin`, params); +}; // docker export const dockerOperate = (operation: string) => { diff --git a/frontend/src/assets/iconfont/iconfont.css b/frontend/src/assets/iconfont/iconfont.css index e8851f814..999793bbb 100644 --- a/frontend/src/assets/iconfont/iconfont.css +++ b/frontend/src/assets/iconfont/iconfont.css @@ -1,9 +1,9 @@ @font-face { font-family: "iconfont"; /* Project id 4776196 */ - src: url('iconfont.woff2?t=1775716122874') format('woff2'), - url('iconfont.woff?t=1775716122874') format('woff'), - url('iconfont.ttf?t=1775716122874') format('truetype'), - url('iconfont.svg?t=1775716122874#iconfont') format('svg'); + src: url('iconfont.woff2?t=1785320291556') format('woff2'), + url('iconfont.woff?t=1785320291556') format('woff'), + url('iconfont.ttf?t=1785320291556') format('truetype'), + url('iconfont.svg?t=1785320291556#iconfont') format('svg'); } .iconfont { @@ -14,6 +14,10 @@ -moz-osx-font-smoothing: grayscale; } +.p-pushpin:before { + content: "\e7e3"; +} + .p-qrcode:before { content: "\e72a"; } diff --git a/frontend/src/assets/iconfont/iconfont.js b/frontend/src/assets/iconfont/iconfont.js index e88a972de..1700dc75a 100644 --- a/frontend/src/assets/iconfont/iconfont.js +++ b/frontend/src/assets/iconfont/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_4776196='',(a=>{var l=(c=(c=document.getElementsByTagName("script"))[c.length-1]).getAttribute("data-injectcss"),c=c.getAttribute("data-disable-injectsvg");if(!c){var h,z,t,p,v,m=function(l,c){c.parentNode.insertBefore(l,c)};if(l&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}h=function(){var l,c=document.createElement("div");c.innerHTML=a._iconfont_svg_string_4776196,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(l=document.body).firstChild?m(c,l.firstChild):l.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(z=function(){document.removeEventListener("DOMContentLoaded",z,!1),h()},document.addEventListener("DOMContentLoaded",z,!1)):document.attachEvent&&(t=h,p=a.document,v=!1,d(),p.onreadystatechange=function(){"complete"==p.readyState&&(p.onreadystatechange=null,M())})}function M(){v||(v=!0,t())}function d(){try{p.documentElement.doScroll("left")}catch(l){return void setTimeout(d,50)}M()}})(window); +window._iconfont_svg_string_4776196='',(a=>{var l=(c=(c=document.getElementsByTagName("script"))[c.length-1]).getAttribute("data-injectcss"),c=c.getAttribute("data-disable-injectsvg");if(!c){var h,z,t,p,v,m=function(l,c){c.parentNode.insertBefore(l,c)};if(l&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}h=function(){var l,c=document.createElement("div");c.innerHTML=a._iconfont_svg_string_4776196,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(l=document.body).firstChild?m(c,l.firstChild):l.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(z=function(){document.removeEventListener("DOMContentLoaded",z,!1),h()},document.addEventListener("DOMContentLoaded",z,!1)):document.attachEvent&&(t=h,p=a.document,v=!1,d(),p.onreadystatechange=function(){"complete"==p.readyState&&(p.onreadystatechange=null,M())})}function M(){v||(v=!0,t())}function d(){try{p.documentElement.doScroll("left")}catch(l){return void setTimeout(d,50)}M()}})(window); \ No newline at end of file diff --git a/frontend/src/assets/iconfont/iconfont.json b/frontend/src/assets/iconfont/iconfont.json index d665f67ad..c07b173cf 100644 --- a/frontend/src/assets/iconfont/iconfont.json +++ b/frontend/src/assets/iconfont/iconfont.json @@ -5,6 +5,13 @@ "css_prefix_text": "p-", "description": "", "glyphs": [ + { + "icon_id": "4766969", + "name": "pushpin", + "font_class": "pushpin", + "unicode": "e7e3", + "unicode_decimal": 59363 + }, { "icon_id": "14679640", "name": "qrcode", diff --git a/frontend/src/assets/iconfont/iconfont.svg b/frontend/src/assets/iconfont/iconfont.svg index cd9d498fa..4f895a8d2 100644 --- a/frontend/src/assets/iconfont/iconfont.svg +++ b/frontend/src/assets/iconfont/iconfont.svg @@ -13,6 +13,8 @@ descent="-128" /> + + diff --git a/frontend/src/assets/iconfont/iconfont.ttf b/frontend/src/assets/iconfont/iconfont.ttf index aabf57379..859e96651 100644 Binary files a/frontend/src/assets/iconfont/iconfont.ttf and b/frontend/src/assets/iconfont/iconfont.ttf differ diff --git a/frontend/src/assets/iconfont/iconfont.woff b/frontend/src/assets/iconfont/iconfont.woff index 8e48dda64..056f14d63 100644 Binary files a/frontend/src/assets/iconfont/iconfont.woff and b/frontend/src/assets/iconfont/iconfont.woff differ diff --git a/frontend/src/assets/iconfont/iconfont.woff2 b/frontend/src/assets/iconfont/iconfont.woff2 index 9d482c729..295860c35 100644 Binary files a/frontend/src/assets/iconfont/iconfont.woff2 and b/frontend/src/assets/iconfont/iconfont.woff2 differ diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 9e6d7a3ca..cc6b31486 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -150,6 +150,8 @@ const message = { manageGroup: 'Manage Groups', backToList: 'Back to List', keepEdit: 'Continue Editing', + pin: 'Pin to top', + unpin: 'Unpin', }, loadingText: { Upgrading: 'Upgrading system, please wait...', @@ -3758,8 +3760,6 @@ const message = { cacheWarn: 'Please turn off the cache switch in the reverse proxy first', loadBalanceHelper: 'After creating the load balancing, go to "Reverse Proxy", add a proxy and set the backend address to: http://', - favorite: 'Favorite', - cancelFavorite: 'Cancel Favorite', useProxy: 'Use Proxy', useProxyHelper: 'Use the proxy server address in the panel settings', westCN: 'West Digital', diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts index c1ff8f208..4738b95b3 100644 --- a/frontend/src/lang/modules/es-es.ts +++ b/frontend/src/lang/modules/es-es.ts @@ -147,6 +147,8 @@ const message = { manageGroup: 'Gestionar grupos', backToList: 'Volver a la lista', keepEdit: 'Continuar Editando', + pin: 'Fijar arriba', + unpin: 'Desfijar', creator: 'Creador', updater: 'Actualizador', }, @@ -3805,8 +3807,6 @@ const message = { runtimePortWarn: 'Este runtime no tiene puertos, no se puede usar proxy', cacheWarn: 'Desactiva la caché en proxy inverso primero', loadBalanceHelper: 'Tras crear balanceo, ve a "Proxy inverso" y añade un backend: http://', - favorite: 'Favorito', - cancelFavorite: 'Quitar favorito', useProxy: 'Usar proxy', useProxyHelper: 'Usa la dirección del proxy configurado en el panel', westCN: 'West Digital', diff --git a/frontend/src/lang/modules/fa.ts b/frontend/src/lang/modules/fa.ts index b66b112fe..51d191758 100644 --- a/frontend/src/lang/modules/fa.ts +++ b/frontend/src/lang/modules/fa.ts @@ -146,6 +146,8 @@ const message = { manageGroup: 'مدیریت گروه‌ها', backToList: 'بازگشت به لیست', keepEdit: 'ادامه ویرایش', + pin: 'سنجاق کردن در بالا', + unpin: 'برداشتن سنجاق', }, loadingText: { Upgrading: 'در حال ارتقاء سیستم، لطفاً صبر کنید...', @@ -3727,8 +3729,6 @@ const message = { cacheWarn: 'لطفاً ابتدا کلید کش را در پراکسی معکوس خاموش کنید', loadBalanceHelper: 'پس از ایجاد تعادل بار، به "پراکسی معکوس" بروید، یک پراکسی اضافه کرده و آدرس بک‌اند را به: http://<نام تعادل بار> تنظیم کنید', - favorite: 'نشان کردن', - cancelFavorite: 'لغو نشان کردن', useProxy: 'استفاده از پراکسی', useProxyHelper: 'از آدرس سرور پراکسی در تنظیمات پنل استفاده کنید', westCN: 'وست دیجیتال', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index 316dde138..6ca5604ea 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -142,6 +142,8 @@ const message = { manageGroup: 'グループ管理', backToList: 'リストに戻る', keepEdit: '編集を続ける', + pin: '上部に固定', + unpin: '固定を解除', default: 'デフォルト', noRefresh: '自動更新なし', creator: '作成者', @@ -3772,8 +3774,6 @@ const message = { cacheWarn: 'まずリバースプロキシのキャッシュスイッチをオフにしてください', loadBalanceHelper: '負荷分散を作成した後、「リバースプロキシ」に移動し、プロキシを追加してバックエンドアドレスを次のように設定してください:http://<負荷分散名>。', - favorite: 'お気に入り', - cancelFavorite: 'お気に入りを解除', useProxy: 'プロキシを使用', useProxyHelper: 'パネル設定のプロキシサーバーアドレスを使用', westCN: '西部デジタル', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 05706b6b6..34b019e2b 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -142,6 +142,8 @@ const message = { manageGroup: '그룹 관리', backToList: '목록으로 돌아가기', keepEdit: '계속 편집', + pin: '상단 고정', + unpin: '고정 해제', default: '기본값', noRefresh: '자동 새로고침 안 함', creator: '생성자', @@ -3691,8 +3693,6 @@ const message = { cacheWarn: '먼저 리버스 프록시의 캐시 스위치를 끄십시오', loadBalanceHelper: '로드 밸런싱을 생성한 후, "리버스 프록시"로 이동하여 프록시를 추가하고 백엔드 주소를 다음으로 설정하세요: http://<로드 밸런싱 이름>.', - favorite: '즐겨찾기', - cancelFavorite: '즐겨찾기 취소', useProxy: '프록시 사용', useProxyHelper: '패널 설정의 프록시 서버 주소 사용', westCN: '서부 디지털', diff --git a/frontend/src/lang/modules/lo.ts b/frontend/src/lang/modules/lo.ts index 2114a9baa..5191f603d 100644 --- a/frontend/src/lang/modules/lo.ts +++ b/frontend/src/lang/modules/lo.ts @@ -150,6 +150,8 @@ const message = { manageGroup: 'ຈັດການກຸ່ມ', backToList: 'ກັບຄືນໄປລາຍການ', keepEdit: 'ແກ້ໄຂຕໍ່', + pin: 'ປັກໝຸດໄວ້ເທິງ', + unpin: 'ຍົກເລີກການປັກໝຸດ', }, loadingText: { Upgrading: 'ກຳລັງອັບເກຣດລະບົບ, ກະລຸນາຖ້າ...', @@ -3672,8 +3674,6 @@ const message = { cacheWarn: 'ກະລຸນາປິດແຄຊໃນ reverse proxy ກ່ອນ', loadBalanceHelper: 'ຫຼັງຈາກສ້າງການກະຈາຍພາລະແລ້ວ, ໃຫ້ໄປທີ່ "Reverse Proxy", ເພີ່ມ proxy ແລະ ຕັ້ງທີ່ຢູ່ເບື້ອງຫຼັງເປັນ: http://<ຊື່ load balancing>', - favorite: 'ເພີ່ມໃນລາຍການທີ່ມັກ', - cancelFavorite: 'ຍົກເລີກລາຍການທີ່ມັກ', useProxy: 'ໃຊ້ Proxy', useProxyHelper: 'ໃຊ້ທີ່ຢູ່ເຊີບເວີ proxy ໃນການຕັ້ງຄ່າແຜງຄວບຄຸມ', westCN: 'West Digital', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index d5d8318cc..d86b9d599 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -142,6 +142,8 @@ const message = { manageGroup: 'Urus Kumpulan', backToList: 'Kembali ke Senarai', keepEdit: 'Teruskan Mengedit', + pin: 'Semat ke atas', + unpin: 'Nyahsemat', default: 'Lalai', noRefresh: 'Tiada segar semula auto', creator: 'Pencipta', @@ -3825,8 +3827,6 @@ const message = { cacheWarn: 'Sila matikan suis cache dalam pembalikan proksi terlebih dahulu', loadBalanceHelper: 'Setelah mencipta pengimbang beban, sila pergi ke "Reverse Proxy", tambahkan proksi dan tetapkan alamat backend ke: http://.', - favorite: 'Kegemaran', - cancelFavorite: 'Batalkan Kegemaran', useProxy: 'Gunakan Proksi', useProxyHelper: 'Gunakan alamat pelayan proksi dalam tetapan panel', westCN: 'West Digital', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index 195caeaac..fe9ae3599 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -142,6 +142,8 @@ const message = { manageGroup: 'Gerenciar Grupos', backToList: 'Voltar à Lista', keepEdit: 'Continuar Editando', + pin: 'Fixar no topo', + unpin: 'Desafixar', default: 'Padrão', noRefresh: 'Sem atualização', creator: 'Criador', @@ -3961,8 +3963,6 @@ const message = { cacheWarn: 'Por favor, desligue o interruptor de cache no proxy reverso primeiro', loadBalanceHelper: 'Após criar o balanceamento de carga, vá para "Proxy Reverso", adicione um proxy e configure o endereço de backend para: http://.', - favorite: 'Favorito', - cancelFavorite: 'Cancelar Favorito', useProxy: 'Usar Proxy', useProxyHelper: 'Usar o endereço do servidor proxy nas configurações do painel', westCN: 'West Digital', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index f73df6df0..e08c34130 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -142,6 +142,8 @@ const message = { manageGroup: 'Управление группами', backToList: 'Вернуться к списку', keepEdit: 'Продолжить редактирование', + pin: 'Закрепить сверху', + unpin: 'Открепить', default: 'По умолчанию', noRefresh: 'Без автообновления', creator: 'Создатель', @@ -3814,8 +3816,6 @@ const message = { cacheWarn: 'Пожалуйста, сначала выключите кэш в обратном прокси', loadBalanceHelper: 'После создания балансировки нагрузки, пожалуйста, перейдите в "Обратный прокси", добавьте прокси и установите адрес бэкенда на: http://<название балансировки нагрузки>.', - favorite: 'Избранное', - cancelFavorite: 'Отменить избранное', useProxy: 'Использовать прокси', useProxyHelper: 'Использовать адрес прокси-сервера в настройках панели', westCN: 'Западный цифровой', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 96e7c5e47..9a4daf853 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -147,6 +147,8 @@ const message = { manageGroup: 'Grupları Yönet', backToList: 'Listeye Dön', keepEdit: 'Düzenlemeye Devam Et', + pin: 'Üste sabitle', + unpin: 'Sabitlemeyi kaldır', creator: 'Oluşturan', updater: 'Güncelleyen', }, @@ -3816,8 +3818,6 @@ const message = { cacheWarn: 'Lütfen önce ters vekildeki önbellek anahtarını kapatın', loadBalanceHelper: 'Bu bölüm yalnızca yük dengeleme kuralları oluşturur, kuralları kullanmak için lütfen http(s):// adresine ters vekil yapın', - favorite: 'Favori', - cancelFavorite: 'Favoriyi İptal Et', useProxy: 'Vekil Kullan', useProxyHelper: 'Panel ayarlarındaki vekil sunucu adresini kullan', westCN: 'Batı Dijital', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index 1ecc75dcb..ffb5f4ff0 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -143,6 +143,8 @@ const message = { manageGroup: '管理群組', backToList: '返回列表', keepEdit: '繼續編輯', + pin: '置頂', + unpin: '取消置頂', creator: '建立者', updater: '更新者', }, @@ -3490,8 +3492,6 @@ const message = { runtimePortWarn: '目前執行環境沒有埠,無法代理', cacheWarn: '請先關閉反代中的快取開關', loadBalanceHelper: '建立負載均衡後,請前往『反向代理』,新增代理並將後端地址設定為:http://<負載均衡名稱>', - favorite: '收藏', - cancelFavorite: '取消收藏', useProxy: '使用代理', useProxyHelper: '使用面板設定中的代理伺服器地址', westCN: '西部數碼', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index c5a0f541b..800479afd 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -138,6 +138,8 @@ const message = { manageGroup: '管理分组', backToList: '返回列表', keepEdit: '继续编辑', + pin: '置顶', + unpin: '取消置顶', }, loadingText: { Upgrading: '系统升级中,请稍候...', @@ -3491,8 +3493,6 @@ const message = { runtimePortWarn: '当前运行环境没有端口,无法代理', cacheWarn: '请先关闭反代中的缓存开关', loadBalanceHelper: '创建负载均衡后,请前往‘反向代理’,添加代理并将后端地址设置为:http://<负载均衡名称>。', - favorite: '收藏', - cancelFavorite: '取消收藏', useProxy: '使用代理', useProxyHelper: '使用面板设置中的代理服务器地址', westCN: '西部数码', diff --git a/frontend/src/layout/components/Sidebar/components/node-drawer/index.vue b/frontend/src/layout/components/Sidebar/components/node-drawer/index.vue index 427f1fe75..5d797dd1e 100644 --- a/frontend/src/layout/components/Sidebar/components/node-drawer/index.vue +++ b/frontend/src/layout/components/Sidebar/components/node-drawer/index.vue @@ -21,9 +21,7 @@
+ > + +
@@ -309,6 +308,13 @@ watch( height: 20px; min-height: 20px; padding: 0; + + :deep(.node-pin-icon) { + width: 1em; + height: 1em; + padding: 0; + vertical-align: middle; + } } .node-name-cell { diff --git a/frontend/src/views/app-store/installed/app/header.vue b/frontend/src/views/app-store/installed/app/header.vue index 2cb3ea92c..229f55469 100644 --- a/frontend/src/views/app-store/installed/app/header.vue +++ b/frontend/src/views/app-store/installed/app/header.vue @@ -83,29 +83,21 @@ - - - + > + + + +
diff --git a/frontend/src/views/container/compose/index.vue b/frontend/src/views/container/compose/index.vue index 794797e12..52f4d89da 100644 --- a/frontend/src/views/container/compose/index.vue +++ b/frontend/src/views/container/compose/index.vue @@ -38,7 +38,7 @@ :class="{ 'is-active': currentCompose?.name === row.name && !isOnCreate }" >
- {{ row.name }} + {{ row.name }} + + + + +
@@ -222,7 +240,10 @@