diff --git a/backend/app/api/v1/compose_template.go b/backend/app/api/v1/compose_template.go new file mode 100644 index 000000000..5c9e03b9d --- /dev/null +++ b/backend/app/api/v1/compose_template.go @@ -0,0 +1,100 @@ +package v1 + +import ( + "github.com/1Panel-dev/1Panel/app/api/v1/helper" + "github.com/1Panel-dev/1Panel/app/dto" + "github.com/1Panel-dev/1Panel/constant" + "github.com/1Panel-dev/1Panel/global" + "github.com/gin-gonic/gin" +) + +func (b *BaseApi) CreateComposeTemplate(c *gin.Context) { + var req dto.ComposeTemplateCreate + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := composeTemplateService.Create(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} + +func (b *BaseApi) SearchComposeTemplate(c *gin.Context) { + var req dto.PageInfo + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + total, list, err := composeTemplateService.SearchWithPage(req) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + + helper.SuccessWithData(c, dto.PageResult{ + Items: list, + Total: total, + }) +} + +func (b *BaseApi) ListComposeTemplate(c *gin.Context) { + list, err := composeTemplateService.List() + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + + helper.SuccessWithData(c, list) +} + +func (b *BaseApi) DeleteComposeTemplate(c *gin.Context) { + var req dto.BatchDeleteReq + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + if err := composeTemplateService.Delete(req.Ids); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} + +func (b *BaseApi) UpdateComposeTemplate(c *gin.Context) { + var req dto.ComposeTemplateUpdate + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + id, err := helper.GetParamID(c) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + upMap := make(map[string]interface{}) + upMap["from"] = req.From + upMap["content"] = req.Content + upMap["description"] = req.Description + if err := composeTemplateService.Update(id, upMap); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} diff --git a/backend/app/api/v1/entry.go b/backend/app/api/v1/entry.go index 94aa3d212..1c6c462c4 100644 --- a/backend/app/api/v1/entry.go +++ b/backend/app/api/v1/entry.go @@ -9,17 +9,18 @@ type ApiGroup struct { var ApiGroupApp = new(ApiGroup) var ( - authService = service.ServiceGroupApp.AuthService - hostService = service.ServiceGroupApp.HostService - backupService = service.ServiceGroupApp.BackupService - groupService = service.ServiceGroupApp.GroupService - containerService = service.ServiceGroupApp.ContainerService - imageRepoService = service.ServiceGroupApp.ImageRepoService - imageService = service.ServiceGroupApp.ImageService - commandService = service.ServiceGroupApp.CommandService - operationService = service.ServiceGroupApp.OperationService - fileService = service.ServiceGroupApp.FileService - cronjobService = service.ServiceGroupApp.CronjobService - settingService = service.ServiceGroupApp.SettingService - appService = service.ServiceGroupApp.AppService + authService = service.ServiceGroupApp.AuthService + hostService = service.ServiceGroupApp.HostService + backupService = service.ServiceGroupApp.BackupService + groupService = service.ServiceGroupApp.GroupService + containerService = service.ServiceGroupApp.ContainerService + composeTemplateService = service.ServiceGroupApp.ComposeTemplateService + imageRepoService = service.ServiceGroupApp.ImageRepoService + imageService = service.ServiceGroupApp.ImageService + commandService = service.ServiceGroupApp.CommandService + operationService = service.ServiceGroupApp.OperationService + fileService = service.ServiceGroupApp.FileService + cronjobService = service.ServiceGroupApp.CronjobService + settingService = service.ServiceGroupApp.SettingService + appService = service.ServiceGroupApp.AppService ) diff --git a/backend/app/api/v1/file.go b/backend/app/api/v1/file.go index 4cc24f976..394d0de24 100644 --- a/backend/app/api/v1/file.go +++ b/backend/app/api/v1/file.go @@ -246,7 +246,7 @@ func (b *BaseApi) LoadFromFile(c *gin.Context) { return } defer file.Close() - buf := make([]byte, 1024*500) + buf := make([]byte, 1024*2) if _, err := file.Read(buf); err != nil { helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) return diff --git a/backend/app/dto/compose_template.go b/backend/app/dto/compose_template.go new file mode 100644 index 000000000..5a17fbbdd --- /dev/null +++ b/backend/app/dto/compose_template.go @@ -0,0 +1,25 @@ +package dto + +import "time" + +type ComposeTemplateCreate struct { + Name string `json:"name" validate:"required"` + From string `json:"from" validate:"required,oneof=edit path"` + Description string `json:"description"` + Content string `json:"content"` +} + +type ComposeTemplateUpdate struct { + From string `json:"from" validate:"required,oneof=edit path"` + Description string `json:"description"` + Content string `json:"content"` +} + +type ComposeTemplateInfo struct { + ID uint `json:"id"` + CreatedAt time.Time `json:"createdAt"` + Name string `json:"name"` + From string `json:"from"` + Description string `json:"description"` + Content string `json:"content"` +} diff --git a/backend/app/model/compose_template.go b/backend/app/model/compose_template.go new file mode 100644 index 000000000..948b9b435 --- /dev/null +++ b/backend/app/model/compose_template.go @@ -0,0 +1,10 @@ +package model + +type ComposeTemplate struct { + BaseModel + + Name string `gorm:"type:varchar(64);not null;unique" json:"name"` + From string `gorm:"type:varchar(64);not null" json:"from"` + Description string `gorm:"type:varchar(256);" json:"description"` + Content string `gorm:"type:longtext" json:"content"` +} diff --git a/backend/app/repo/compose_template.go b/backend/app/repo/compose_template.go new file mode 100644 index 000000000..ac1daf08f --- /dev/null +++ b/backend/app/repo/compose_template.go @@ -0,0 +1,69 @@ +package repo + +import ( + "github.com/1Panel-dev/1Panel/app/model" + "github.com/1Panel-dev/1Panel/global" +) + +type ComposeTemplateRepo struct{} + +type IComposeTemplateRepo interface { + Get(opts ...DBOption) (model.ComposeTemplate, error) + List(opts ...DBOption) ([]model.ComposeTemplate, error) + Page(limit, offset int, opts ...DBOption) (int64, []model.ComposeTemplate, error) + Create(compose *model.ComposeTemplate) error + Update(id uint, vars map[string]interface{}) error + Delete(opts ...DBOption) error +} + +func NewIComposeTemplateRepo() IComposeTemplateRepo { + return &ComposeTemplateRepo{} +} + +func (u *ComposeTemplateRepo) Get(opts ...DBOption) (model.ComposeTemplate, error) { + var compose model.ComposeTemplate + db := global.DB + for _, opt := range opts { + db = opt(db) + } + err := db.First(&compose).Error + return compose, err +} + +func (u *ComposeTemplateRepo) Page(page, size int, opts ...DBOption) (int64, []model.ComposeTemplate, error) { + var users []model.ComposeTemplate + db := global.DB.Model(&model.ComposeTemplate{}) + for _, opt := range opts { + db = opt(db) + } + count := int64(0) + db = db.Count(&count) + err := db.Limit(size).Offset(size * (page - 1)).Find(&users).Error + return count, users, err +} + +func (u *ComposeTemplateRepo) List(opts ...DBOption) ([]model.ComposeTemplate, error) { + var composes []model.ComposeTemplate + db := global.DB.Model(&model.ComposeTemplate{}) + for _, opt := range opts { + db = opt(db) + } + err := db.Find(&composes).Error + return composes, err +} + +func (u *ComposeTemplateRepo) Create(compose *model.ComposeTemplate) error { + return global.DB.Create(compose).Error +} + +func (u *ComposeTemplateRepo) Update(id uint, vars map[string]interface{}) error { + return global.DB.Model(&model.ComposeTemplate{}).Where("id = ?", id).Updates(vars).Error +} + +func (u *ComposeTemplateRepo) Delete(opts ...DBOption) error { + db := global.DB + for _, opt := range opts { + db = opt(db) + } + return db.Delete(&model.ComposeTemplate{}).Error +} diff --git a/backend/app/repo/entry.go b/backend/app/repo/entry.go index 35bfff802..659463da9 100644 --- a/backend/app/repo/entry.go +++ b/backend/app/repo/entry.go @@ -5,6 +5,7 @@ type RepoGroup struct { BackupRepo GroupRepo ImageRepoRepo + ComposeTemplateRepo CommandRepo OperationRepo CommonRepo diff --git a/backend/app/service/compose_template.go b/backend/app/service/compose_template.go new file mode 100644 index 000000000..6d0daeca7 --- /dev/null +++ b/backend/app/service/compose_template.go @@ -0,0 +1,80 @@ +package service + +import ( + "github.com/1Panel-dev/1Panel/app/dto" + "github.com/1Panel-dev/1Panel/constant" + "github.com/jinzhu/copier" + "github.com/pkg/errors" +) + +type ComposeTemplateService struct{} + +type IComposeTemplateService interface { + List() ([]dto.ComposeTemplateInfo, error) + SearchWithPage(search dto.PageInfo) (int64, interface{}, error) + Create(composeDto dto.ComposeTemplateCreate) error + Update(id uint, upMap map[string]interface{}) error + Delete(ids []uint) error +} + +func NewIComposeTemplateService() IComposeTemplateService { + return &ComposeTemplateService{} +} + +func (u *ComposeTemplateService) List() ([]dto.ComposeTemplateInfo, error) { + composes, err := composeRepo.List() + if err != nil { + return nil, constant.ErrRecordNotFound + } + var dtoLists []dto.ComposeTemplateInfo + for _, compose := range composes { + var item dto.ComposeTemplateInfo + if err := copier.Copy(&item, &compose); err != nil { + return nil, errors.WithMessage(constant.ErrStructTransform, err.Error()) + } + dtoLists = append(dtoLists, item) + } + return dtoLists, err +} + +func (u *ComposeTemplateService) SearchWithPage(search dto.PageInfo) (int64, interface{}, error) { + total, composes, err := composeRepo.Page(search.Page, search.PageSize) + var dtoComposeTemplates []dto.ComposeTemplateInfo + for _, compose := range composes { + var item dto.ComposeTemplateInfo + if err := copier.Copy(&item, &compose); err != nil { + return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error()) + } + dtoComposeTemplates = append(dtoComposeTemplates, item) + } + return total, dtoComposeTemplates, err +} + +func (u *ComposeTemplateService) Create(composeDto dto.ComposeTemplateCreate) error { + compose, _ := composeRepo.Get(commonRepo.WithByName(composeDto.Name)) + if compose.ID != 0 { + return constant.ErrRecordExist + } + if err := copier.Copy(&compose, &composeDto); err != nil { + return errors.WithMessage(constant.ErrStructTransform, err.Error()) + } + if err := composeRepo.Create(&compose); err != nil { + return err + } + return nil +} + +func (u *ComposeTemplateService) Delete(ids []uint) error { + if len(ids) == 1 { + compose, _ := composeRepo.Get(commonRepo.WithByID(ids[0])) + if compose.ID == 0 { + return constant.ErrRecordNotFound + } + return composeRepo.Delete(commonRepo.WithByID(ids[0])) + } + return composeRepo.Delete(commonRepo.WithIdsIn(ids)) +} + +func (u *ComposeTemplateService) Update(id uint, upMap map[string]interface{}) error { + return composeRepo.Update(id, upMap) +} diff --git a/backend/app/service/entry.go b/backend/app/service/entry.go index 9dc568f8f..8ac921c16 100644 --- a/backend/app/service/entry.go +++ b/backend/app/service/entry.go @@ -8,6 +8,7 @@ type ServiceGroup struct { BackupService GroupService ImageService + ComposeTemplateService ImageRepoService ContainerService CommandService @@ -28,6 +29,7 @@ var ( operationRepo = repo.RepoGroupApp.OperationRepo commonRepo = repo.RepoGroupApp.CommonRepo imageRepoRepo = repo.RepoGroupApp.ImageRepoRepo + composeRepo = repo.RepoGroupApp.ComposeTemplateRepo cronjobRepo = repo.RepoGroupApp.CronjobRepo settingRepo = repo.RepoGroupApp.SettingRepo appRepo = repo.RepoGroupApp.AppRepo @@ -36,6 +38,7 @@ var ( tagRepo = repo.RepoGroupApp.TagRepo appInstallRepo = repo.RepoGroupApp.AppInstallRepo appInstallResourceRepo = repo.RepoGroupApp.AppInstallResourceRpo + appContainerRepo = repo.RepoGroupApp.AppContainerRepo dataBaseRepo = repo.RepoGroupApp.DatabaseRepo appInstallBackupRepo = repo.RepoGroupApp.AppInstallBackupRepo ) diff --git a/backend/init/migration/migrations/init.go b/backend/init/migration/migrations/init.go index f1ec2f146..26a554bd5 100644 --- a/backend/init/migration/migrations/init.go +++ b/backend/init/migration/migrations/init.go @@ -157,7 +157,7 @@ var AddTableApp = &gormigrate.Migration{ var AddTableImageRepo = &gormigrate.Migration{ ID: "20201009-add-table-imagerepo", Migrate: func(tx *gorm.DB) error { - if err := tx.AutoMigrate(&model.ImageRepo{}); err != nil { + if err := tx.AutoMigrate(&model.ImageRepo{}, &model.ComposeTemplate{}); err != nil { return err } item := &model.ImageRepo{ diff --git a/backend/router/ro_container.go b/backend/router/ro_container.go index 56e6c6afe..b73ba520c 100644 --- a/backend/router/ro_container.go +++ b/backend/router/ro_container.go @@ -33,6 +33,12 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) { withRecordRouter.POST("/repo", baseApi.CreateRepo) withRecordRouter.POST("/repo/del", baseApi.DeleteRepo) + baRouter.POST("/compose/search", baseApi.SearchComposeTemplate) + baRouter.PUT("/compose/:id", baseApi.UpdateComposeTemplate) + baRouter.GET("/compose", baseApi.ListComposeTemplate) + withRecordRouter.POST("/compose", baseApi.CreateComposeTemplate) + withRecordRouter.POST("/compose/del", baseApi.DeleteComposeTemplate) + baRouter.POST("/image/search", baseApi.SearchImage) baRouter.GET("/image", baseApi.ListImage) baRouter.POST("/image/pull", baseApi.ImagePull) diff --git a/frontend/src/api/interface/container.ts b/frontend/src/api/interface/container.ts index 49d3ca613..ab4c242d7 100644 --- a/frontend/src/api/interface/container.ts +++ b/frontend/src/api/interface/container.ts @@ -161,6 +161,27 @@ export namespace Container { downloadUrl: string; } + export interface TemplateCreate { + name: string; + from: string; + description: string; + content: string; + } + export interface TemplateUpdate { + id: number; + from: string; + description: string; + content: string; + } + export interface TemplateInfo { + id: number; + createdAt: Date; + name: string; + from: string; + description: string; + content: string; + } + export interface BatchDelete { ids: Array; } diff --git a/frontend/src/api/modules/container.ts b/frontend/src/api/modules/container.ts index 448255887..27afcbcb4 100644 --- a/frontend/src/api/modules/container.ts +++ b/frontend/src/api/modules/container.ts @@ -2,33 +2,30 @@ import http from '@/api'; import { ResPage, ReqPage } from '../interface'; import { Container } from '../interface/container'; -export const getContainerPage = (params: ReqPage) => { +export const searchContainer = (params: ReqPage) => { return http.post>(`/containers/search`, params); }; export const createContainer = (params: Container.ContainerCreate) => { return http.post(`/containers`, params); }; - -export const getContainerLog = (params: Container.ContainerLogSearch) => { +export const logContainer = (params: Container.ContainerLogSearch) => { return http.post(`/containers/log`, params); }; export const ContainerStats = (id: string) => { return http.get(`/containers/stats/${id}`); }; - export const ContainerOperator = (params: Container.ContainerOperate) => { return http.post(`/containers/operate`, params); }; - export const inspect = (params: Container.ContainerInspect) => { return http.post(`/containers/inspect`, params); }; // image -export const getImagePage = (params: ReqPage) => { +export const searchImage = (params: ReqPage) => { return http.post>(`/containers/image/search`, params); }; -export const imageOptions = () => { +export const listImage = () => { return http.get>(`/containers/image`); }; export const imageBuild = (params: Container.ImageBuild) => { @@ -54,7 +51,7 @@ export const imageRemove = (params: Container.BatchDelete) => { }; // network -export const getNetworkPage = (params: ReqPage) => { +export const searchNetwork = (params: ReqPage) => { return http.post>(`/containers/network/search`, params); }; export const deleteNetwork = (params: Container.BatchDelete) => { @@ -65,10 +62,10 @@ export const createNetwork = (params: Container.NetworkCreate) => { }; // volume -export const getVolumePage = (params: ReqPage) => { +export const searchVolume = (params: ReqPage) => { return http.post>(`/containers/volume/search`, params); }; -export const volumeOptions = () => { +export const listVolume = () => { return http.get>(`/containers/volume`); }; export const deleteVolume = (params: Container.BatchDelete) => { @@ -79,18 +76,35 @@ export const createVolume = (params: Container.VolumeCreate) => { }; // repo -export const getRepoPage = (params: ReqPage) => { +export const searchImageRepo = (params: ReqPage) => { return http.post>(`/containers/repo/search`, params); }; -export const getRepoOption = () => { +export const listImageRepo = () => { return http.get(`/containers/repo`); }; -export const repoCreate = (params: Container.RepoCreate) => { +export const createImageRepo = (params: Container.RepoCreate) => { return http.post(`/containers/repo`, params); }; -export const repoUpdate = (params: Container.RepoUpdate) => { +export const updateImageRepo = (params: Container.RepoUpdate) => { return http.put(`/containers/repo/${params.id}`, params); }; -export const deleteRepo = (params: { ids: number[] }) => { +export const deleteImageRepo = (params: { ids: number[] }) => { return http.post(`/containers/repo/del`, params); }; + +// composeTemplate +export const searchComposeTemplate = (params: ReqPage) => { + return http.post>(`/containers/compose/search`, params); +}; +export const listComposeTemplate = (params: ReqPage) => { + return http.post>(`/containers/compose/search`, params); +}; +export const deleteComposeTemplate = (params: { ids: number[] }) => { + return http.post(`/containers/compose/del`, params); +}; +export const createComposeTemplate = (params: Container.TemplateCreate) => { + return http.post(`/containers/compose`, params); +}; +export const updateComposeTemplate = (params: Container.TemplateUpdate) => { + return http.put(`/containers/compose/${params.id}`, params); +}; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index a4c25b25d..99131c842 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -93,6 +93,7 @@ export default { number: 'Please enter the correct number', ip: 'Please enter the correct IP address', port: 'Please enter the correct port', + selectHelper: 'Please select the correct {0} file', }, res: { paramError: 'The request failed, please try again later!', @@ -161,7 +162,6 @@ export default { reName: 'ReName', remove: 'Remove', container: 'Container', - schedule: 'Schedule', upTime: 'UpTime', all: 'All', lastDay: 'Last Day', @@ -242,6 +242,11 @@ export default { imageRepo: 'Image repo', repoHelper: 'Does it include a mirror repository/organization/project?', auth: 'Auth', + + compose: 'Compose', + composeTemplate: 'Compose template', + description: 'Description', + content: 'Content', }, cronjob: { cronTask: 'Task', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 80c8dd16f..4966ad20d 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -2,6 +2,7 @@ export default { commons: { true: '是', false: '否', + example: '例如:', button: { create: '新建', add: '添加', @@ -90,6 +91,7 @@ export default { number: '请输入正确的数字', ip: '请输入正确的 IP 地址', port: '请输入正确的端口', + selectHelper: '请选择正确的 {0} 文件', }, res: { paramError: '请求失败,请稍后重试!', @@ -158,7 +160,6 @@ export default { reName: '重命名', remove: '移除', container: '容器', - schedule: '编排', upTime: '运行时长', all: '全部', lastDay: '最近一天', @@ -242,6 +243,11 @@ export default { imageRepo: '镜像仓库', repoHelper: '是否包含镜像仓库/组织/项目?', auth: '认证', + + compose: '编排', + composeTemplate: '编排模版', + description: '描述', + content: '内容', }, cronjob: { cronTask: '计划任务', diff --git a/frontend/src/views/container/compose/template/index.vue b/frontend/src/views/container/compose/template/index.vue new file mode 100644 index 000000000..9e0d27417 --- /dev/null +++ b/frontend/src/views/container/compose/template/index.vue @@ -0,0 +1,169 @@ + + + diff --git a/frontend/src/views/container/compose/template/operator/index.vue b/frontend/src/views/container/compose/template/operator/index.vue new file mode 100644 index 000000000..c18aac639 --- /dev/null +++ b/frontend/src/views/container/compose/template/operator/index.vue @@ -0,0 +1,133 @@ + + + diff --git a/frontend/src/views/container/container/create/index.vue b/frontend/src/views/container/container/create/index.vue index 261b28476..358aa5f08 100644 --- a/frontend/src/views/container/container/create/index.vue +++ b/frontend/src/views/container/container/create/index.vue @@ -189,7 +189,7 @@ import { reactive, ref } from 'vue'; import { Rules } from '@/global/form-rules'; import i18n from '@/lang'; import { ElForm, ElMessage } from 'element-plus'; -import { imageOptions, volumeOptions, createContainer } from '@/api/modules/container'; +import { listImage, listVolume, createContainer } from '@/api/modules/container'; import { Container } from '@/api/interface/container'; const createVisiable = ref(false); @@ -259,11 +259,11 @@ const handleVolumesDelete = (index: number) => { }; const loadImageOptions = async () => { - const res = await imageOptions(); + const res = await listImage(); images.value = res.data; }; const loadVolumeOptions = async () => { - const res = await volumeOptions(); + const res = await listVolume(); volumes.value = res.data; }; const onSubmit = async (formEl: FormInstance | undefined) => { diff --git a/frontend/src/views/container/container/index.vue b/frontend/src/views/container/container/index.vue index 58fd09127..9b912c0bc 100644 --- a/frontend/src/views/container/container/index.vue +++ b/frontend/src/views/container/container/index.vue @@ -171,7 +171,7 @@ import { oneDark } from '@codemirror/theme-one-dark'; import { reactive, onMounted, ref } from 'vue'; import { dateFromat, dateFromatForName } from '@/utils/util'; import { Rules } from '@/global/form-rules'; -import { ContainerOperator, inspect, getContainerLog, getContainerPage } from '@/api/modules/container'; +import { ContainerOperator, inspect, logContainer, searchContainer } from '@/api/modules/container'; import { Container } from '@/api/interface/container'; import { ElForm, ElMessage, ElMessageBox, FormInstance } from 'element-plus'; import i18n from '@/lang'; @@ -234,7 +234,7 @@ const timeOptions = ref([ const search = async () => { containerSearch.page = paginationConfig.page; containerSearch.pageSize = paginationConfig.pageSize; - await getContainerPage(containerSearch).then((res) => { + await searchContainer(containerSearch).then((res) => { if (res.data) { data.value = res.data.items; } @@ -272,7 +272,7 @@ const onCloseLog = async () => { clearInterval(Number(timer)); }; const searchLogs = async () => { - const res = await getContainerLog(logSearch); + const res = await logContainer(logSearch); logInfo.value = res.data; }; const onDownload = async () => { diff --git a/frontend/src/views/container/image/build/index.vue b/frontend/src/views/container/image/build/index.vue index 3d1a0fd47..22ccb64fd 100644 --- a/frontend/src/views/container/image/build/index.vue +++ b/frontend/src/views/container/image/build/index.vue @@ -93,6 +93,16 @@ const form = reactive({ tagStr: '', tags: [] as Array, }); +const varifyPath = (rule: any, value: any, callback: any) => { + if (value.indexOf('docker-compose.yml') === -1) { + callback(new Error(i18n.global.t('commons.rule.selectHelper', ['Dockerfile']))); + } + callback(); +}; +const rules = reactive({ + name: [Rules.requiredInput, Rules.name], + content: [Rules.requiredInput, { validator: varifyPath, trigger: 'change', required: true }], +}); const acceptParams = async () => { buildVisiable.value = true; form.from = 'path'; diff --git a/frontend/src/views/container/image/index.vue b/frontend/src/views/container/image/index.vue index 28cb49e5d..587d5f0d7 100644 --- a/frontend/src/views/container/image/index.vue +++ b/frontend/src/views/container/image/index.vue @@ -78,7 +78,7 @@ import Push from '@/views/container/image/push/index.vue'; import Save from '@/views/container/image/save/index.vue'; import Load from '@/views/container/image/load/index.vue'; import Build from '@/views/container/image/build/index.vue'; -import { getImagePage, getRepoOption, imageRemove } from '@/api/modules/container'; +import { searchImage, listImageRepo, imageRemove } from '@/api/modules/container'; import i18n from '@/lang'; import { ElForm } from 'element-plus'; import { useDeleteData } from '@/hooks/use-delete-data'; @@ -112,7 +112,7 @@ const search = async () => { page: paginationConfig.page, pageSize: paginationConfig.pageSize, }; - await getImagePage(repoSearch).then((res) => { + await searchImage(repoSearch).then((res) => { if (res.data) { data.value = res.data.items; } @@ -120,7 +120,7 @@ const search = async () => { }); }; const loadRepos = async () => { - const res = await getRepoOption(); + const res = await listImageRepo(); repos.value = res.data; }; diff --git a/frontend/src/views/container/index.vue b/frontend/src/views/container/index.vue index 02ab7889f..5e2eef04a 100644 --- a/frontend/src/views/container/index.vue +++ b/frontend/src/views/container/index.vue @@ -17,8 +17,11 @@ {{ $t('container.repo') }} - - {{ $t('container.schedule') }} + + {{ $t('container.compose') }} + + + {{ $t('container.composeTemplate') }} @@ -27,7 +30,7 @@ - + @@ -38,7 +41,7 @@ import Repo from '@/views/container/repo/index.vue'; import Image from '@/views/container/image/index.vue'; import Network from '@/views/container/network/index.vue'; import Volume from '@/views/container/volume/index.vue'; -import About from '@/views/setting/tabs/about.vue'; +import ComposeTemplate from '@/views/container/compose/template/index.vue'; const activeNames = ref('container'); diff --git a/frontend/src/views/container/network/index.vue b/frontend/src/views/container/network/index.vue index d00085f73..5b83e2d7f 100644 --- a/frontend/src/views/container/network/index.vue +++ b/frontend/src/views/container/network/index.vue @@ -83,7 +83,7 @@ import { javascript } from '@codemirror/lang-javascript'; import { oneDark } from '@codemirror/theme-one-dark'; import { reactive, onMounted, ref } from 'vue'; import { dateFromat } from '@/utils/util'; -import { deleteNetwork, getNetworkPage, inspect } from '@/api/modules/container'; +import { deleteNetwork, searchNetwork, inspect } from '@/api/modules/container'; import { Container } from '@/api/interface/container'; import i18n from '@/lang'; import { useDeleteData } from '@/hooks/use-delete-data'; @@ -114,7 +114,7 @@ const search = async () => { page: paginationConfig.page, pageSize: paginationConfig.pageSize, }; - await getNetworkPage(params).then((res) => { + await searchNetwork(params).then((res) => { if (res.data) { data.value = res.data.items; } diff --git a/frontend/src/views/container/repo/index.vue b/frontend/src/views/container/repo/index.vue index d7a9bd1e7..66c05afb1 100644 --- a/frontend/src/views/container/repo/index.vue +++ b/frontend/src/views/container/repo/index.vue @@ -38,7 +38,7 @@ import OperatorDialog from '@/views/container/repo/operator/index.vue'; import { reactive, onMounted, ref } from 'vue'; import { dateFromat } from '@/utils/util'; import { Container } from '@/api/interface/container'; -import { deleteRepo, getRepoPage } from '@/api/modules/container'; +import { deleteImageRepo, searchImageRepo } from '@/api/modules/container'; import { useDeleteData } from '@/hooks/use-delete-data'; import i18n from '@/lang'; @@ -49,25 +49,20 @@ const paginationConfig = reactive({ pageSize: 10, total: 0, }); -const repoSearch = reactive({ - page: 1, - pageSize: 5, -}); const search = async () => { - repoSearch.page = paginationConfig.page; - repoSearch.pageSize = paginationConfig.pageSize; - await getRepoPage(repoSearch).then((res) => { + let params = { + page: paginationConfig.page, + pageSize: paginationConfig.pageSize, + }; + await searchImageRepo(params).then((res) => { if (res.data) { data.value = res.data.items; } }); }; -interface DialogExpose { - acceptParams: (params: any) => void; -} -const dialogRef = ref(); +const dialogRef = ref(); const onOpenDialog = async ( title: string, rowData: Partial = { @@ -91,7 +86,7 @@ const onBatchDelete = async (row: Container.RepoInfo | null) => { ids.push(item.id); }); } - await useDeleteData(deleteRepo, { ids: ids }, 'commons.msg.delete', true); + await useDeleteData(deleteImageRepo, { ids: ids }, 'commons.msg.delete', true); search(); }; diff --git a/frontend/src/views/container/repo/operator/index.vue b/frontend/src/views/container/repo/operator/index.vue index c2deb2a4c..cecb83b95 100644 --- a/frontend/src/views/container/repo/operator/index.vue +++ b/frontend/src/views/container/repo/operator/index.vue @@ -48,7 +48,7 @@ import { Rules } from '@/global/form-rules'; import i18n from '@/lang'; import { ElForm, ElMessage } from 'element-plus'; import { Container } from '@/api/interface/container'; -import { repoCreate, repoUpdate } from '@/api/modules/container'; +import { createImageRepo, updateImageRepo } from '@/api/modules/container'; interface DialogProps { title: string; @@ -89,10 +89,10 @@ const onSubmit = async (formEl: FormInstance | undefined) => { formEl.validate(async (valid) => { if (!valid) return; if (dialogData.value.title === 'create') { - await repoCreate(dialogData.value.rowData!); + await createImageRepo(dialogData.value.rowData!); } if (dialogData.value.title === 'edit') { - await repoUpdate(dialogData.value.rowData!); + await updateImageRepo(dialogData.value.rowData!); } ElMessage.success(i18n.global.t('commons.msg.operationSuccess')); restForm(); diff --git a/frontend/src/views/container/volume/index.vue b/frontend/src/views/container/volume/index.vue index 2ffb856e4..d1d0f7e17 100644 --- a/frontend/src/views/container/volume/index.vue +++ b/frontend/src/views/container/volume/index.vue @@ -72,7 +72,7 @@ import { javascript } from '@codemirror/lang-javascript'; import { oneDark } from '@codemirror/theme-one-dark'; import { reactive, onMounted, ref } from 'vue'; import { dateFromat } from '@/utils/util'; -import { deleteVolume, getVolumePage, inspect } from '@/api/modules/container'; +import { deleteVolume, searchVolume, inspect } from '@/api/modules/container'; import { Container } from '@/api/interface/container'; import i18n from '@/lang'; import { useDeleteData } from '@/hooks/use-delete-data'; @@ -103,7 +103,7 @@ const search = async () => { page: paginationConfig.page, pageSize: paginationConfig.pageSize, }; - await getVolumePage(params).then((res) => { + await searchVolume(params).then((res) => { if (res.data) { data.value = res.data.items; }