feat: 应用增加 Web 访问地址 (#6248)

This commit is contained in:
zhengkunwang 2024-08-26 15:37:13 +08:00 committed by GitHub
parent 4ac5ff7cf0
commit 53cfb2e755
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 137 additions and 10 deletions

View file

@ -325,3 +325,24 @@ func (b *BaseApi) IgnoreUpgrade(c *gin.Context) {
}
helper.SuccessWithOutData(c)
}
// @Tags App
// @Summary Update app config
// @Description 更新应用配置
// @Accept json
// @Param request body request.AppConfigUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /apps/installed/config/update [post]
// @x-panel-log {"bodyKeys":["installID","webUI"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"应用配置更新 [installID]","formatEN":"Application config update [installID]"}
func (b *BaseApi) UpdateAppConfig(c *gin.Context) {
var req request.AppConfigUpdate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := appInstallService.UpdateAppConfig(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}

View file

@ -37,6 +37,8 @@ type AppContainerConfig struct {
HostMode bool `json:"hostMode"`
PullImage bool `json:"pullImage"`
GpuConfig bool `json:"gpuConfig"`
WebUI string `json:"webUI"`
Type string `json:"type"`
}
type AppInstalledSearch struct {
@ -103,6 +105,11 @@ type AppInstalledUpdate struct {
AppContainerConfig
}
type AppConfigUpdate struct {
InstallID uint `json:"installID" validate:"required"`
WebUI string `json:"webUI"`
}
type AppInstalledIgnoreUpgrade struct {
DetailID uint `json:"detailID" validate:"required"`
Operate string `json:"operate" validate:"required,oneof=cancel ignore"`

View file

@ -120,6 +120,7 @@ type AppInstallDTO struct {
AppType string `json:"appType"`
AppStatus string `json:"appStatus"`
DockerCompose string `json:"dockerCompose"`
WebUI string `json:"webUI"`
CreatedAt time.Time `json:"createdAt"`
App AppDetail `json:"app"`
}

View file

@ -21,8 +21,9 @@ type AppInstall struct {
Message string `json:"message"`
ContainerName string `json:"containerName" gorm:"not null"`
ServiceName string `json:"serviceName" gorm:"not null"`
HttpPort int `json:"httpPort" gorm:"not null"`
HttpsPort int `json:"httpsPort" gorm:"not null"`
HttpPort int `json:"httpPort"`
HttpsPort int `json:"httpsPort"`
WebUI string `json:"webUI"`
App App `json:"app" gorm:"-:migration"`
}

View file

@ -59,6 +59,7 @@ type IAppInstallService interface {
GetDefaultConfigByKey(key, name string) (string, error)
DeleteCheck(installId uint) ([]dto.AppResource, error)
UpdateAppConfig(req request.AppConfigUpdate) error
GetInstallList() ([]dto.AppInstallInfo, error)
}
@ -304,6 +305,18 @@ func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
}
}
func (a *AppInstallService) UpdateAppConfig(req request.AppConfigUpdate) error {
installed, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallID))
if err != nil {
return err
}
installed.WebUI = ""
if req.WebUI != "" {
installed.WebUI = req.WebUI
}
return appInstallRepo.Save(context.Background(), &installed)
}
func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
installed, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallId))
if err != nil {
@ -767,6 +780,8 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
}
res.AppContainerConfig = config
res.HostMode = isHostModel(install.DockerCompose)
res.WebUI = install.WebUI
res.Type = install.App.Type
return &res, nil
}

View file

@ -1363,6 +1363,7 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
AppType: installed.App.Type,
Path: installed.GetPath(),
CreatedAt: installed.CreatedAt,
WebUI: installed.WebUI,
App: response.AppDetail{
Github: installed.App.Github,
Website: installed.App.Website,

View file

@ -20,6 +20,7 @@ func Init() {
migrations.UpdateWebsiteDomain,
migrations.UpdateApp,
migrations.AddTaskDB,
migrations.UpdateAppInstall,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)

View file

@ -251,3 +251,11 @@ var UpdateApp = &gormigrate.Migration{
&model.App{})
},
}
var UpdateAppInstall = &gormigrate.Migration{
ID: "20240828-update-app-install",
Migrate: func(tx *gorm.DB) error {
return tx.AutoMigrate(
&model.AppInstall{})
},
}

View file

@ -38,5 +38,6 @@ func (a *AppRouter) InitRouter(Router *gin.RouterGroup) {
appRouter.POST("/installed/ignore", baseApi.IgnoreUpgrade)
appRouter.GET("/ignored/detail", baseApi.GetIgnoredApp)
appRouter.POST("/installed/update/versions", baseApi.GetUpdateVersions)
appRouter.POST("/installed/config/update", baseApi.UpdateAppConfig)
}
}

View file

