mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-23 00:00:52 +00:00
feat: Support customizing whether scripts are automatically synchronized (#10487)
Refs #10057
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/core/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/mfa"
|
||||
@@ -32,6 +33,25 @@ func (b *BaseApi) GetSettingInfo(c *gin.Context) {
|
||||
helper.SuccessWithData(c, setting)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Load system setting by key
|
||||
// @Success 200 {string} info
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /core/settings/by [post]
|
||||
func (b *BaseApi) GetSettingByKey(c *gin.Context) {
|
||||
var req dto.SettingKey
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
setting, err := repo.NewISettingRepo().GetValueByKey(req.Key)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, setting)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Load system terminal setting info
|
||||
// @Success 200 {object} dto.TerminalInfo
|
||||
|
||||
@@ -52,6 +52,10 @@ type SettingInfo struct {
|
||||
ApiKeyValidityTime string `json:"apiKeyValidityTime"`
|
||||
}
|
||||
|
||||
type SettingKey struct {
|
||||
Key string `json:"key" validate:"required,oneof=ScriptSync"`
|
||||
}
|
||||
|
||||
type SettingUpdate struct {
|
||||
Key string `json:"key" validate:"required"`
|
||||
Value string `json:"value"`
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
mathRand "math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/1Panel-dev/1Panel/core/init/cron/job"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/common"
|
||||
@@ -19,7 +21,8 @@ func Init() {
|
||||
global.LOG.Errorf("[core] can not add backup token refresh corn job: %s", err.Error())
|
||||
}
|
||||
|
||||
if !global.CONF.Base.IsOffLine {
|
||||
scriptSync, _ := repo.NewISettingRepo().GetValueByKey("ScriptSync")
|
||||
if !global.CONF.Base.IsOffLine && scriptSync == constant.StatusEnable {
|
||||
scriptJob := job.NewScriptJob()
|
||||
if _, err := global.Cron.AddJob(fmt.Sprintf("%v %v * * *", mathRand.Intn(60), mathRand.Intn(3)), scriptJob); err != nil {
|
||||
global.LOG.Errorf("[core] can not add script sync corn job: %s", err.Error())
|
||||
|
||||
@@ -24,6 +24,7 @@ func Init() {
|
||||
migrations.AddDiskMenu,
|
||||
migrations.AddSimpleNodeGroup,
|
||||
migrations.AddUpgradeBackupCopies,
|
||||
migrations.AddScriptSync,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
||||
@@ -545,3 +545,13 @@ var AddUpgradeBackupCopies = &gormigrate.Migration{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddScriptSync = &gormigrate.Migration{
|
||||
ID: "20250916-add-script-sync",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.Create(&model.Setting{Key: "ScriptSync", Value: constant.StatusEnable}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2,12 +2,17 @@ package run
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/core/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/core/app/service"
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
)
|
||||
|
||||
func Init() {
|
||||
if err := service.NewIScriptService().Sync(dto.OperateByTaskID{}); err != nil {
|
||||
global.LOG.Errorf("sync scripts from remote failed, err: %v", err)
|
||||
scriptSync, _ := repo.NewISettingRepo().GetValueByKey("ScriptSync")
|
||||
if !global.CONF.Base.IsOffLine && scriptSync == constant.StatusEnable {
|
||||
if err := service.NewIScriptService().Sync(dto.OperateByTaskID{}); err != nil {
|
||||
global.LOG.Errorf("sync scripts from remote failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ func (s *SettingRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
{
|
||||
router.POST("/search", baseApi.GetSettingInfo)
|
||||
router.POST("/expired/handle", baseApi.HandlePasswordExpired)
|
||||
settingRouter.POST("/by", baseApi.GetSettingByKey)
|
||||
settingRouter.POST("/terminal/search", baseApi.GetTerminalSettingInfo)
|
||||
settingRouter.GET("/search/available", baseApi.GetSystemAvailable)
|
||||
settingRouter.POST("/update", baseApi.UpdateSetting)
|
||||
|
||||
@@ -76,6 +76,9 @@ export const getAgentSettingByKey = (key: string) => {
|
||||
export const getSettingInfo = () => {
|
||||
return http.post<Setting.SettingInfo>(`/core/settings/search`);
|
||||
};
|
||||
export const getSettingBy = (key: string) => {
|
||||
return http.post<string>(`/core/settings/by`, { key: key });
|
||||
};
|
||||
export const getTerminalInfo = () => {
|
||||
return http.post<Setting.TerminalInfo>(`/core/settings/terminal/search`);
|
||||
};
|
||||
|
||||
@@ -1131,6 +1131,12 @@ const message = {
|
||||
alertTitle: 'Planned Task - {0} 「{1}」 Task Failure Alert',
|
||||
library: {
|
||||
script: 'Script',
|
||||
syncNow: 'Sync Now',
|
||||
turnOnSync: 'Enable Auto Sync',
|
||||
turnOnSyncHelper:
|
||||
'Enabling auto sync will perform automatic synchronization during early morning hours daily',
|
||||
turnOffSync: 'Disable Auto Sync',
|
||||
turnOffSyncHelper: 'Disabling auto sync may cause script synchronization delays, confirm?',
|
||||
isInteractive: 'Interactive',
|
||||
interactive: 'Interactive script',
|
||||
interactiveHelper: 'Requires user input during execution and cannot be used in scheduled tasks.',
|
||||
|
||||
@@ -1131,6 +1131,13 @@ const message = {
|
||||
alertTitle: 'Tarea programada - {0} 「{1}」 Alerta de fallo',
|
||||
library: {
|
||||
script: 'Script',
|
||||
syncNow: 'Sincronizar Ahora',
|
||||
turnOnSync: 'Activar Sincronización Automática',
|
||||
turnOnSyncHelper:
|
||||
'Activar la sincronización automática realizará sincronizaciones automáticas durante las primeras horas de la madrugada diariamente',
|
||||
turnOffSync: 'Desactivar Sincronización Automática',
|
||||
turnOffSyncHelper:
|
||||
'Desactivar la sincronización automática puede causar retrasos en la sincronización de scripts, ¿confirmar?',
|
||||
isInteractive: 'Interactivo',
|
||||
interactive: 'Script interactivo',
|
||||
interactiveHelper:
|
||||
|
||||
@@ -1094,6 +1094,11 @@ const message = {
|
||||
alertTitle: '計画タスク - {0}「{1}」タスク障害アラート',
|
||||
library: {
|
||||
script: 'スクリプト',
|
||||
syncNow: '今すぐ同期',
|
||||
turnOnSync: '自動同期を有効化',
|
||||
turnOnSyncHelper: '自動同期を有効にすると、毎日未明の時間帯に自動同期が実行されます',
|
||||
turnOffSync: '自動同期を無効化',
|
||||
turnOffSyncHelper: '自動同期を無効にするとスクリプトの同期が遅れる可能性がありますが、よろしいですか?',
|
||||
isInteractive: '対話型',
|
||||
interactive: '対話型スクリプト',
|
||||
interactiveHelper: '実行中にユーザー入力が必要で、スケジュールタスクでは使用できません。',
|
||||
|
||||
@@ -1087,6 +1087,11 @@ const message = {
|
||||
alertTitle: '예정된 작업 - {0} 「{1}」 작업 실패 경고',
|
||||
library: {
|
||||
script: '스크립트',
|
||||
syncNow: '지금 동기화',
|
||||
turnOnSync: '자동 동기화 켜기',
|
||||
turnOnSyncHelper: '자동 동기화를 켜면 매일 새벽 시간에 자동 동기화가 수행됩니다',
|
||||
turnOffSync: '자동 동기화 끄기',
|
||||
turnOffSyncHelper: '자동 동기화를 끄면 스크립트 동기화가 지연될 수 있습니다. 확인하시겠습니까?',
|
||||
isInteractive: '대화형',
|
||||
interactive: '대화형 스크립트',
|
||||
interactiveHelper: '실행 중 사용자 입력이 필요하며 예약 작업에서는 사용할 수 없습니다.',
|
||||
|
||||
@@ -1122,6 +1122,12 @@ const message = {
|
||||
alertTitle: 'Tugas Terancang - {0} 「{1}」 Amaran Kegagalan Tugas',
|
||||
library: {
|
||||
script: 'Skrip',
|
||||
syncNow: 'Segerakan Sekarang',
|
||||
turnOnSync: 'Hidupkan Segerakan Auto',
|
||||
turnOnSyncHelper:
|
||||
'Menghidupkan segerakan auto akan melakukan penyegerakan automatik pada waktu awal pagi setiap hari',
|
||||
turnOffSync: 'Matikan Segerakan Auto',
|
||||
turnOffSyncHelper: 'Mematikan segerakan auto mungkin menyebabkan kelewatan penyegerakan skrip, sahkan?',
|
||||
isInteractive: 'Interaktif',
|
||||
interactive: 'Skrip interaktif',
|
||||
interactiveHelper:
|
||||
|
||||
@@ -1114,6 +1114,13 @@ const message = {
|
||||
alertTitle: 'Tarefa Planejada - {0} 「{1}」 Alerta de Falha na Tarefa',
|
||||
library: {
|
||||
script: 'Script',
|
||||
syncNow: 'Sincronizar Agora',
|
||||
turnOnSync: 'Ativar Sincronização Automática',
|
||||
turnOnSyncHelper:
|
||||
'Ativar a sincronização automática realizará sincronizações automáticas durante as primeiras horas da manhã diariamente',
|
||||
turnOffSync: 'Desativar Sincronização Automática',
|
||||
turnOffSyncHelper:
|
||||
'Desativar a sincronização automática pode causar atrasos na sincronização de scripts, confirmar?',
|
||||
isInteractive: 'Interativo',
|
||||
interactive: 'Script interativo',
|
||||
interactiveHelper:
|
||||
|
||||
@@ -1117,6 +1117,13 @@ const message = {
|
||||
alertTitle: 'Плановая задача - {0} «{1}» Оповещение о сбое задачи',
|
||||
library: {
|
||||
script: 'Скрипт',
|
||||
syncNow: 'Синхронизировать Сейчас',
|
||||
turnOnSync: 'Включить Автосинхронизацию',
|
||||
turnOnSyncHelper:
|
||||
'Включение автосинхронизации будет выполнять автоматическую синхронизацию в ранние утренние часы ежедневно',
|
||||
turnOffSync: 'Отключить Автосинхронизацию',
|
||||
turnOffSyncHelper:
|
||||
'Отключение автосинхронизации может вызвать задержки синхронизации скриптов, подтвердить?',
|
||||
isInteractive: 'Интерактивный',
|
||||
interactive: 'Интерактивный скрипт',
|
||||
interactiveHelper:
|
||||
|
||||
@@ -1142,6 +1142,13 @@ const message = {
|
||||
alertTitle: 'Planlanmış Görev - {0} 「{1}」 Görev Başarısızlık Uyarısı',
|
||||
library: {
|
||||
script: 'Script',
|
||||
syncNow: 'Hemen Senkronize Et',
|
||||
turnOnSync: 'Otomatik Senkronizasyonu Aç',
|
||||
turnOnSyncHelper:
|
||||
'Otomatik senkronizasyonu açmak, her gün sabahın erken saatlerinde otomatik senkronizasyon gerçekleştirecektir',
|
||||
turnOffSync: 'Otomatik Senkronizasyonu Kapat',
|
||||
turnOffSyncHelper:
|
||||
'Otomatik senkronizasyonu kapatmak, betik senkronizasyon gecikmelerine neden olabilir, onaylıyor musunuz?',
|
||||
isInteractive: 'Etkileşimli',
|
||||
interactive: 'Etkileşimli script',
|
||||
interactiveHelper: 'Yürütme sırasında kullanıcı girişi gerektirir ve zamanlanmış görevlerde kullanılamaz.',
|
||||
|
||||
@@ -1076,6 +1076,11 @@ const message = {
|
||||
alertTitle: '計畫任務-{0}「{1}」任務失敗告警',
|
||||
library: {
|
||||
script: '腳本',
|
||||
syncNow: '立即同步',
|
||||
turnOnSync: '開啟自動同步',
|
||||
turnOnSyncHelper: '開啟自動同步將在每天凌晨時段進行自動同步',
|
||||
turnOffSync: '關閉自動同步',
|
||||
turnOffSyncHelper: '關閉自動同步可能導致腳本同步不及時,是否確認?',
|
||||
isInteractive: '互動式',
|
||||
interactive: '互動式腳本',
|
||||
interactiveHelper: '在腳本執行過程中需要使用者輸入參數或做出選擇,且無法用於計劃任務中。',
|
||||
|
||||
@@ -1076,6 +1076,11 @@ const message = {
|
||||
alertTitle: '计划任务-{0}「 {1} 」任务失败告警',
|
||||
library: {
|
||||
script: '脚本',
|
||||
syncNow: '立即同步',
|
||||
turnOnSync: '开启自动同步',
|
||||
turnOnSyncHelper: '开启自动同步将在每天凌晨时段进行自动同步',
|
||||
turnOffSync: '关闭自动同步',
|
||||
turnOffSyncHelper: '关闭自动同步可能导致脚本同步不及时,是否确认?',
|
||||
isInteractive: '交互式',
|
||||
interactive: '交互式脚本',
|
||||
interactiveHelper: '在脚本执行过程中需要用户输入参数或做出选择,且无法用于计划任务中。',
|
||||
|
||||
@@ -5,9 +5,26 @@
|
||||
<el-button type="primary" @click="onOpenDialog('create')">
|
||||
{{ $t('commons.button.create') }}
|
||||
</el-button>
|
||||
<el-button type="primary" plain @click="onSync()">
|
||||
{{ $t('commons.button.sync') }}
|
||||
</el-button>
|
||||
<el-dropdown @command="handleSyncOp" class="mr-2.5">
|
||||
<el-button type="primary" plain>
|
||||
{{ $t('commons.button.sync') }}
|
||||
<el-icon><arrow-down /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="sync">
|
||||
{{ $t('cronjob.library.syncNow') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="scriptSync === 'Disable'" command="turnOnSync">
|
||||
{{ $t('cronjob.library.turnOnSync') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="scriptSync === 'Enable'" command="turnOffSync">
|
||||
{{ $t('cronjob.library.turnOffSync') }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
|
||||
<el-button type="primary" plain @click="onOpenGroupDialog()">
|
||||
{{ $t('commons.table.group') }}
|
||||
</el-button>
|
||||
@@ -116,6 +133,7 @@ import { GlobalStore } from '@/store';
|
||||
import { getGroupList } from '@/api/modules/group';
|
||||
import CodemirrorDrawer from '@/components/codemirror-pro/drawer.vue';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { getSettingBy, updateSetting } from '@/api/modules/setting';
|
||||
|
||||
const globalStore = GlobalStore();
|
||||
const mobile = computed(() => {
|
||||
@@ -129,6 +147,7 @@ const opRef = ref();
|
||||
|
||||
const runRef = ref();
|
||||
const taskLogRef = ref();
|
||||
const scriptSync = ref();
|
||||
|
||||
const data = ref();
|
||||
const paginationConfig = reactive({
|
||||
@@ -194,7 +213,7 @@ const onDelete = async (row: Cronjob.ScriptInfo | null) => {
|
||||
};
|
||||
|
||||
const onSync = async () => {
|
||||
ElMessageBox.confirm(i18n.global.t('cronjob.library.syncHelper', i18n.global.t('commons.button.sync')), {
|
||||
ElMessageBox.confirm(i18n.global.t('cronjob.library.syncHelper'), i18n.global.t('commons.button.syncNow'), {
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
type: 'info',
|
||||
@@ -217,6 +236,46 @@ const openTaskLog = (taskID: string) => {
|
||||
taskLogRef.value.openWithTaskID(taskID, true, 'local');
|
||||
};
|
||||
|
||||
const loadSyncStatus = async () => {
|
||||
const res = await getSettingBy('ScriptSync');
|
||||
scriptSync.value = res.data;
|
||||
};
|
||||
const handleSyncOp = async (command: string) => {
|
||||
let val = 'Enable';
|
||||
switch (command) {
|
||||
case 'sync':
|
||||
onSync();
|
||||
return;
|
||||
case 'turnOnSync':
|
||||
val = 'Enable';
|
||||
break;
|
||||
case 'turnOffSync':
|
||||
val = 'Disable';
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
ElMessageBox.confirm(
|
||||
i18n.global.t('cronjob.library.' + command + 'Helper'),
|
||||
i18n.global.t('cronjob.library.' + command),
|
||||
{
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
type: 'info',
|
||||
},
|
||||
).then(async () => {
|
||||
loading.value = true;
|
||||
await updateSetting({ key: 'ScriptSync', value: val })
|
||||
.then(() => {
|
||||
loadSyncStatus();
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
let params = {
|
||||
info: searchInfo.value,
|
||||
@@ -297,6 +356,7 @@ const buttons = [
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
loadSyncStatus();
|
||||
loadGroupOptions();
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user