Compare commits

...
13 Commits
Author SHA1 Message Date
王贺 0be45b6a55 Modify the install script 2025-06-10 17:18:51 +08:00
CityFun c922615183 feat: fix issue with build frontend failed (#8994) 2025-06-10 16:57:45 +08:00
CityFun 8b2990fca4 feat: change 1panel v1 docs url (#8993) 2025-06-10 16:22:04 +08:00
longjuan 37b5cd743a feat: add name attrs to login inputs for password managers to recognize (#8953) 2025-06-10 16:21:59 +08:00
玲珑芯ExquisiteCore 3b1324db08 feat: Move current status to first position in MySQL settings and set… (#8882)
* feat: Move current status to first position in MySQL and Redis settings and set as default tab
2025-06-10 16:21:53 +08:00
Alan f56bbb7dc1 ini filetype support (#8628) 2025-06-10 16:21:43 +08:00
CityFun cff649ae95 fix: Fix issue with update website config (#8610) 2025-06-10 16:21:38 +08:00
Wankko Ree cb87ca4361 fix: the docker image which no tag but used be pruned (#8529) 2025-06-10 16:21:32 +08:00
igophper 165d2b1290 fix(cronjob): prevent unnecessary log updates and clean log formatting (#8481)
Refs #8425
2025-06-10 16:21:25 +08:00
igophper 189555e16c fix(editor): reset edit state after not saving content (#8474)
Refs #8461
2025-06-10 16:21:12 +08:00
ChengPlay 2d8250926f Fix issue with errors when reverse proxy source text includes comments. (#8444)
Refs https://github.com/1Panel-dev/1Panel/issues/8442
2025-06-10 16:20:52 +08:00
ChengPlay 47e343712e feat: change commandPlaceHolder translate (#8391) 2025-06-10 16:20:33 +08:00
ssongliu 11ffb4f2be fix: Fix the mysql root account permission switchover exception (#8378) 2025-06-10 16:20:21 +08:00
22 changed files with 88 additions and 56 deletions
+18 -5
View File
@@ -427,7 +427,9 @@ func (w WebsiteService) UpdateWebsite(req request.WebsiteUpdate) error {
} }
} }
website.PrimaryDomain = req.PrimaryDomain website.PrimaryDomain = req.PrimaryDomain
website.WebsiteGroupID = req.WebsiteGroupID if req.WebsiteGroupID > 0 {
website.WebsiteGroupID = req.WebsiteGroupID
}
website.Remark = req.Remark website.Remark = req.Remark
website.IPV6 = req.IPV6 website.IPV6 = req.IPV6
@@ -1768,11 +1770,22 @@ func (w WebsiteService) GetProxies(id uint) (res []request.WebsiteProxyConfig, e
} }
directives := config.GetDirectives() directives := config.GetDirectives()
location, ok := directives[0].(*components.Location) var (
if !ok { location *components.Location
err = errors.New("error") ok bool
return )
for _, directive := range directives {
if directive.GetName() == "location" {
location, ok = directive.(*components.Location)
if ok {
break
}
}
} }
if location == nil {
return nil, buserr.New("ErrConfigParse")
}
proxyConfig.ProxyPass = location.ProxyPass proxyConfig.ProxyPass = location.ProxyPass
proxyConfig.Cache = location.Cache proxyConfig.Cache = location.Cache
if location.CacheTime > 0 { if location.CacheTime > 0 {
+12 -13
View File
@@ -188,19 +188,18 @@ func (r *Local) ChangeAccess(info AccessChangeInfo) error {
info.Name = "*" info.Name = "*"
info.Password = r.Password info.Password = r.Password
} }
if info.Permission == info.OldPermission { if info.Permission != info.OldPermission {
return nil if err := r.Delete(DeleteInfo{
} Version: info.Version,
if err := r.Delete(DeleteInfo{ Username: info.Username,
Version: info.Version, Permission: info.OldPermission,
Username: info.Username, ForceDelete: true,
Permission: info.OldPermission, Timeout: 300}); err != nil {
ForceDelete: true, return err
Timeout: 300}); err != nil { }
return err if info.Username == "root" {
} return nil
if info.Username == "root" { }
return nil
} }
if err := r.CreateUser(CreateInfo{ if err := r.CreateUser(CreateInfo{
Name: info.Name, Name: info.Name,
+12 -13
View File
@@ -199,19 +199,18 @@ func (r *Remote) ChangeAccess(info AccessChangeInfo) error {
info.Name = "*" info.Name = "*"
info.Password = r.Password info.Password = r.Password
} }
if info.Permission == info.OldPermission { if info.Permission != info.OldPermission {
return nil if err := r.Delete(DeleteInfo{
} Version: info.Version,
if err := r.Delete(DeleteInfo{ Username: info.Username,
Version: info.Version, Permission: info.OldPermission,
Username: info.Username, ForceDelete: true,
Permission: info.OldPermission, Timeout: 300}); err != nil {
ForceDelete: true, return err
Timeout: 300}); err != nil { }
return err if info.Username == "root" {
} return nil
if info.Username == "root" { }
return nil
} }
if err := r.CreateUser(CreateInfo{ if err := r.CreateUser(CreateInfo{
Name: info.Name, Name: info.Name,
+3 -3
View File
@@ -6,15 +6,15 @@ command -v wget >/dev/null || {
} }
if [ ! -f "1pctl" ]; then if [ ! -f "1pctl" ]; then
wget https://github.com/1Panel-dev/installer/raw/main/1pctl wget https://github.com/1Panel-dev/installer/raw/dev/1pctl
fi fi
if [ ! -f "1panel.service" ]; then if [ ! -f "1panel.service" ]; then
wget https://github.com/1Panel-dev/installer/raw/main/1panel.service wget https://github.com/1Panel-dev/installer/raw/dev/1panel.service
fi fi
if [ ! -f "install.sh" ]; then if [ ! -f "install.sh" ]; then
wget https://github.com/1Panel-dev/installer/raw/main/install.sh wget https://github.com/1Panel-dev/installer/raw/dev/install.sh
fi fi
if [ ! -f "GeoIP.mmdb" ]; then if [ ! -f "GeoIP.mmdb" ]; then
+1
View File
@@ -7,6 +7,7 @@ location ^~ /test {
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection; proxy_set_header Connection $http_connection;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_http_version 1.1; proxy_http_version 1.1;
add_header X-Cache $upstream_cache_status; add_header X-Cache $upstream_cache_status;
add_header Cache-Control no-cache; add_header Cache-Control no-cache;
+4
View File
@@ -95,6 +95,10 @@ export const Languages = [
label: 'css', label: 'css',
value: ['css'], value: ['css'],
}, },
{
label: 'ini',
value: ['ini'],
},
]; ];
export const Rewrites = [ export const Rewrites = [
+1 -1
View File
@@ -2621,7 +2621,7 @@ const message = {
domain: 'Default Access Address', domain: 'Default Access Address',
domainHelper: 'For example: 192.168.1.1 or example.com', domainHelper: 'For example: 192.168.1.1 or example.com',
bindDomain: 'Bind Website', bindDomain: 'Bind Website',
commandPlaceHolder: 'Currently only supports npx startup commands', commandPlaceHolder: 'Currently only supports npx and binary startup commands',
importMcpJson: 'Import MCP Server Configuration', importMcpJson: 'Import MCP Server Configuration',
importMcpJsonError: 'mcpServers structure is incorrect', importMcpJsonError: 'mcpServers structure is incorrect',
bindDomainHelper: bindDomainHelper:
+1 -1
View File
@@ -2591,7 +2591,7 @@ const message = {
domain: 'デフォルトアクセスアドレス', domain: 'デフォルトアクセスアドレス',
domainHelper: '例: 192.168.1.1 または example.com', domainHelper: '例: 192.168.1.1 または example.com',
bindDomain: 'ウェブサイトをバインド', bindDomain: 'ウェブサイトをバインド',
commandPlaceHolder: '現在、npx スタートアップコマンドのみをサポートしています', commandPlaceHolder: '現在、npx およびバイナリスタートアップコマンドのみをサポートしています',
importMcpJson: 'MCP サーバー設定をインポート', importMcpJson: 'MCP サーバー設定をインポート',
importMcpJsonError: 'mcpServers 構造が正しくありません', importMcpJsonError: 'mcpServers 構造が正しくありません',
bindDomainHelper: bindDomainHelper:
+1 -1
View File
@@ -2550,7 +2550,7 @@ const message = {
domain: 'デフォルトアクセスアドレス', domain: 'デフォルトアクセスアドレス',
domainHelper: '例: 192.168.1.1 または example.com', domainHelper: '例: 192.168.1.1 または example.com',
bindDomain: 'ウェブサイトをバインド', bindDomain: 'ウェブサイトをバインド',
commandPlaceHolder: '현재 npx 시작 명령만 지원합니다', commandPlaceHolder: '현재 npx 및 바이너리 시작 명령만 지원합니다',
importMcpJson: 'MCP サーバー設定をインポート', importMcpJson: 'MCP サーバー設定をインポート',
importMcpJsonError: 'mcpServers 構造が正しくありません', importMcpJsonError: 'mcpServers 構造が正しくありません',
bindDomainHelper: bindDomainHelper:
+1 -1
View File
@@ -2649,7 +2649,7 @@ const message = {
domain: 'Alamat Akses Lalai', domain: 'Alamat Akses Lalai',
domainHelper: 'Contoh: 192.168.1.1 atau example.com', domainHelper: 'Contoh: 192.168.1.1 atau example.com',
bindDomain: 'Sematkan Laman Web', bindDomain: 'Sematkan Laman Web',
commandPlaceHolder: 'Kini hanya menyokong perintah pelancaran npx', commandPlaceHolder: 'Kini hanya menyokong perintah pelancaran npx dan binari',
importMcpJson: 'Import Konfigurasi Pelayan MCP', importMcpJson: 'Import Konfigurasi Pelayan MCP',
importMcpJsonError: 'Struktur mcpServers tidak betul', importMcpJsonError: 'Struktur mcpServers tidak betul',
bindDomainHelper: bindDomainHelper:
+1 -1
View File
@@ -2647,7 +2647,7 @@ const message = {
domain: 'Endereço de Acesso Padrão', domain: 'Endereço de Acesso Padrão',
domainHelper: 'Por exemplo: 192.168.1.1 ou example.com', domainHelper: 'Por exemplo: 192.168.1.1 ou example.com',
bindDomain: 'Vincular Site', bindDomain: 'Vincular Site',
commandPlaceHolder: 'Atualmente, apenas comandos de inicialização npx são suportados', commandPlaceHolder: 'Atualmente, apenas comandos de inicialização npx e binários são suportados',
importMcpJson: 'Importar Configuração do Servidor MCP', importMcpJson: 'Importar Configuração do Servidor MCP',
importMcpJsonError: 'A estrutura mcpServers está incorreta', importMcpJsonError: 'A estrutura mcpServers está incorreta',
bindDomainHelper: bindDomainHelper:
+1 -1
View File
@@ -2643,7 +2643,7 @@ const message = {
domain: 'Адрес доступа по умолчанию', domain: 'Адрес доступа по умолчанию',
domainHelper: 'Например: 192.168.1.1 или example.com', domainHelper: 'Например: 192.168.1.1 или example.com',
bindDomain: 'Привязать сайт', bindDomain: 'Привязать сайт',
commandPlaceHolder: 'В настоящее время поддерживаются только команды запуска npx', commandPlaceHolder: 'В настоящее время поддерживаются только команды запуска npx и двоичных файлов',
importMcpJson: 'Импортировать конфигурацию сервера MCP', importMcpJson: 'Импортировать конфигурацию сервера MCP',
importMcpJsonError: 'Структура mcpServers некорректна', importMcpJsonError: 'Структура mcpServers некорректна',
bindDomainHelper: bindDomainHelper:
+1 -1
View File
@@ -2456,7 +2456,7 @@ const message = {
domain: '默認訪問地址', domain: '默認訪問地址',
domainHelper: '例如:192.168.1.1 或者 example.com', domainHelper: '例如:192.168.1.1 或者 example.com',
bindDomain: '綁定網站', bindDomain: '綁定網站',
commandPlaceHolder: '當前僅支持 npx 啟動命令', commandPlaceHolder: '當前僅支持 npx 和 二進制啟動的命令',
importMcpJson: '導入 MCP Server配置', importMcpJson: '導入 MCP Server配置',
importMcpJsonError: 'mcpServers 結構不正確', importMcpJsonError: 'mcpServers 結構不正確',
bindDomainHelper: '綁定網站之後會修改所有已安裝 MCP Server 的訪問地址,並關閉端口的外部訪問', bindDomainHelper: '綁定網站之後會修改所有已安裝 MCP Server 的訪問地址,並關閉端口的外部訪問',
+1 -1
View File
@@ -2458,7 +2458,7 @@ const message = {
domain: '默认访问地址', domain: '默认访问地址',
domainHelper: '例如:192.168.1.1 或者 example.com', domainHelper: '例如:192.168.1.1 或者 example.com',
bindDomain: '绑定网站', bindDomain: '绑定网站',
commandPlaceHolder: '当前仅支持 npx 启动命令', commandPlaceHolder: '当前仅支持 npx 和 二进制启动的命令',
importMcpJson: '导入 MCP Server 配置', importMcpJson: '导入 MCP Server 配置',
importMcpJsonError: 'mcpServers 结构不正确', importMcpJsonError: 'mcpServers 结构不正确',
bindDomainHelper: '绑定网站之后会修改所有已安装 MCP Server 的访问地址,并关闭端口的外部访问', bindDomainHelper: '绑定网站之后会修改所有已安装 MCP Server 的访问地址,并关闭端口的外部访问',
+1 -1
View File
@@ -49,7 +49,7 @@ const GlobalStore = defineStore({
state.themeConfig.theme === 'dark' || state.themeConfig.theme === 'dark' ||
(state.themeConfig.theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches), (state.themeConfig.theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches),
isDarkGoldTheme: (state) => state.themeConfig.primary === '#F0BE96' && state.isProductPro, isDarkGoldTheme: (state) => state.themeConfig.primary === '#F0BE96' && state.isProductPro,
docsUrl: (state) => (state.isIntl ? 'https://docs.1panel.pro' : 'https://1panel.cn/docs'), docsUrl: (state) => (state.isIntl ? 'https://docs.1panel.pro' : 'https://1panel.cn/docs/v1'),
}, },
actions: { actions: {
setOpenMenuTabs(openMenuTabs: boolean) { setOpenMenuTabs(openMenuTabs: boolean) {
@@ -70,9 +70,10 @@ const acceptParams = async (): Promise<void> => {
unUsedList.value = []; unUsedList.value = [];
for (const item of list) { for (const item of list) {
if ( if (
!item.tags || (!item.tags ||
item.tags.length === 0 || item.tags.length === 0 ||
(item.tags.length === 1 && item.tags[0].indexOf('<none>') !== -1 && !item.isUsed) (item.tags.length === 1 && item.tags[0].indexOf('<none>') !== -1)) &&
!item.isUsed
) { ) {
unTagList.value.push(item); unTagList.value.push(item);
} }
+5 -1
View File
@@ -395,6 +395,7 @@ const search = async () => {
if (!currentRecord.value) { if (!currentRecord.value) {
currentRecord.value = records.value[0]; currentRecord.value = records.value[0];
} else { } else {
let oldRecordID = currentRecord.value.id;
let beDelete = true; let beDelete = true;
for (const item of records.value) { for (const item of records.value) {
if (item.id === currentRecord.value.id) { if (item.id === currentRecord.value.id) {
@@ -406,6 +407,9 @@ const search = async () => {
if (beDelete) { if (beDelete) {
currentRecord.value = records.value[0]; currentRecord.value = records.value[0];
} }
if (oldRecordID === currentRecord.value.id && currentRecord.value.status !== 'Waiting') {
return;
}
} }
if (currentRecord.value?.records) { if (currentRecord.value?.records) {
loadRecord(currentRecord.value); loadRecord(currentRecord.value);
@@ -419,7 +423,7 @@ const forDetail = async (row: Cronjob.Record) => {
const loadRecord = async (row: Cronjob.Record) => { const loadRecord = async (row: Cronjob.Record) => {
if (row.records) { if (row.records) {
const res = await getRecordLog(row.id); const res = await getRecordLog(row.id);
let log = res.data.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, ''); let log = res.data.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, '').replace(/\r/g, '');
if (currentRecordDetail.value === log) { if (currentRecordDetail.value === log) {
return; return;
} }
@@ -74,6 +74,8 @@ const changeVisible = ref(false);
type FormInstance = InstanceType<typeof ElForm>; type FormInstance = InstanceType<typeof ElForm>;
const changeFormRef = ref<FormInstance>(); const changeFormRef = ref<FormInstance>();
const title = ref(); const title = ref();
const oldPrivilege = ref();
const oldPrivilegeIPs = ref();
const changeForm = reactive({ const changeForm = reactive({
id: 0, id: 0,
from: '', from: '',
@@ -124,6 +126,8 @@ const acceptParams = (params: DialogProps): void => {
changeForm.privilegeIPs = params.privilegeIPs; changeForm.privilegeIPs = params.privilegeIPs;
changeForm.value = params.value; changeForm.value = params.value;
changeVisible.value = true; changeVisible.value = true;
oldPrivilege.value = params.privilege;
oldPrivilegeIPs.value = params.privilegeIPs;
}; };
const emit = defineEmits<{ (e: 'search'): void }>(); const emit = defineEmits<{ (e: 'search'): void }>();
@@ -167,6 +171,10 @@ const submitChangeInfo = async (formEl: FormInstance | undefined) => {
} }
return; return;
} }
if (changeForm.privilege === oldPrivilege.value && changeForm.privilegeIPs === oldPrivilegeIPs.value) {
changeVisible.value = false;
return;
}
if (changeForm.privilege !== 'ip') { if (changeForm.privilege !== 'ip') {
param.value = changeForm.privilege; param.value = changeForm.privilege;
} else { } else {
@@ -4,9 +4,6 @@
<template #title> <template #title>
<back-button name="MySQL" :header="props.database + ' ' + $t('commons.button.set')"> <back-button name="MySQL" :header="props.database + ' ' + $t('commons.button.set')">
<template #buttons> <template #buttons>
<el-button type="primary" :plain="activeName !== 'conf'" @click="jumpToConf">
{{ $t('database.confChange') }}
</el-button>
<el-button <el-button
type="primary" type="primary"
:disabled="mysqlStatus !== 'Running'" :disabled="mysqlStatus !== 'Running'"
@@ -15,6 +12,9 @@
> >
{{ $t('database.currentStatus') }} {{ $t('database.currentStatus') }}
</el-button> </el-button>
<el-button type="primary" :plain="activeName !== 'conf'" @click="jumpToConf">
{{ $t('database.confChange') }}
</el-button>
<el-button <el-button
type="primary" type="primary"
:disabled="mysqlStatus !== 'Running'" :disabled="mysqlStatus !== 'Running'"
@@ -159,7 +159,7 @@ const globalStore = GlobalStore();
const loading = ref(false); const loading = ref(false);
const extensions = [javascript(), oneDark]; const extensions = [javascript(), oneDark];
const activeName = ref('conf'); const activeName = ref('status');
const baseInfo = reactive({ const baseInfo = reactive({
name: '', name: '',
@@ -2,9 +2,6 @@
<div v-show="settingShow" v-loading="loading"> <div v-show="settingShow" v-loading="loading">
<LayoutContent :title="database + ' ' + $t('commons.button.set')" :reload="true"> <LayoutContent :title="database + ' ' + $t('commons.button.set')" :reload="true">
<template #buttons> <template #buttons>
<el-button type="primary" :plain="activeName !== 'conf'" @click="changeTab('conf')">
{{ $t('database.confChange') }}
</el-button>
<el-button <el-button
type="primary" type="primary"
:disabled="redisStatus !== 'Running'" :disabled="redisStatus !== 'Running'"
@@ -13,6 +10,9 @@
> >
{{ $t('database.currentStatus') }} {{ $t('database.currentStatus') }}
</el-button> </el-button>
<el-button type="primary" :plain="activeName !== 'conf'" @click="changeTab('conf')">
{{ $t('database.confChange') }}
</el-button>
<el-button <el-button
type="primary" type="primary"
:disabled="redisStatus !== 'Running'" :disabled="redisStatus !== 'Running'"
@@ -170,7 +170,7 @@ const rules = reactive({
maxmemory: [Rules.number, checkNumberRange(0, 999999)], maxmemory: [Rules.number, checkNumberRange(0, 999999)],
}); });
const activeName = ref('conf'); const activeName = ref('status');
const statusRef = ref(); const statusRef = ref();
const persistenceRef = ref(); const persistenceRef = ref();
@@ -217,7 +217,7 @@ const acceptParams = (prop: DialogProps): void => {
redisStatus.value = prop.status; redisStatus.value = prop.status;
database.value = prop.database; database.value = prop.database;
settingShow.value = true; settingShow.value = true;
loadConfFile(); changeTab('status');
}; };
const portRef = ref(); const portRef = ref();
@@ -328,6 +328,7 @@ const handleClose = () => {
saveContent(); saveContent();
}) })
.finally(() => { .finally(() => {
isEdit.value = false;
closeEditor(); closeEditor();
}); });
} else { } else {
@@ -72,6 +72,7 @@
</div> </div>
<el-form-item prop="name" class="no-border"> <el-form-item prop="name" class="no-border">
<el-input <el-input
name="username"
v-model.trim="loginForm.name" v-model.trim="loginForm.name"
:placeholder="$t('commons.login.username')" :placeholder="$t('commons.login.username')"
class="form-input" class="form-input"
@@ -85,6 +86,7 @@
</el-form-item> </el-form-item>
<el-form-item prop="password" class="no-border"> <el-form-item prop="password" class="no-border">
<el-input <el-input
name="password"
type="password" type="password"
clearable clearable
v-model.trim="loginForm.password" v-model.trim="loginForm.password"