@ -239,6 +239,8 @@ export namespace App {
allowPort: boolean;
dockerCompose: string;
hostMode?: boolean;
type: string;
webUI: string;
}
export interface IgnoredApp {
@ -256,4 +258,9 @@ export namespace App {
export interface AppStoreSync {
taskID: string;
}
export interface AppConfigUpdate {
installID: number;
webUI: string;
}
}

View file

@ -106,3 +106,7 @@ export const IgnoreUpgrade = (req: any) => {
export const GetIgnoredApp = () => {
return http.get<App.IgnoredApp>(`apps/ignored/detail`);
};
export const UpdateInstallConfig = (req: App.AppConfigUpdate) => {
return http.post(`apps/installed/config/update`, req);
};

View file

@ -1883,6 +1883,8 @@ const message = {
gpuConfig: 'Enable GPU Support',
gpuConfigHelper:
'Please ensure the machine has an NVIDIA GPU and that NVIDIA drivers and the NVIDIA Docker Container Toolkit are installed',
webUI: 'Web Access Address',
webUIPlaceholder: 'For example: http://example.com:8080/login',
},
website: {
website: 'Website',

View file

@ -1748,6 +1748,8 @@ const message = {
memoryRequiredHelper: '目前應用記憶體需求 {0}',
gpuConfig: '開啟 GPU 支援',
gpuConfigHelper: '請確保機器有 NVIDIA GPU 並且安裝 NVIDIA 驅動 NVIDIA docker Container Toolkit',
webUI: 'Web 訪問地址',
webUIPlaceholder: '例如http://example.com:8080/login',
},
website: {
website: '網站',

View file

@ -1749,6 +1749,8 @@ const message = {
memoryRequiredHelper: '当前应用内存需求 {0}',
gpuConfig: '开启 GPU 支持',
gpuConfigHelper: '请确保机器有 NVIDIA GPU 并且安装 NVIDIA 驱动 NVIDIA docker Container Toolkit',
webUI: 'Web 访问地址',
webUIPlaceholder: '例如http://example.com:8080/login',
},
website: {
website: '网站',

View file

@ -5,15 +5,29 @@
{{ edit ? $t('app.detail') : $t('commons.button.edit') }}
</el-button>
</template>
<el-descriptions border :column="1" v-if="!edit">
<el-descriptions-item v-for="(param, key) in params" :label="getLabel(param)" :key="key">
<span>{{ param.showValue && param.showValue != '' ? param.showValue : param.value }}</span>
</el-descriptions-item>
</el-descriptions>
<div v-if="!edit">
<el-descriptions border :column="1">
<el-descriptions-item v-for="(param, key) in params" :label="getLabel(param)" :key="key">
<span>{{ param.showValue && param.showValue != '' ? param.showValue : param.value }}</span>
</el-descriptions-item>
</el-descriptions>
<el-form label-position="top" class="mt-2">
<el-form-item v-if="appType == 'website'" :label="$t('app.webUI')">
<el-input v-model="appConfigUpdate.webUI" :placeholder="$t('app.webUIPlaceholder')"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" :disabled="loading" @click="updateAppConfig">
{{ $t('commons.button.confirm') }}
</el-button>
</el-form-item>
</el-form>
</div>
<div v-else v-loading="loading">
<el-alert :title="$t('app.updateHelper')" type="warning" :closable="false" class="common-prompt" />
<el-form @submit.prevent ref="paramForm" :model="paramModel" label-position="top" :rules="rules">
<el-form-item v-if="appType == 'website'" :label="$t('app.webUI')">
<el-input v-model="appConfigUpdate.webUI" :placeholder="$t('app.webUIPlaceholder')"></el-input>
</el-form-item>
<div v-for="(p, index) in params" :key="index">
<el-form-item :prop="p.key" :label="getLabel(p)">
<el-input
@ -93,7 +107,7 @@
</template>
<script lang="ts" setup>
import { App } from '@/api/interface/app';
import { GetAppInstallParams, UpdateAppInstallParams } from '@/api/modules/app';
import { GetAppInstallParams, UpdateAppInstallParams, UpdateInstallConfig } from '@/api/modules/app';
import { reactive, ref } from 'vue';
import { FormInstance } from 'element-plus';
import { Rules, checkNumberRange } from '@/global/form-rules';
@ -128,7 +142,14 @@ const rules = reactive({
memoryLimit: [Rules.requiredInput, checkNumberRange(0, 9999999999)],
containerName: [Rules.containerName],
});
const submitModel = ref<any>({});
const submitModel = ref<any>({
webUI: '',
});
const appType = ref('');
const appConfigUpdate = ref<App.AppConfigUpdate>({
installID: 0,
webUI: '',
});
const acceptParams = async (props: ParamProps) => {
submitModel.value.installId = props.id;
@ -188,6 +209,8 @@ const get = async () => {
paramModel.value.advanced = false;
paramModel.value.dockerCompose = res.data.dockerCompose;
paramModel.value.isHostMode = res.data.hostMode;
appConfigUpdate.value.webUI = res.data.webUI;
appType.value = res.data.type;
} catch (error) {
} finally {
loading.value = false;
@ -240,6 +263,17 @@ const submit = async (formEl: FormInstance) => {
});
};
const updateAppConfig = async () => {
try {
await UpdateInstallConfig({
installID: Number(paramData.value.id),
webUI: appConfigUpdate.value.webUI,
});
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
handleClose();
} catch (error) {}
};
defineExpose({ acceptParams });
</script>

View file

@ -175,6 +175,22 @@
</el-button>
</el-tooltip>
</span>
<span class="ml-1">
<el-tooltip
v-if="installed.webUI !== ''"
effect="dark"
:content="installed.webUI"
placement="top"
>
<el-button
type="primary"
link
@click="toLink(installed.webUI)"
>
<el-icon><Promotion /></el-icon>
</el-button>
</el-tooltip>
</span>
<el-button
class="h-button"
@ -650,6 +666,10 @@ const openLog = (row: any) => {
}
};
const toLink = (link: string) => {
window.open(link, '_blank');
};
onMounted(() => {
const path = router.currentRoute.value.path;
if (path == '/apps/upgrade') {