314 lines
7.8 KiB
Vue
314 lines
7.8 KiB
Vue
<template>
|
|
<Card title="App Releases">
|
|
<div v-if="sources.length">
|
|
<div class="flex flex-row items-baseline">
|
|
<FormControl
|
|
type="select"
|
|
v-if="sources.length > 1"
|
|
v-model="selectedSource"
|
|
:options="
|
|
sources.map(s => ({
|
|
label: `${s.source_information.repository}:${s.source_information.branch}`,
|
|
value: s.source
|
|
}))
|
|
"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div v-if="!sources.length">
|
|
<p class="mt-3 text-center text-lg text-gray-600">
|
|
No published source exist for this app. Please contact support to
|
|
publish a version of this app.
|
|
</p>
|
|
</div>
|
|
<div
|
|
v-else-if="releasesList.length === 0 && !$resources.releases.list.loading"
|
|
>
|
|
<p class="mt-3 text-center text-lg text-gray-600">
|
|
No app releases have been created for this version.
|
|
</p>
|
|
</div>
|
|
|
|
<div v-else>
|
|
<div class="divide-y">
|
|
<div
|
|
class="grid grid-cols-3 items-center gap-x-8 py-4 text-base text-gray-600 md:grid-cols-6"
|
|
>
|
|
<span class="md:col-span-2">Commit Message</span>
|
|
<span class="hidden md:inline">Tag</span>
|
|
<span class="hidden md:inline">Author</span>
|
|
<span>Status</span>
|
|
<span></span>
|
|
</div>
|
|
|
|
<div
|
|
v-for="release in releasesList"
|
|
:key="release.name"
|
|
class="grid grid-cols-3 items-center gap-x-8 py-4 text-base text-gray-900 md:grid-cols-6"
|
|
>
|
|
<p
|
|
class="max-w-md truncate text-base font-medium text-gray-700 md:col-span-2"
|
|
>
|
|
{{ release.message }}
|
|
</p>
|
|
<CommitTag
|
|
class="hidden md:flex"
|
|
:tag="release.tag || release.hash.slice(0, 6)"
|
|
:link="getCommitUrl(release.hash)"
|
|
/>
|
|
<span class="hidden text-gray-600 md:inline">
|
|
{{ release.author }}
|
|
</span>
|
|
<span>
|
|
<Badge v-if="release.status != 'Draft'" :label="release.status" />
|
|
</span>
|
|
<span class="text-right">
|
|
<Button
|
|
v-if="isPublishable(release)"
|
|
:loading="
|
|
$resources.createApprovalRequest.loading ||
|
|
$resources.latestApproved.loading
|
|
"
|
|
@click="confirmApprovalRequest(release.name)"
|
|
>
|
|
Publish
|
|
</Button>
|
|
|
|
<Button
|
|
v-else-if="release.status == 'Awaiting Approval'"
|
|
@click="confirmCancelRequest(release.name)"
|
|
>Cancel</Button
|
|
>
|
|
|
|
<Button
|
|
v-else-if="release.status == 'Rejected'"
|
|
@click="showFeedback(release)"
|
|
>View Feedback</Button
|
|
>
|
|
</span>
|
|
</div>
|
|
<Dialog
|
|
:options="{ title: 'Reason for Rejection' }"
|
|
v-model="showRejectionFeedbackDialog"
|
|
>
|
|
<template v-slot:body-content>
|
|
<div class="prose text-lg" v-html="rejectionFeedback"></div>
|
|
</template>
|
|
</Dialog>
|
|
|
|
<div class="py-3">
|
|
<Button
|
|
@click="$resources.releases.next()"
|
|
v-if="$resources.releases.hasNextPage"
|
|
:loading="$resources.releases.list.loading"
|
|
loadingText="Loading..."
|
|
>Load More</Button
|
|
>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
</template>
|
|
|
|
<script>
|
|
import CommitTag from './utils/CommitTag.vue';
|
|
import { notify } from '@/utils/toast';
|
|
|
|
export default {
|
|
props: {
|
|
app: {
|
|
type: Object
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
showRejectionFeedbackDialog: false,
|
|
rejectionFeedback: '',
|
|
selectedSource: null
|
|
};
|
|
},
|
|
mounted() {
|
|
this.$socket.emit('pagetype_subscribe', 'App Release');
|
|
this.$socket.on('list_update', this.releaseStateUpdate);
|
|
if (this.sources.length > 0) {
|
|
this.selectedSource = this.sources[0].source;
|
|
}
|
|
},
|
|
beforeMount() {
|
|
this.$socket.emit('pagetype_unsubscribe', 'App Release');
|
|
this.$socket.off('list_update', this.releaseStateUpdate);
|
|
},
|
|
resources: {
|
|
releases() {
|
|
return {
|
|
type: 'list',
|
|
pagetype: 'App Release',
|
|
url: 'jcloud.api.marketplace.releases',
|
|
filters: {
|
|
app: this.app.app,
|
|
source: this.selectedSource
|
|
},
|
|
start: 0,
|
|
pageLength: 15,
|
|
auto: true
|
|
};
|
|
},
|
|
appSource() {
|
|
return {
|
|
url: 'jcloud.api.marketplace.get_app_source',
|
|
params: {
|
|
name: this.selectedSource
|
|
}
|
|
};
|
|
},
|
|
latestApproved() {
|
|
return {
|
|
url: 'jcloud.api.marketplace.latest_approved_release',
|
|
params: {
|
|
source: this.selectedSource
|
|
},
|
|
auto: true
|
|
};
|
|
},
|
|
createApprovalRequest() {
|
|
return {
|
|
url: 'jcloud.api.marketplace.create_approval_request',
|
|
onSuccess() {
|
|
this.resetReleaseListState();
|
|
},
|
|
onError(err) {
|
|
const requestAlreadyExists = err.messages.some(msg =>
|
|
msg.includes('already awaiting approval')
|
|
);
|
|
|
|
if (requestAlreadyExists)
|
|
notify({
|
|
title: 'Request already exists',
|
|
message: err.messages.join('\n'),
|
|
color: 'red',
|
|
icon: 'x'
|
|
});
|
|
else
|
|
notify({
|
|
title: 'Error',
|
|
message: err.messages.join('\n'),
|
|
color: 'red',
|
|
icon: 'x'
|
|
});
|
|
}
|
|
};
|
|
},
|
|
cancelApprovalRequest() {
|
|
return {
|
|
url: 'jcloud.api.marketplace.cancel_approval_request',
|
|
onSuccess() {
|
|
this.resetReleaseListState();
|
|
}
|
|
};
|
|
}
|
|
},
|
|
methods: {
|
|
isPublishable(release) {
|
|
return (
|
|
release.status == 'Draft' &&
|
|
(!this.latestApprovedOn ||
|
|
this.$date(release.creation) > this.latestApprovedOn)
|
|
);
|
|
},
|
|
createApprovalRequest(appRelease) {
|
|
let { app } = this.app;
|
|
this.$resources.createApprovalRequest.submit({
|
|
name: app,
|
|
app_release: appRelease
|
|
});
|
|
},
|
|
cancelApprovalRequest(appRelease) {
|
|
let { app } = this.app;
|
|
this.$resources.cancelApprovalRequest.submit({
|
|
marketplace_app: app,
|
|
app_release: appRelease
|
|
});
|
|
},
|
|
resetReleaseListState() {
|
|
this.$resources.releases.reload();
|
|
this.$resources.latestApproved.reload();
|
|
},
|
|
showFeedback(appRelease) {
|
|
this.showRejectionFeedbackDialog = true;
|
|
this.rejectionFeedback = appRelease.reason_for_rejection;
|
|
},
|
|
confirmApprovalRequest(appRelease) {
|
|
this.$confirm({
|
|
title: 'Publish Release',
|
|
message:
|
|
'Are you sure you want to publish this release to marketplace? Upon confirmation, the release will be sent for approval by the review team.',
|
|
actionLabel: 'Publish',
|
|
action: closeDialog => {
|
|
closeDialog();
|
|
this.createApprovalRequest(appRelease);
|
|
}
|
|
});
|
|
},
|
|
confirmCancelRequest(appRelease) {
|
|
this.$confirm({
|
|
title: 'Cancel Release Approval Request',
|
|
message:
|
|
'Are you sure you want to <strong>cancel</strong> the publish request for this release?',
|
|
actionLabel: 'Proceed',
|
|
actionColor: 'red',
|
|
action: closeDialog => {
|
|
closeDialog();
|
|
this.cancelApprovalRequest(appRelease);
|
|
}
|
|
});
|
|
},
|
|
getCommitUrl(releaseHash) {
|
|
return this.repoUrl ? `${this.repoUrl}/commit/${releaseHash}` : '';
|
|
},
|
|
releaseStateUpdate(data) {
|
|
if (this.selectedSource && data.source == this.selectedSource) {
|
|
this.resetReleaseListState();
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
releasesList() {
|
|
if (!this.$resources.releases.data) {
|
|
return [];
|
|
}
|
|
return this.$resources.releases.data;
|
|
},
|
|
latestApprovedOn() {
|
|
if (
|
|
this.$resources.latestApproved.data &&
|
|
!this.$resources.latestApproved.loading
|
|
) {
|
|
return this.$date(this.$resources.latestApproved.data.creation);
|
|
}
|
|
},
|
|
sources() {
|
|
// Return only the unique sources
|
|
let tempArray = [];
|
|
for (let source of this.app.sources) {
|
|
if (!tempArray.find(x => x.source === source.source)) {
|
|
tempArray.push(source);
|
|
}
|
|
}
|
|
return tempArray;
|
|
},
|
|
repoUrl() {
|
|
return this.$resources.appSource?.data?.repository_url;
|
|
}
|
|
},
|
|
watch: {
|
|
selectedSource(value) {
|
|
if (value) {
|
|
this.resetReleaseListState();
|
|
this.$resources.appSource.submit({ name: value });
|
|
}
|
|
}
|
|
},
|
|
components: { CommitTag }
|
|
};
|
|
</script>
|