jcloude/dashboard/src/pages/CreateSiteForMarketplaceApp.vue
2025-12-23 19:23:49 +08:00

243 lines
5.5 KiB
Vue

<template>
<div class="top-0 z-10 shrink-0">
<Header>
<FBreadcrumbs
:items="[
{
label: 'Install App',
route: { name: 'InstallApp', params: { app: app } },
},
]"
/>
</Header>
<div class="m-12 mx-auto max-w-2xl px-5">
<div v-if="$resources.app.loading" class="py-4 text-base text-gray-600">
Loading...
</div>
<div v-else class="space-y-6">
<div class="mb-12 flex">
<img
:src="appDoc.image"
class="h-12 w-12 rounded-lg border"
:alt="appDoc.name"
/>
<div class="my-1 ml-4 flex flex-col justify-between">
<h1 class="text-lg font-semibold">{{ appDoc.title }}</h1>
<p class="text-sm text-gray-600">{{ appDoc.description }}</p>
</div>
</div>
<div
v-if="failure"
class="flex items-center space-x-2 rounded border border-gray-200 bg-gray-100 p-4 text-base text-gray-700"
>
<lucide-alert-circle class="inline-block h-5 w-5" />
<p>
Failed to install the app.
<router-link class="underline" :to="failureRoute">
{{
$resources.siteGroupDeploy.pg?.status === 'Bench Deploy Failed'
? 'View Deploy'
: 'View Job'
}}
</router-link>
.
</p>
</div>
<div class="divide-y rounded-lg bg-gray-50 px-4">
<div
v-for="step in steps"
:key="step.id"
class="flex items-center border-gray-200 px-1 py-3"
>
<div class="flex items-center space-x-4">
<LoadingIndicator
class="h-4 w-4 text-gray-900"
v-if="step.icon() === 'loading'"
/>
<FeatherIcon
v-else
:name="step.icon()"
class="h-5 w-5 rounded-full p-0.5 text-white"
:stroke-width="3"
:class="{
'bg-green-500': step.icon() === 'check',
'bg-red-500': step.icon() === 'x',
'bg-gray-500': step.icon() === 'clock',
}"
/>
<div class="flex flex-col space-y-1">
<h5 class="text-base">{{ step.title }}</h5>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { Breadcrumbs } from 'frappe-ui';
import Header from '../components/Header.vue';
export default {
props: {
app: {
type: String,
required: true,
},
},
pageMeta() {
return {
title: `Install ${this.appDoc.title} - Frappe Cloud`,
};
},
components: {
FBreadcrumbs: Breadcrumbs,
Header,
},
data() {
return {
siteGroupDeployName: this.$route.query.siteGroupDeployName,
};
},
mounted() {
this.$socket.emit(
'pg_subscribe',
'Site Group Deploy',
this.siteGroupDeployName,
);
this.$socket.on('pg_update', () => {
this.$resources.siteGroupDeploy.reload();
});
},
resources: {
app() {
return {
url: 'press.api.marketplace.get',
params: {
app: this.app,
},
auto: true,
};
},
siteGroupDeploy() {
return {
type: 'document',
doctype: 'Site Group Deploy',
name: this.siteGroupDeployName,
onSuccess: (pg) => {
if (pg.status === 'Site Created') {
setTimeout(() => {
this.$router.push({
name: 'Site Detail Overview',
params: { name: pg.site },
});
}, 1000);
}
},
};
},
},
computed: {
failure() {
return ['Site Creation Failed', 'Bench Deploy Failed'].includes(
this.$resources.siteGroupDeploy.pg?.status,
);
},
failureRoute() {
if (this.$resources.siteGroupDeploy.pg?.status === 'Bench Deploy Failed')
return {
name: 'Release Group Detail Deploys',
params: {
name: this.$resources.siteGroupDeploy.pg.release_group,
},
};
else if (
this.$resources.siteGroupDeploy.pg?.status === 'Site Creation Failed'
)
return {
name: 'Site Jobs',
params: { name: this.$resources.siteGroupDeploy.pg.site },
};
},
steps() {
const statusPosition = (status) => {
if (!status) return -1;
return [
'Pending',
'Deploying Bench',
'Bench Deployed',
'Bench Deploy Failed',
'Creating Site',
'Site Created',
'Site Creation Failed',
].indexOf(status);
};
const status = this.$resources.siteGroupDeploy?.pg?.status;
return [
{
id: 0,
title: 'Initializing',
description: 'Initializing the setup',
status: 'Pending',
icon: () => {
if (statusPosition(status) === 0) {
return 'loading';
} else if (statusPosition(status) > 0) {
return 'check';
}
},
message: 'This should take a few minutes',
},
{
id: 1,
title:
statusPosition(status) <= 1 ? 'Deploying Bench' : 'Bench Deployed',
description: 'Deploying bench on the server',
status: 'Deploying Bench',
icon: () => {
if (status === 'Bench Deploy Failed') {
return 'x';
} else if (statusPosition(status) === 1) {
return 'loading';
} else if (statusPosition(status) > 1) {
return 'check';
} else {
return 'clock';
}
},
message: 'This should take a few minutes',
},
{
id: 2,
title: statusPosition(status) <= 4 ? 'Creating Site' : 'Site Created',
description: 'Creating site on the server',
status: 'Creating Site',
icon: () => {
if (status === 'Site Creation Failed') {
return 'x';
} else if (statusPosition(status) === 4) {
return 'loading';
} else if (statusPosition(status) > 4) {
return 'check';
} else {
return 'clock';
}
},
message: 'This should take a few minutes',
},
];
},
appDoc() {
return this.$resources.app.data || {};
},
},
};
</script>