mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-19 22:09:03 +08:00
feat: Optimize the structure of installed apps in the App Store
This commit is contained in:
parent
15bc6cf884
commit
b965b1357b
9 changed files with 439 additions and 395 deletions
|
|
@ -626,10 +626,10 @@ func (w WebsiteService) GetWebsite(id uint) (response.WebsiteDTO, error) {
|
||||||
dName := d.GetName()
|
dName := d.GetName()
|
||||||
if _, ok := dto.LBAlgorithms[dName]; ok {
|
if _, ok := dto.LBAlgorithms[dName]; ok {
|
||||||
res.Algorithm = dName
|
res.Algorithm = dName
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res.Servers = getNginxUpstreamServers(up.UpstreamServers)
|
res.Servers = getNginxUpstreamServers(up.UpstreamServers)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,9 @@ export namespace App {
|
||||||
webUI: string;
|
webUI: string;
|
||||||
appKey?: string;
|
appKey?: string;
|
||||||
serviceName: string;
|
serviceName: string;
|
||||||
|
appStatus?: string;
|
||||||
|
appType?: string;
|
||||||
|
version?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppInstalledInfo {
|
export interface AppInstalledInfo {
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ export interface SearchWithPage {
|
||||||
}
|
}
|
||||||
export interface CommonModel {
|
export interface CommonModel {
|
||||||
id: number;
|
id: number;
|
||||||
CreatedAt?: string;
|
createdAt?: string;
|
||||||
UpdatedAt?: string;
|
updatedAt?: string;
|
||||||
}
|
}
|
||||||
export interface DescriptionUpdate {
|
export interface DescriptionUpdate {
|
||||||
id: number;
|
id: number;
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,6 @@ const getApp = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await getAppByKey(appKey.value);
|
const res = await getAppByKey(appKey.value);
|
||||||
app.value = res.data;
|
app.value = res.data;
|
||||||
app.value.icon = 'data:image/png;base64,' + res.data.icon;
|
|
||||||
version.value = app.value.versions[0];
|
version.value = app.value.versions[0];
|
||||||
getDetail(app.value.id, version.value);
|
getDetail(app.value.id, version.value);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
78
frontend/src/views/app-store/installed/app/card.vue
Normal file
78
frontend/src/views/app-store/installed/app/card.vue
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
<template>
|
||||||
|
<div class="install-card">
|
||||||
|
<el-card class="e-card">
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :xs="3" :sm="3" :md="3" :lg="4" :xl="3">
|
||||||
|
<AppIcon
|
||||||
|
@open-detail="$emit('openDetail')"
|
||||||
|
:appID="installed.appID"
|
||||||
|
:currentNode="currentNode"
|
||||||
|
></AppIcon>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="21" :sm="21" :md="21" :lg="20" :xl="21">
|
||||||
|
<div class="a-detail">
|
||||||
|
<AppHeader
|
||||||
|
:installed="installed"
|
||||||
|
:mode="mode"
|
||||||
|
:defaultLink="defaultLink"
|
||||||
|
@open-backups="$emit('openBackups')"
|
||||||
|
@open-log="$emit('openLog')"
|
||||||
|
@open-terminal="$emit('openTerminal')"
|
||||||
|
@open-operate="$emit('openOperate')"
|
||||||
|
@favorite-install="$emit('favoriteInstall')"
|
||||||
|
@to-folder="$emit('toFolder')"
|
||||||
|
@open-uploads="$emit('openUploads')"
|
||||||
|
@ignore-app="$emit('ignoreApp')"
|
||||||
|
@to-container="$emit('toContainer')"
|
||||||
|
></AppHeader>
|
||||||
|
<AppInfo
|
||||||
|
:installed="installed"
|
||||||
|
:defaultLink="defaultLink"
|
||||||
|
@open-link="$emit('openLink')"
|
||||||
|
@to-link="$emit('toLink')"
|
||||||
|
@jump-to-path="$emit('jumpToPath', '/settings/panel')"
|
||||||
|
></AppInfo>
|
||||||
|
<div class="app-divider" />
|
||||||
|
<slot name="buttons"></slot>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import AppIcon from '@/views/app-store/installed/app/icon.vue';
|
||||||
|
import AppHeader from '@/views/app-store/installed/app/header.vue';
|
||||||
|
import AppInfo from '@/views/app-store/installed/app/info.vue';
|
||||||
|
|
||||||
|
import { App } from '@/api/interface/app';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
installed: App.AppInstalled;
|
||||||
|
mode: string;
|
||||||
|
defaultLink: string;
|
||||||
|
currentNode: string;
|
||||||
|
}
|
||||||
|
defineProps<Props>();
|
||||||
|
|
||||||
|
defineEmits([
|
||||||
|
'toFolder',
|
||||||
|
'openUploads',
|
||||||
|
'openDetail',
|
||||||
|
'openBackups',
|
||||||
|
'openLog',
|
||||||
|
'openTerminal',
|
||||||
|
'openOperate',
|
||||||
|
'favoriteInstall',
|
||||||
|
'openLink',
|
||||||
|
'toLink',
|
||||||
|
'jumpToPath',
|
||||||
|
'ignoreApp',
|
||||||
|
'toContainer',
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use '@/views/app-store/index.scss';
|
||||||
|
</style>
|
||||||
193
frontend/src/views/app-store/installed/app/header.vue
Normal file
193
frontend/src/views/app-store/installed/app/header.vue
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
<template>
|
||||||
|
<div class="d-name">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="min-w-50 flex items-center justify-start gap-1">
|
||||||
|
<el-button link type="info">
|
||||||
|
<el-tooltip :content="installed.name" placement="top">
|
||||||
|
<span class="name">{{ installed.name }}</span>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-button>
|
||||||
|
<span class="status">
|
||||||
|
<Status :key="installed.status" :status="installed.status"></Status>
|
||||||
|
</span>
|
||||||
|
<span class="msg">
|
||||||
|
<el-popover
|
||||||
|
v-if="isAppErr(installed)"
|
||||||
|
placement="bottom"
|
||||||
|
:width="400"
|
||||||
|
trigger="hover"
|
||||||
|
:content="installed.message"
|
||||||
|
:popper-options="options"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<el-button link type="danger">
|
||||||
|
<el-icon><Warning /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
<div class="app-error">
|
||||||
|
{{ installed.message }}
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
</span>
|
||||||
|
<span class="ml-1">
|
||||||
|
<el-tooltip effect="dark" :content="$t('app.toFolder')" placement="top">
|
||||||
|
<el-button type="primary" link @click="$emit('toFolder')" icon="FolderOpened"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
|
<span class="ml-1">
|
||||||
|
<el-tooltip
|
||||||
|
v-if="mode !== 'upgrade'"
|
||||||
|
effect="dark"
|
||||||
|
:content="$t('commons.button.log')"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
link
|
||||||
|
@click="$emit('openLog')"
|
||||||
|
:disabled="installed.status === 'DownloadErr'"
|
||||||
|
>
|
||||||
|
<el-icon><Tickets /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
|
<span class="ml-1">
|
||||||
|
<el-tooltip v-if="mode !== 'upgrade'" effect="dark" :content="$t('menu.terminal')" placement="top">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
link
|
||||||
|
@click="$emit('openTerminal')"
|
||||||
|
:disabled="installed.status !== 'Running'"
|
||||||
|
>
|
||||||
|
<el-icon>
|
||||||
|
<SvgIcon iconName="p-terminal2" />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
|
<span class="ml-1">
|
||||||
|
<el-tooltip v-if="mode !== 'upgrade'" effect="dark" :content="$t('menu.container')" placement="top">
|
||||||
|
<el-button type="primary" link @click="$emit('toContainer')">
|
||||||
|
<el-icon>
|
||||||
|
<SvgIcon iconName="p-docker" />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
|
<span class="ml-1" v-if="mode === 'installed'">
|
||||||
|
<el-tooltip
|
||||||
|
effect="dark"
|
||||||
|
:content="$t('website.cancelFavorite')"
|
||||||
|
placement="top-start"
|
||||||
|
v-if="installed.favorite"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
size="large"
|
||||||
|
icon="StarFilled"
|
||||||
|
type="warning"
|
||||||
|
@click="$emit('favoriteInstall')"
|
||||||
|
></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip effect="dark" :content="$t('website.favorite')" placement="top-start" v-else>
|
||||||
|
<el-button link icon="Star" type="info" @click="$emit('favoriteInstall')"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-wrap items-center justify-end gap-1">
|
||||||
|
<el-button
|
||||||
|
class="h-button"
|
||||||
|
plain
|
||||||
|
round
|
||||||
|
size="small"
|
||||||
|
@click="$emit('openUploads')"
|
||||||
|
v-if="mode === 'installed'"
|
||||||
|
>
|
||||||
|
{{ $t('database.loadBackup') }}
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
class="h-button"
|
||||||
|
plain
|
||||||
|
round
|
||||||
|
size="small"
|
||||||
|
@click="$emit('openBackups')"
|
||||||
|
v-if="mode === 'installed'"
|
||||||
|
>
|
||||||
|
{{ $t('commons.button.backup') }}
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
class="h-button"
|
||||||
|
plain
|
||||||
|
round
|
||||||
|
size="small"
|
||||||
|
:disabled="installed.status === 'Upgrading'"
|
||||||
|
@click="$emit('ignoreApp')"
|
||||||
|
v-if="mode === 'upgrade'"
|
||||||
|
>
|
||||||
|
{{ $t('commons.button.ignore') }}
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
class="h-button"
|
||||||
|
plain
|
||||||
|
round
|
||||||
|
size="small"
|
||||||
|
:disabled="
|
||||||
|
(installed.status !== 'Running' && installed.status !== 'UpgradeErr') ||
|
||||||
|
installed.appStatus === 'TakeDown'
|
||||||
|
"
|
||||||
|
@click="$emit('openOperate')"
|
||||||
|
v-if="mode === 'upgrade'"
|
||||||
|
>
|
||||||
|
{{ $t('commons.button.upgrade') }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { App } from '@/api/interface/app';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
installed: App.AppInstalled;
|
||||||
|
mode: string;
|
||||||
|
}
|
||||||
|
defineProps<Props>();
|
||||||
|
|
||||||
|
defineEmits([
|
||||||
|
'toFolder',
|
||||||
|
'openLog',
|
||||||
|
'openTerminal',
|
||||||
|
'toContainer',
|
||||||
|
'openBackups',
|
||||||
|
'openOperate',
|
||||||
|
'ignoreApp',
|
||||||
|
'openUploads',
|
||||||
|
'favoriteInstall',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
modifiers: [
|
||||||
|
{
|
||||||
|
name: 'flip',
|
||||||
|
options: {
|
||||||
|
padding: 5,
|
||||||
|
fallbackPlacements: ['bottom-start', 'top-start', 'right', 'left'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const isAppErr = (row: any) => {
|
||||||
|
return row.status.includes('Err') || row.status.includes('Error') || row.status.includes('UnHealthy');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use '@/views/app-store/index.scss';
|
||||||
|
|
||||||
|
.svg-icon {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
17
frontend/src/views/app-store/installed/app/icon.vue
Normal file
17
frontend/src/views/app-store/installed/app/icon.vue
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<template>
|
||||||
|
<div class="icon">
|
||||||
|
<el-avatar @click="$emit('openDetail')" shape="square" :size="77" :src="getAppIconUrl(appID, currentNode)" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { getAppIconUrl } from '@/api/modules/app';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
currentNode: string;
|
||||||
|
appID: number;
|
||||||
|
}
|
||||||
|
defineProps<Props>();
|
||||||
|
|
||||||
|
defineEmits(['openDetail']);
|
||||||
|
</script>
|
||||||
98
frontend/src/views/app-store/installed/app/info.vue
Normal file
98
frontend/src/views/app-store/installed/app/info.vue
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="d-description flex flex-wrap items-center justify-start gap-1.5">
|
||||||
|
<el-button class="mr-1" plain size="small">
|
||||||
|
{{ $t('app.version') }}{{ $t('commons.colon') }}{{ installed.version }}
|
||||||
|
</el-button>
|
||||||
|
<el-button v-if="installed.httpPort > 0" class="mr-1" plain size="small">
|
||||||
|
{{ $t('commons.table.port') }}{{ $t('commons.colon') }}{{ installed.httpPort }}
|
||||||
|
</el-button>
|
||||||
|
<el-button v-if="installed.httpsPort > 0" plain size="small">
|
||||||
|
{{ $t('commons.table.port') }}:{{ installed.httpsPort }}
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
<el-popover placement="top-start" trigger="hover" v-if="hasLinkButton(installed)" :width="400">
|
||||||
|
<template #reference>
|
||||||
|
<el-button plain icon="Promotion" size="small" @click="$emit('openLink')">
|
||||||
|
{{ $t('app.toLink') }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr v-if="defaultLink != ''">
|
||||||
|
<td v-if="installed.httpPort > 0">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
link
|
||||||
|
@click="$emit('toLink', 'http://' + defaultLink + ':' + installed.httpPort)"
|
||||||
|
>
|
||||||
|
{{ 'http://' + defaultLink + ':' + installed.httpPort }}
|
||||||
|
</el-button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="defaultLink != ''">
|
||||||
|
<td v-if="installed.httpsPort > 0">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
link
|
||||||
|
@click="$emit('toLink', 'https://' + defaultLink + ':' + installed.httpsPort)"
|
||||||
|
>
|
||||||
|
{{ 'https://' + defaultLink + ':' + installed.httpsPort }}
|
||||||
|
</el-button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="installed.webUI != ''">
|
||||||
|
<td>
|
||||||
|
<el-button type="primary" link @click="$emit('toLink')">
|
||||||
|
{{ installed.webUI }}
|
||||||
|
</el-button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<span v-if="defaultLink == '' && installed.webUI == ''">
|
||||||
|
{{ $t('app.webUIConfig') }}
|
||||||
|
<el-link icon="Position" @click="$emit('jumpToPath')" type="primary">
|
||||||
|
{{ $t('firewall.quickJump') }}
|
||||||
|
</el-link>
|
||||||
|
</span>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
<div class="description">
|
||||||
|
<span>
|
||||||
|
{{ $t('app.alreadyRun') }}{{ $t('commons.colon') }}
|
||||||
|
{{ getAge(installed.createdAt) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { App } from '@/api/interface/app';
|
||||||
|
import { getAge } from '@/utils/util';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
installed: App.AppInstalled;
|
||||||
|
defaultLink: string;
|
||||||
|
}
|
||||||
|
defineProps<Props>();
|
||||||
|
|
||||||
|
defineEmits(['openLink', 'toLink', 'jumpToPath']);
|
||||||
|
|
||||||
|
const hasLinkButton = (installed: any) => {
|
||||||
|
return (
|
||||||
|
(installed.appType == 'website' || installed.appKey?.startsWith('local')) &&
|
||||||
|
(installed.httpPort > 0 || installed.httpsPort > 0 || installed.webUI != '')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use '@/views/app-store/index.scss';
|
||||||
|
|
||||||
|
.d-description {
|
||||||
|
.el-button + .el-button {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -29,7 +29,6 @@
|
||||||
>
|
>
|
||||||
{{ $t('firewall.quickJump') }}
|
{{ $t('firewall.quickJump') }}
|
||||||
</el-link>
|
</el-link>
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-alert>
|
</el-alert>
|
||||||
|
|
@ -49,343 +48,46 @@
|
||||||
:lg="12"
|
:lg="12"
|
||||||
:xl="12"
|
:xl="12"
|
||||||
>
|
>
|
||||||
<div class="install-card">
|
<AppCard
|
||||||
<el-card class="e-card">
|
:installed="installed"
|
||||||
<el-row :gutter="10">
|
:mode="mode"
|
||||||
<el-col :xs="3" :sm="3" :md="3" :lg="4" :xl="4">
|
:defaultLink="defaultLink"
|
||||||
<div class="icon">
|
:currentNode="currentNode"
|
||||||
<el-avatar
|
@open-detail="openDetail(installed.appKey)"
|
||||||
@click="openDetail(installed.appKey)"
|
@open-backups="openBackups(installed)"
|
||||||
shape="square"
|
@open-log="openLog(installed)"
|
||||||
:size="66"
|
@open-terminal="openTerminal(installed)"
|
||||||
:src="getAppIconUrl(installed.appID, currentNode)"
|
@open-operate="openOperate(installed, 'upgrade')"
|
||||||
/>
|
@favorite-install="favoriteInstall(installed)"
|
||||||
</div>
|
@to-folder="routerToFileWithPath(installed.path)"
|
||||||
</el-col>
|
@open-uploads="openUploads(installed.appKey, installed.name)"
|
||||||
<el-col :xs="24" :sm="21" :md="21" :lg="20" :xl="20">
|
@open-link="openLink(defaultLink, installed)"
|
||||||
<div class="a-detail">
|
@to-link="toLink(installed.webUI)"
|
||||||
<div class="d-name">
|
@jump-to-path="jumpToPath(router, '/settings/panel')"
|
||||||
<div class="flex items-center justify-between">
|
@to-container="toContainer(installed)"
|
||||||
<div class="min-w-50 flex items-center justify-start gap-1">
|
@ignore-app="ignoreApp(installed)"
|
||||||
<el-button link type="info">
|
>
|
||||||
<el-tooltip :content="installed.name" placement="top">
|
<template #buttons>
|
||||||
<span class="name">{{ installed.name }}</span>
|
<div
|
||||||
</el-tooltip>
|
class="d-button flex flex-wrap items-center justify-start gap-1.5"
|
||||||
</el-button>
|
v-if="mode === 'installed' && installed.status != 'Installing'"
|
||||||
<span class="status">
|
>
|
||||||
<Status
|
<el-button
|
||||||
:key="installed.status"
|
class="app-button"
|
||||||
:status="installed.status"
|
v-for="(button, key) in buttons"
|
||||||
></Status>
|
:key="key"
|
||||||
</span>
|
:type="button.disabled && button.disabled(installed) ? 'info' : ''"
|
||||||
<span class="msg">
|
plain
|
||||||
<el-popover
|
round
|
||||||
v-if="isAppErr(installed)"
|
size="small"
|
||||||
placement="bottom"
|
@click="button.click(installed)"
|
||||||
:width="400"
|
:disabled="button.disabled && button.disabled(installed)"
|
||||||
trigger="hover"
|
>
|
||||||
:content="installed.message"
|
{{ button.label }}
|
||||||
:popper-options="options"
|
</el-button>
|
||||||
>
|
</div>
|
||||||
<template #reference>
|
</template>
|
||||||
<el-button link type="danger">
|
</AppCard>
|
||||||
<el-icon><Warning /></el-icon>
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
<div class="app-error">
|
|
||||||
{{ installed.message }}
|
|
||||||
</div>
|
|
||||||
</el-popover>
|
|
||||||
</span>
|
|
||||||
<span class="ml-1">
|
|
||||||
<el-tooltip
|
|
||||||
effect="dark"
|
|
||||||
:content="$t('app.toFolder')"
|
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
link
|
|
||||||
@click="routerToFileWithPath(installed.path)"
|
|
||||||
icon="FolderOpened"
|
|
||||||
></el-button>
|
|
||||||
</el-tooltip>
|
|
||||||
</span>
|
|
||||||
<span class="ml-1">
|
|
||||||
<el-tooltip
|
|
||||||
v-if="mode !== 'upgrade'"
|
|
||||||
effect="dark"
|
|
||||||
:content="$t('commons.button.log')"
|
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
link
|
|
||||||
@click="openLog(installed)"
|
|
||||||
:disabled="installed.status === 'DownloadErr'"
|
|
||||||
>
|
|
||||||
<el-icon><Tickets /></el-icon>
|
|
||||||
</el-button>
|
|
||||||
</el-tooltip>
|
|
||||||
</span>
|
|
||||||
<span class="ml-1">
|
|
||||||
<el-tooltip
|
|
||||||
v-if="mode !== 'upgrade'"
|
|
||||||
effect="dark"
|
|
||||||
:content="$t('menu.terminal')"
|
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
link
|
|
||||||
@click="openTerminal(installed)"
|
|
||||||
:disabled="installed.status !== 'Running'"
|
|
||||||
>
|
|
||||||
<el-icon>
|
|
||||||
<SvgIcon iconName="p-terminal2" />
|
|
||||||
</el-icon>
|
|
||||||
</el-button>
|
|
||||||
</el-tooltip>
|
|
||||||
</span>
|
|
||||||
<span class="ml-1">
|
|
||||||
<el-tooltip
|
|
||||||
v-if="mode !== 'upgrade'"
|
|
||||||
effect="dark"
|
|
||||||
:content="$t('menu.container')"
|
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
link
|
|
||||||
@click="toContainer(installed)"
|
|
||||||
>
|
|
||||||
<el-icon>
|
|
||||||
<SvgIcon iconName="p-docker" />
|
|
||||||
</el-icon>
|
|
||||||
</el-button>
|
|
||||||
</el-tooltip>
|
|
||||||
</span>
|
|
||||||
<span class="ml-1" v-if="mode === 'installed'">
|
|
||||||
<el-tooltip
|
|
||||||
effect="dark"
|
|
||||||
:content="$t('website.cancelFavorite')"
|
|
||||||
placement="top-start"
|
|
||||||
v-if="installed.favorite"
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
link
|
|
||||||
size="large"
|
|
||||||
icon="StarFilled"
|
|
||||||
type="warning"
|
|
||||||
@click="favoriteInstall(installed)"
|
|
||||||
></el-button>
|
|
||||||
</el-tooltip>
|
|
||||||
<el-tooltip
|
|
||||||
effect="dark"
|
|
||||||
:content="$t('website.favorite')"
|
|
||||||
placement="top-start"
|
|
||||||
v-else
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
link
|
|
||||||
icon="Star"
|
|
||||||
type="info"
|
|
||||||
@click="favoriteInstall(installed)"
|
|
||||||
></el-button>
|
|
||||||
</el-tooltip>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-wrap items-center justify-end gap-1">
|
|
||||||
<el-button
|
|
||||||
class="h-button"
|
|
||||||
plain
|
|
||||||
round
|
|
||||||
size="small"
|
|
||||||
@click="openUploads(installed.appKey, installed.name)"
|
|
||||||
v-if="mode === 'installed'"
|
|
||||||
>
|
|
||||||
{{ $t('database.loadBackup') }}
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
class="h-button"
|
|
||||||
plain
|
|
||||||
round
|
|
||||||
size="small"
|
|
||||||
@click="openBackups(installed)"
|
|
||||||
v-if="mode === 'installed'"
|
|
||||||
>
|
|
||||||
{{ $t('commons.button.backup') }}
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
class="h-button"
|
|
||||||
plain
|
|
||||||
round
|
|
||||||
size="small"
|
|
||||||
:disabled="installed.status === 'Upgrading'"
|
|
||||||
@click="ignoreApp(installed)"
|
|
||||||
v-if="mode === 'upgrade'"
|
|
||||||
>
|
|
||||||
{{ $t('commons.button.ignore') }}
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
class="h-button"
|
|
||||||
plain
|
|
||||||
round
|
|
||||||
size="small"
|
|
||||||
:disabled="
|
|
||||||
(installed.status !== 'Running' &&
|
|
||||||
installed.status !== 'UpgradeErr') ||
|
|
||||||
installed.appStatus === 'TakeDown'
|
|
||||||
"
|
|
||||||
@click="openOperate(installed, 'upgrade')"
|
|
||||||
v-if="mode === 'upgrade'"
|
|
||||||
>
|
|
||||||
{{ $t('commons.button.upgrade') }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="d-description flex flex-wrap items-center justify-start gap-1.5"
|
|
||||||
>
|
|
||||||
<el-button class="mr-1" plain size="small">
|
|
||||||
{{ $t('app.version') }}{{ $t('commons.colon')
|
|
||||||
}}{{ installed.version }}
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
v-if="installed.httpPort > 0"
|
|
||||||
class="mr-1"
|
|
||||||
plain
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
{{ $t('commons.table.port') }}{{ $t('commons.colon')
|
|
||||||
}}{{ installed.httpPort }}
|
|
||||||
</el-button>
|
|
||||||
<el-button v-if="installed.httpsPort > 0" plain size="small">
|
|
||||||
{{ $t('commons.table.port') }}:{{ installed.httpsPort }}
|
|
||||||
</el-button>
|
|
||||||
|
|
||||||
<el-popover
|
|
||||||
placement="top-start"
|
|
||||||
trigger="hover"
|
|
||||||
v-if="hasLinkButton(installed)"
|
|
||||||
:width="400"
|
|
||||||
>
|
|
||||||
<template #reference>
|
|
||||||
<el-button
|
|
||||||
plain
|
|
||||||
icon="Promotion"
|
|
||||||
size="small"
|
|
||||||
@click="openLink(defaultLink, installed)"
|
|
||||||
>
|
|
||||||
{{ $t('app.toLink') }}
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr v-if="defaultLink != ''">
|
|
||||||
<td v-if="installed.httpPort > 0">
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
link
|
|
||||||
@click="
|
|
||||||
toLink(
|
|
||||||
'http://' +
|
|
||||||
defaultLink +
|
|
||||||
':' +
|
|
||||||
installed.httpPort,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{
|
|
||||||
'http://' +
|
|
||||||
defaultLink +
|
|
||||||
':' +
|
|
||||||
installed.httpPort
|
|
||||||
}}
|
|
||||||
</el-button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-if="defaultLink != ''">
|
|
||||||
<td v-if="installed.httpsPort > 0">
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
link
|
|
||||||
@click="
|
|
||||||
toLink(
|
|
||||||
'https://' +
|
|
||||||
defaultLink +
|
|
||||||
':' +
|
|
||||||
installed.httpsPort,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{
|
|
||||||
'https://' +
|
|
||||||
defaultLink +
|
|
||||||
':' +
|
|
||||||
installed.httpsPort
|
|
||||||
}}
|
|
||||||
</el-button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-if="installed.webUI != ''">
|
|
||||||
<td>
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
link
|
|
||||||
@click="toLink(installed.webUI)"
|
|
||||||
>
|
|
||||||
{{ installed.webUI }}
|
|
||||||
</el-button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<span v-if="defaultLink == '' && installed.webUI == ''">
|
|
||||||
{{ $t('app.webUIConfig') }}
|
|
||||||
<el-link
|
|
||||||
icon="Position"
|
|
||||||
@click="jumpToPath(router, '/settings/panel')"
|
|
||||||
type="primary"
|
|
||||||
>
|
|
||||||
{{ $t('firewall.quickJump') }}
|
|
||||||
</el-link>
|
|
||||||
</span>
|
|
||||||
</el-popover>
|
|
||||||
</div>
|
|
||||||
<div class="description">
|
|
||||||
<span>
|
|
||||||
{{ $t('app.alreadyRun') }}{{ $t('commons.colon') }}
|
|
||||||
{{ getAge(installed.createdAt) }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="app-divider" />
|
|
||||||
<div
|
|
||||||
class="d-button flex flex-wrap items-center justify-start gap-1.5"
|
|
||||||
v-if="mode === 'installed' && installed.status != 'Installing'"
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
class="app-button"
|
|
||||||
v-for="(button, key) in buttons"
|
|
||||||
:key="key"
|
|
||||||
:type="
|
|
||||||
button.disabled && button.disabled(installed) ? 'info' : ''
|
|
||||||
"
|
|
||||||
plain
|
|
||||||
round
|
|
||||||
size="small"
|
|
||||||
@click="button.click(installed)"
|
|
||||||
:disabled="button.disabled && button.disabled(installed)"
|
|
||||||
>
|
|
||||||
{{ button.label }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-card>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</MainDiv>
|
</MainDiv>
|
||||||
|
|
@ -407,7 +109,6 @@
|
||||||
<AppDelete ref="deleteRef" @close="search" />
|
<AppDelete ref="deleteRef" @close="search" />
|
||||||
<AppParams ref="appParamRef" @close="search" />
|
<AppParams ref="appParamRef" @close="search" />
|
||||||
<AppUpgrade ref="upgradeRef" @close="search" />
|
<AppUpgrade ref="upgradeRef" @close="search" />
|
||||||
<PortJumpDialog ref="dialogPortJumpRef" />
|
|
||||||
<AppIgnore ref="ignoreRef" @close="search" />
|
<AppIgnore ref="ignoreRef" @close="search" />
|
||||||
<ComposeLogs ref="composeLogRef" />
|
<ComposeLogs ref="composeLogRef" />
|
||||||
<TerminalDialog ref="dialogTerminalRef" />
|
<TerminalDialog ref="dialogTerminalRef" />
|
||||||
|
|
@ -417,30 +118,28 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import AppCard from '@/views/app-store/installed/app/card.vue';
|
||||||
import Backups from '@/components/backup/index.vue';
|
import Backups from '@/components/backup/index.vue';
|
||||||
import Uploads from '@/components/upload/index.vue';
|
import Uploads from '@/components/upload/index.vue';
|
||||||
import PortJumpDialog from '@/components/port-jump/index.vue';
|
|
||||||
import AppResources from './check/index.vue';
|
import AppResources from './check/index.vue';
|
||||||
import AppDelete from './delete/index.vue';
|
import AppDelete from './delete/index.vue';
|
||||||
import AppParams from './detail/index.vue';
|
import AppParams from './detail/index.vue';
|
||||||
import AppUpgrade from './upgrade/index.vue';
|
import AppUpgrade from './upgrade/index.vue';
|
||||||
import AppIgnore from './ignore/index.vue';
|
import AppIgnore from './ignore/index.vue';
|
||||||
import Status from '@/components/status/index.vue';
|
|
||||||
import TaskLog from '@/components/log/task/index.vue';
|
import TaskLog from '@/components/log/task/index.vue';
|
||||||
import Detail from '@/views/app-store/detail/index.vue';
|
import Detail from '@/views/app-store/detail/index.vue';
|
||||||
import Tags from '@/views/app-store/components/tag.vue';
|
import Tags from '@/views/app-store/components/tag.vue';
|
||||||
import SvgIcon from '@/components/svg-icon/svg-icon.vue';
|
|
||||||
import MainDiv from '@/components/main-div/index.vue';
|
import MainDiv from '@/components/main-div/index.vue';
|
||||||
import ComposeLogs from '@/components/log/compose/index.vue';
|
import ComposeLogs from '@/components/log/compose/index.vue';
|
||||||
import IgnoreApp from '@/views/app-store/installed/ignore/create/index.vue';
|
import IgnoreApp from '@/views/app-store/installed/ignore/create/index.vue';
|
||||||
import TerminalDialog from '@/views/container/container/terminal/index.vue';
|
import TerminalDialog from '@/views/container/container/terminal/index.vue';
|
||||||
|
|
||||||
import { searchAppInstalled, installedOp, appInstalledDeleteCheck, getAppIconUrl } from '@/api/modules/app';
|
import { searchAppInstalled, installedOp, appInstalledDeleteCheck } from '@/api/modules/app';
|
||||||
import { onMounted, onUnmounted, reactive, ref } from 'vue';
|
import { onMounted, onUnmounted, reactive, ref } from 'vue';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { ElMessageBox } from 'element-plus';
|
import { ElMessageBox } from 'element-plus';
|
||||||
import { App } from '@/api/interface/app';
|
import { App } from '@/api/interface/app';
|
||||||
import { getAge, jumpToPath, toLink } from '@/utils/util';
|
import { jumpToPath, toLink } from '@/utils/util';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { MsgSuccess } from '@/utils/message';
|
import { MsgSuccess } from '@/utils/message';
|
||||||
import { getAgentSettingByKey } from '@/api/modules/setting';
|
import { getAgentSettingByKey } from '@/api/modules/setting';
|
||||||
|
|
@ -472,7 +171,6 @@ const deleteRef = ref();
|
||||||
const appParamRef = ref();
|
const appParamRef = ref();
|
||||||
const upgradeRef = ref();
|
const upgradeRef = ref();
|
||||||
const ignoreRef = ref();
|
const ignoreRef = ref();
|
||||||
const dialogPortJumpRef = ref();
|
|
||||||
const composeLogRef = ref();
|
const composeLogRef = ref();
|
||||||
const dialogTerminalRef = ref();
|
const dialogTerminalRef = ref();
|
||||||
const taskLogRef = ref();
|
const taskLogRef = ref();
|
||||||
|
|
@ -491,18 +189,6 @@ const defaultLink = ref('');
|
||||||
const detailRef = ref();
|
const detailRef = ref();
|
||||||
const ignoreAppRef = ref();
|
const ignoreAppRef = ref();
|
||||||
|
|
||||||
const options = {
|
|
||||||
modifiers: [
|
|
||||||
{
|
|
||||||
name: 'flip',
|
|
||||||
options: {
|
|
||||||
padding: 5,
|
|
||||||
fallbackPlacements: ['bottom-start', 'top-start', 'right', 'left'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const openDetail = (key: string) => {
|
const openDetail = (key: string) => {
|
||||||
detailRef.value.acceptParams(key, 'install');
|
detailRef.value.acceptParams(key, 'install');
|
||||||
};
|
};
|
||||||
|
|
@ -515,13 +201,6 @@ const changeTag = (key: string) => {
|
||||||
search();
|
search();
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasLinkButton = (installed: any) => {
|
|
||||||
return (
|
|
||||||
(installed.appType == 'website' || installed.appKey?.startsWith('local')) &&
|
|
||||||
(installed.httpPort > 0 || installed.httpsPort > 0 || installed.webUI != '')
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const search = async () => {
|
const search = async () => {
|
||||||
searchReq.page = paginationConfig.currentPage;
|
searchReq.page = paginationConfig.currentPage;
|
||||||
searchReq.pageSize = paginationConfig.pageSize;
|
searchReq.pageSize = paginationConfig.pageSize;
|
||||||
|
|
@ -579,10 +258,6 @@ const openIgnore = () => {
|
||||||
ignoreRef.value.acceptParams();
|
ignoreRef.value.acceptParams();
|
||||||
};
|
};
|
||||||
|
|
||||||
const ignoreApp = (row: App.AppInstalled) => {
|
|
||||||
ignoreAppRef.value.acceptParams(row);
|
|
||||||
};
|
|
||||||
|
|
||||||
const operate = async () => {
|
const operate = async () => {
|
||||||
open.value = false;
|
open.value = false;
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
@ -702,6 +377,10 @@ const buttons = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const ignoreApp = (row: App.AppInstalled) => {
|
||||||
|
ignoreAppRef.value.acceptParams(row);
|
||||||
|
};
|
||||||
|
|
||||||
const toContainer = async (row: App.AppInstalled) => {
|
const toContainer = async (row: App.AppInstalled) => {
|
||||||
routerToNameWithQuery('ContainerItem', {
|
routerToNameWithQuery('ContainerItem', {
|
||||||
filters: 'com.docker.compose.project=' + row.serviceName,
|
filters: 'com.docker.compose.project=' + row.serviceName,
|
||||||
|
|
@ -733,10 +412,6 @@ const openParam = (row: any) => {
|
||||||
appParamRef.value.acceptParams({ id: row.id });
|
appParamRef.value.acceptParams({ id: row.id });
|
||||||
};
|
};
|
||||||
|
|
||||||
const isAppErr = (row: any) => {
|
|
||||||
return row.status.includes('Err') || row.status.includes('Error') || row.status.includes('UnHealthy');
|
|
||||||
};
|
|
||||||
|
|
||||||
const openLog = (row: any) => {
|
const openLog = (row: any) => {
|
||||||
switch (row.status) {
|
switch (row.status) {
|
||||||
case 'Installing':
|
case 'Installing':
|
||||||
|
|
@ -819,28 +494,9 @@ onUnmounted(() => {
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@use '../index';
|
@use '../index';
|
||||||
|
|
||||||
.app-error {
|
|
||||||
max-height: 500px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
.d-name {
|
|
||||||
.el-button + .el-button {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.d-button {
|
.d-button {
|
||||||
.el-button + .el-button {
|
.el-button + .el-button {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.d-description {
|
|
||||||
.el-button + .el-button {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.svg-icon {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue