mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-16 18:54:43 +08:00
feat(appstore): Add Synchronization of Main Node Application Store Pa… (#7612)
This commit is contained in:
parent
68698217ee
commit
b1fbdcc566
@ -251,22 +251,22 @@ func (t *Task) Logf(format string, v ...any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) LogFailed(msg string) {
|
func (t *Task) LogFailed(msg string) {
|
||||||
t.Logger.Printf(msg + i18n.GetMsgByKey("Failed"))
|
t.Logger.Println(msg + i18n.GetMsgByKey("Failed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) LogFailedWithErr(msg string, err error) {
|
func (t *Task) LogFailedWithErr(msg string, err error) {
|
||||||
t.Logger.Printf(fmt.Sprintf("%s %s : %s", msg, i18n.GetMsgByKey("Failed"), err.Error()))
|
t.Logger.Println(fmt.Sprintf("%s %s : %s", msg, i18n.GetMsgByKey("Failed"), err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) LogSuccess(msg string) {
|
func (t *Task) LogSuccess(msg string) {
|
||||||
t.Logger.Printf(msg + i18n.GetMsgByKey("Success"))
|
t.Logger.Println(msg + i18n.GetMsgByKey("Success"))
|
||||||
}
|
}
|
||||||
func (t *Task) LogSuccessF(format string, v ...any) {
|
func (t *Task) LogSuccessF(format string, v ...any) {
|
||||||
t.Logger.Printf(fmt.Sprintf(format, v...) + i18n.GetMsgByKey("Success"))
|
t.Logger.Println(fmt.Sprintf(format, v...) + i18n.GetMsgByKey("Success"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) LogStart(msg string) {
|
func (t *Task) LogStart(msg string) {
|
||||||
t.Logger.Printf(fmt.Sprintf("%s%s", i18n.GetMsgByKey("Start"), msg))
|
t.Logger.Println(fmt.Sprintf("%s%s", i18n.GetMsgByKey("Start"), msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) LogWithOps(operate, msg string) {
|
func (t *Task) LogWithOps(operate, msg string) {
|
||||||
|
@ -65,3 +65,14 @@ func WithMap(Key string, maps map[string]interface{}, err error) BusinessError {
|
|||||||
Err: err,
|
Err: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithName(Key string, name string) BusinessError {
|
||||||
|
paramMap := map[string]interface{}{}
|
||||||
|
if name != "" {
|
||||||
|
paramMap["name"] = name
|
||||||
|
}
|
||||||
|
return BusinessError{
|
||||||
|
Msg: Key,
|
||||||
|
Map: paramMap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -161,3 +161,11 @@ func DownloadFileWithProxy(url, dst string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Stat(path string) bool {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err != nil && os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
@ -268,4 +268,9 @@ export namespace App {
|
|||||||
export interface AppStoreConfig {
|
export interface AppStoreConfig {
|
||||||
defaultDomain: string;
|
defaultDomain: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CustomAppStoreConfig {
|
||||||
|
status: string;
|
||||||
|
imagePrefix: string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,3 +122,7 @@ export const UpdateAppStoreConfig = (req: App.AppStoreConfig) => {
|
|||||||
export const SyncCutomAppStore = (req: App.AppStoreSync) => {
|
export const SyncCutomAppStore = (req: App.AppStoreSync) => {
|
||||||
return http.post(`/custom/app/sync`, req);
|
return http.post(`/custom/app/sync`, req);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getCurrentNodeCustomAppConfig = () => {
|
||||||
|
return http.get<App.CustomAppStoreConfig>(`/custom/app/config`);
|
||||||
|
};
|
||||||
|
@ -114,6 +114,8 @@ import { Backup } from '@/api/interface/backup';
|
|||||||
import router from '@/routers';
|
import router from '@/routers';
|
||||||
import { MsgSuccess } from '@/utils/message';
|
import { MsgSuccess } from '@/utils/message';
|
||||||
import TaskLog from '@/components/task-log/index.vue';
|
import TaskLog from '@/components/task-log/index.vue';
|
||||||
|
import { GlobalStore } from '@/store';
|
||||||
|
const globalStore = GlobalStore();
|
||||||
|
|
||||||
const selects = ref<any>([]);
|
const selects = ref<any>([]);
|
||||||
const loading = ref();
|
const loading = ref();
|
||||||
@ -306,7 +308,7 @@ const onDownload = async (row: Backup.RecordInfo) => {
|
|||||||
fileName: row.fileName,
|
fileName: row.fileName,
|
||||||
};
|
};
|
||||||
await downloadBackupRecord(params).then(async (res) => {
|
await downloadBackupRecord(params).then(async (res) => {
|
||||||
downloadFile(res.data);
|
downloadFile(res.data, globalStore.currentNode);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, useSlots } from 'vue';
|
import { computed, useSlots } from 'vue';
|
||||||
defineOptions({ name: 'DrawerPro' });
|
defineOptions({ name: 'DialogPro' });
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
title: String,
|
title: String,
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
import { nextTick, onMounted, onUnmounted, reactive, ref } from 'vue';
|
import { nextTick, onMounted, onUnmounted, reactive, ref } from 'vue';
|
||||||
import { downloadFile } from '@/utils/util';
|
import { downloadFile } from '@/utils/util';
|
||||||
import { ReadByLine } from '@/api/modules/files';
|
import { ReadByLine } from '@/api/modules/files';
|
||||||
|
import { GlobalStore } from '@/store';
|
||||||
|
const globalStore = GlobalStore();
|
||||||
|
|
||||||
interface LogProps {
|
interface LogProps {
|
||||||
id?: number;
|
id?: number;
|
||||||
@ -146,7 +148,7 @@ const changeLoading = () => {
|
|||||||
|
|
||||||
const onDownload = async () => {
|
const onDownload = async () => {
|
||||||
changeLoading();
|
changeLoading();
|
||||||
downloadFile(logPath.value);
|
downloadFile(logPath.value, globalStore.currentNode);
|
||||||
changeLoading();
|
changeLoading();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1859,6 +1859,7 @@ const message = {
|
|||||||
defaultWebDomainHepler: '默认访问用于应用端口跳转,例如应用端口为 8080 则跳转地址为http(s)://默认访问地址:8080',
|
defaultWebDomainHepler: '默认访问用于应用端口跳转,例如应用端口为 8080 则跳转地址为http(s)://默认访问地址:8080',
|
||||||
webUIConfig: '请在应用参数或者应用商店设置处添加访问地址',
|
webUIConfig: '请在应用参数或者应用商店设置处添加访问地址',
|
||||||
toLink: '跳转',
|
toLink: '跳转',
|
||||||
|
customAppHelper: '当前使用的是主节点应用商店包,修改配置请在主节点操作',
|
||||||
},
|
},
|
||||||
website: {
|
website: {
|
||||||
website: '网站',
|
website: '网站',
|
||||||
|
@ -51,6 +51,7 @@ const GlobalStore = defineStore({
|
|||||||
state.themeConfig.isGold ||
|
state.themeConfig.isGold ||
|
||||||
(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.isGold && state.isMasterProductPro,
|
isDarkGoldTheme: (state) => state.themeConfig.isGold && state.isMasterProductPro,
|
||||||
|
isMaster: (state) => state.currentNode === 'local',
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
setOpenMenuTabs(openMenuTabs: boolean) {
|
setOpenMenuTabs(openMenuTabs: boolean) {
|
||||||
|
@ -519,10 +519,33 @@ export function toLowerCase(str: string) {
|
|||||||
return str.toLowerCase();
|
return str.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function downloadFile(filePath: string) {
|
export function downloadFile(filePath: string, currentNode: string) {
|
||||||
let url = `${import.meta.env.VITE_API_URL as string}/files/download?`;
|
const url = `${import.meta.env.VITE_API_URL as string}/files/download`;
|
||||||
let path = encodeURIComponent(filePath);
|
const path = encodeURIComponent(filePath);
|
||||||
window.open(url + 'path=' + path, '_blank');
|
|
||||||
|
fetch(`${url}?path=${path}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
CurrentNode: currentNode,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Network response was not ok');
|
||||||
|
}
|
||||||
|
return response.blob();
|
||||||
|
})
|
||||||
|
.then((blob) => {
|
||||||
|
const downloadUrl = window.URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = downloadUrl;
|
||||||
|
a.download = filePath.split('/').pop() || 'downloaded-file';
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
a.remove();
|
||||||
|
window.URL.revokeObjectURL(downloadUrl);
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function downloadWithContent(content: string, fileName: string) {
|
export function downloadWithContent(content: string, fileName: string) {
|
||||||
|
@ -175,7 +175,14 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { App } from '@/api/interface/app';
|
import { App } from '@/api/interface/app';
|
||||||
import { onMounted, reactive, ref, computed } from 'vue';
|
import { onMounted, reactive, ref, computed } from 'vue';
|
||||||
import { GetAppTags, SearchApp, SyncApp, SyncCutomAppStore, SyncLocalApp } from '@/api/modules/app';
|
import {
|
||||||
|
GetAppTags,
|
||||||
|
SearchApp,
|
||||||
|
SyncApp,
|
||||||
|
SyncCutomAppStore,
|
||||||
|
SyncLocalApp,
|
||||||
|
getCurrentNodeCustomAppConfig,
|
||||||
|
} from '@/api/modules/app';
|
||||||
import Install from '../detail/install/index.vue';
|
import Install from '../detail/install/index.vue';
|
||||||
import router from '@/routers';
|
import router from '@/routers';
|
||||||
import { MsgSuccess } from '@/utils/message';
|
import { MsgSuccess } from '@/utils/message';
|
||||||
@ -184,7 +191,6 @@ import { getLanguage, newUUID } from '@/utils/util';
|
|||||||
import Detail from '../detail/index.vue';
|
import Detail from '../detail/index.vue';
|
||||||
import TaskLog from '@/components/task-log/index.vue';
|
import TaskLog from '@/components/task-log/index.vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { GetCustomAppStoreConfig } from '@/xpack/api/modules/app';
|
|
||||||
|
|
||||||
const globalStore = GlobalStore();
|
const globalStore = GlobalStore();
|
||||||
const { isProductPro } = storeToRefs(globalStore);
|
const { isProductPro } = storeToRefs(globalStore);
|
||||||
@ -350,7 +356,7 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
search(req);
|
search(req);
|
||||||
if (isProductPro.value) {
|
if (isProductPro.value) {
|
||||||
const res = await GetCustomAppStoreConfig();
|
const res = await getCurrentNodeCustomAppConfig();
|
||||||
if (res && res.data) {
|
if (res && res.data) {
|
||||||
syncCustomAppstore.value = res.data.status === 'enable';
|
syncCustomAppstore.value = res.data.status === 'enable';
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,10 @@
|
|||||||
</el-input>
|
</el-input>
|
||||||
<span class="input-help">{{ $t('app.defaultWebDomainHepler') }}</span>
|
<span class="input-help">{{ $t('app.defaultWebDomainHepler') }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<CustomSetting v-if="isProductPro" />
|
<CustomSetting v-if="isProductPro && globalStore.isMaster" />
|
||||||
|
<el-form-item v-if="!globalStore.isMaster && useCustomApp">
|
||||||
|
<el-text type="warning">{{ $t('app.customAppHelper') }}</el-text>
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
@ -38,7 +41,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { GetAppStoreConfig } from '@/api/modules/app';
|
import { GetAppStoreConfig, getCurrentNodeCustomAppConfig } from '@/api/modules/app';
|
||||||
import { Rules } from '@/global/form-rules';
|
import { Rules } from '@/global/form-rules';
|
||||||
import { FormRules } from 'element-plus';
|
import { FormRules } from 'element-plus';
|
||||||
import CustomSetting from '@/xpack/views/appstore/index.vue';
|
import CustomSetting from '@/xpack/views/appstore/index.vue';
|
||||||
@ -59,6 +62,7 @@ const loading = ref(false);
|
|||||||
const configForm = ref();
|
const configForm = ref();
|
||||||
const protocol = ref('http://');
|
const protocol = ref('http://');
|
||||||
const domainRef = ref();
|
const domainRef = ref();
|
||||||
|
const useCustomApp = ref(false);
|
||||||
|
|
||||||
function getUrl(url: string) {
|
function getUrl(url: string) {
|
||||||
const regex = /^(https?:\/\/)(.*)/;
|
const regex = /^(https?:\/\/)(.*)/;
|
||||||
@ -99,7 +103,18 @@ const setDefaultDomain = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getNodeConfig = async () => {
|
||||||
|
if (globalStore.isMaster) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const res = await getCurrentNodeCustomAppConfig();
|
||||||
|
if (res && res.data) {
|
||||||
|
useCustomApp.value = res.data.status === 'enable';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
search();
|
search();
|
||||||
|
getNodeConfig();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -54,6 +54,8 @@ import i18n from '@/lang';
|
|||||||
import { downloadBackupRecord, searchBackupRecordsByCronjob } from '@/api/modules/backup';
|
import { downloadBackupRecord, searchBackupRecordsByCronjob } from '@/api/modules/backup';
|
||||||
import { Backup } from '@/api/interface/backup';
|
import { Backup } from '@/api/interface/backup';
|
||||||
import { MsgError } from '@/utils/message';
|
import { MsgError } from '@/utils/message';
|
||||||
|
import { GlobalStore } from '@/store';
|
||||||
|
const globalStore = GlobalStore();
|
||||||
|
|
||||||
const selects = ref<any>([]);
|
const selects = ref<any>([]);
|
||||||
const loading = ref();
|
const loading = ref();
|
||||||
@ -116,7 +118,7 @@ const onDownload = async (row: Backup.RecordInfo) => {
|
|||||||
await downloadBackupRecord(params)
|
await downloadBackupRecord(params)
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
downloadFile(res.data);
|
downloadFile(res.data, globalStore.currentNode);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
@ -311,7 +311,7 @@ import {
|
|||||||
RemoveFavorite,
|
RemoveFavorite,
|
||||||
SearchFavorite,
|
SearchFavorite,
|
||||||
} from '@/api/modules/files';
|
} from '@/api/modules/files';
|
||||||
import { computeSize, copyText, dateFormat, downloadFile, getFileType, getIcon, getRandomStr } from '@/utils/util';
|
import { computeSize, copyText, dateFormat, getFileType, getIcon, getRandomStr, downloadFile } from '@/utils/util';
|
||||||
import { StarFilled, Star, Top, Right, Close } from '@element-plus/icons-vue';
|
import { StarFilled, Star, Top, Right, Close } from '@element-plus/icons-vue';
|
||||||
import { File } from '@/api/interface/file';
|
import { File } from '@/api/interface/file';
|
||||||
import { Mimetypes, Languages } from '@/global/mimetype';
|
import { Mimetypes, Languages } from '@/global/mimetype';
|
||||||
@ -810,7 +810,7 @@ const openPaste = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const openDownload = (file: File.File) => {
|
const openDownload = (file: File.File) => {
|
||||||
downloadFile(file.path);
|
downloadFile(file.path, globalStore.currentNode);
|
||||||
};
|
};
|
||||||
|
|
||||||
const openDetail = (row: File.File) => {
|
const openDetail = (row: File.File) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user