1044 lines
25 KiB
JavaScript
1044 lines
25 KiB
JavaScript
import { LoadingIndicator, Tooltip } from 'jingrow-ui';
|
|
import { defineAsyncComponent, h } from 'vue';
|
|
import { toast } from 'vue-sonner';
|
|
import LucideAppWindow from '~icons/lucide/app-window';
|
|
import LucideHardDriveDownload from '~icons/lucide/hard-drive-download';
|
|
import LucideVenetianMask from '~icons/lucide/venetian-mask';
|
|
import LucideRocket from '~icons/lucide/rocket';
|
|
import AddAppDialog from '../components/group/AddAppDialog.vue';
|
|
import ChangeAppBranchDialog from '../components/group/ChangeAppBranchDialog.vue';
|
|
import PatchAppDialog from '../components/group/PatchAppDialog.vue';
|
|
import { getTeam, switchToTeam } from '../data/team';
|
|
import router from '../router';
|
|
import { confirmDialog, icon, renderDialog } from '../utils/components';
|
|
import { getToastErrorMessage } from '../utils/toast';
|
|
import { date, duration } from '../utils/format';
|
|
import { getJobsTab } from './common/jobs';
|
|
import { getPatchesTab } from './common/patches';
|
|
import { tagTab } from './common/tags';
|
|
|
|
export default {
|
|
doctype: 'Release Group',
|
|
whitelistedMethods: {
|
|
addApp: 'add_app',
|
|
removeApp: 'remove_app',
|
|
changeAppBranch: 'change_app_branch',
|
|
fetchLatestAppUpdates: 'fetch_latest_app_update',
|
|
deleteConfig: 'delete_config',
|
|
updateConfig: 'update_config',
|
|
updateEnvironmentVariable: 'update_environment_variable',
|
|
deleteEnvironmentVariable: 'delete_environment_variable',
|
|
updateDependency: 'update_dependency',
|
|
addRegion: 'add_region',
|
|
deployedVersions: 'deployed_versions',
|
|
getAppVersions: 'get_app_versions',
|
|
getCertificate: 'get_certificate',
|
|
generateCertificate: 'generate_certificate',
|
|
sendTransferRequest: 'send_change_team_request',
|
|
addTag: 'add_resource_tag',
|
|
removeTag: 'remove_resource_tag',
|
|
redeploy: 'redeploy',
|
|
initialDeploy: 'initial_deploy',
|
|
},
|
|
list: {
|
|
route: '/groups',
|
|
title: 'Bench Groups',
|
|
fields: [{ apps: ['app'] }],
|
|
searchField: 'title',
|
|
filterControls() {
|
|
return [
|
|
{
|
|
type: 'link',
|
|
label: 'Version',
|
|
fieldname: 'version',
|
|
options: {
|
|
doctype: 'Jingrow Version',
|
|
},
|
|
},
|
|
{
|
|
type: 'link',
|
|
label: 'Tag',
|
|
fieldname: 'tags.tag',
|
|
options: {
|
|
doctype: 'Jcloude Tag',
|
|
filters: {
|
|
doctype_name: 'Release Group',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
},
|
|
columns: [
|
|
{ label: 'Title', fieldname: 'title', class: 'font-medium' },
|
|
{
|
|
label: 'Status',
|
|
fieldname: 'active_benches',
|
|
type: 'Badge',
|
|
width: 0.5,
|
|
format: (value, row) => {
|
|
if (!value) return 'Awaiting Deploy';
|
|
else return 'Active';
|
|
},
|
|
},
|
|
{
|
|
label: 'Version',
|
|
fieldname: 'version',
|
|
width: 0.5,
|
|
},
|
|
{
|
|
label: 'Apps',
|
|
fieldname: 'app',
|
|
format: (value, row) => {
|
|
return (row.apps || []).map((d) => d.app).join(', ');
|
|
},
|
|
width: '25rem',
|
|
},
|
|
{
|
|
label: 'Sites',
|
|
fieldname: 'site_count',
|
|
class: 'text-gray-600',
|
|
width: 0.25,
|
|
},
|
|
],
|
|
primaryAction() {
|
|
return {
|
|
label: 'New Bench Group',
|
|
variant: 'solid',
|
|
slots: {
|
|
prefix: icon('plus'),
|
|
},
|
|
onClick() {
|
|
router.push({ name: 'New Release Group' });
|
|
},
|
|
};
|
|
},
|
|
banner({ listResource: groups }) {
|
|
if (!groups.data?.length) {
|
|
return {
|
|
title: 'Learn how to create a new private bench group and sites',
|
|
button: {
|
|
label: 'Read docs',
|
|
variant: 'outline',
|
|
link: 'https://docs.framework.jingrow.com/cloud/benches/create-new',
|
|
},
|
|
};
|
|
}
|
|
},
|
|
},
|
|
detail: {
|
|
titleField: 'title',
|
|
statusBadge({ documentResource: releaseGroup }) {
|
|
return { label: releaseGroup.pg.status };
|
|
},
|
|
breadcrumbs({ items, documentResource: releaseGroup }) {
|
|
if (!releaseGroup.pg.server_team) return items;
|
|
|
|
let breadcrumbs = [];
|
|
let $team = getTeam();
|
|
|
|
if (
|
|
releaseGroup.pg.server_team == $team.pg?.name ||
|
|
$team.pg?.is_desk_user
|
|
) {
|
|
breadcrumbs.push(
|
|
{
|
|
label: releaseGroup.pg?.server_title || releaseGroup.pg?.server,
|
|
route: `/servers/${releaseGroup.pg?.server}`,
|
|
},
|
|
items[1],
|
|
);
|
|
} else {
|
|
breadcrumbs.push(...items);
|
|
}
|
|
return breadcrumbs;
|
|
},
|
|
route: '/groups/:name',
|
|
tabs: [
|
|
{
|
|
label: 'Sites',
|
|
icon: icon(LucideAppWindow),
|
|
route: 'sites',
|
|
type: 'Component',
|
|
component: defineAsyncComponent(
|
|
() => import('../pages/ReleaseGroupBenchSites.vue'),
|
|
),
|
|
props: (releaseGroup) => {
|
|
return {
|
|
releaseGroup: releaseGroup.pg.name,
|
|
actionsAccess: releaseGroup.pg.actions_access,
|
|
};
|
|
},
|
|
},
|
|
{
|
|
label: 'Apps',
|
|
icon: icon('grid'),
|
|
route: 'apps',
|
|
type: 'list',
|
|
list: {
|
|
doctype: 'Release Group App',
|
|
filters: (releaseGroup) => {
|
|
return {
|
|
parenttype: 'Release Group',
|
|
parent: releaseGroup.pg.name,
|
|
};
|
|
},
|
|
pageLength: 99999,
|
|
columns: [
|
|
{
|
|
label: 'App',
|
|
fieldname: 'title',
|
|
width: 1,
|
|
},
|
|
{
|
|
label: 'Repository',
|
|
width: 1,
|
|
format(value, row) {
|
|
return `${row.repository_owner}/${row.repository}`;
|
|
},
|
|
link(value, row) {
|
|
return row.repository_url;
|
|
},
|
|
},
|
|
{
|
|
label: 'Branch',
|
|
fieldname: 'branch',
|
|
type: 'Badge',
|
|
width: 0.5,
|
|
link(value, row) {
|
|
return `${row.repository_url}/tree/${value}`;
|
|
},
|
|
},
|
|
{
|
|
label: 'Version',
|
|
type: 'Badge',
|
|
fieldname: 'tag',
|
|
width: 0.5,
|
|
format(value, row) {
|
|
return value || row.hash?.slice(0, 7);
|
|
},
|
|
},
|
|
{
|
|
label: 'Status',
|
|
type: 'Badge',
|
|
suffix(row) {
|
|
if (!row.last_github_poll_failed) return;
|
|
|
|
return h(
|
|
Tooltip,
|
|
{
|
|
text: "What's this?",
|
|
placement: 'top',
|
|
class: 'rounded-full bg-gray-100 p-1',
|
|
},
|
|
() => [
|
|
h(
|
|
'a',
|
|
{
|
|
href: 'https://docs.framework.jingrow.com/cloud/faq/app-installation-issue',
|
|
target: '_blank',
|
|
},
|
|
[h(icon('help-circle', 'w-3 h-3'), {})],
|
|
),
|
|
],
|
|
);
|
|
},
|
|
format(value, row) {
|
|
let { update_available, deployed, last_github_poll_failed } =
|
|
row;
|
|
|
|
return last_github_poll_failed
|
|
? 'Action Required'
|
|
: !deployed
|
|
? 'Not Deployed'
|
|
: update_available
|
|
? 'Update Available'
|
|
: 'Latest Version';
|
|
},
|
|
width: 0.5,
|
|
},
|
|
],
|
|
rowActions({
|
|
row,
|
|
listResource: apps,
|
|
documentResource: releaseGroup,
|
|
}) {
|
|
let team = getTeam();
|
|
return [
|
|
{
|
|
label: 'View in Desk',
|
|
condition: () => team.pg?.is_desk_user,
|
|
onClick() {
|
|
window.open(
|
|
`${window.location.protocol}//${window.location.host}/app/app/${row.name}`,
|
|
'_blank',
|
|
);
|
|
},
|
|
},
|
|
{
|
|
label: 'Fetch Latest Updates',
|
|
onClick() {
|
|
toast.promise(
|
|
releaseGroup.fetchLatestAppUpdates.submit({
|
|
app: row.name,
|
|
}),
|
|
{
|
|
loading: `Fetching Latest Updates for ${row.title}...`,
|
|
success: () => {
|
|
apps.reload();
|
|
return `Latest Updates Fetched for ${row.title}`;
|
|
},
|
|
error: (e) => getToastErrorMessage(e),
|
|
},
|
|
);
|
|
},
|
|
},
|
|
{
|
|
label: 'Change Branch',
|
|
onClick() {
|
|
renderDialog(
|
|
h(ChangeAppBranchDialog, {
|
|
bench: releaseGroup.name,
|
|
app: row,
|
|
onBranchChange() {
|
|
apps.reload();
|
|
},
|
|
}),
|
|
);
|
|
},
|
|
},
|
|
{
|
|
label: 'Remove App',
|
|
condition: () => row.name !== 'jingrow',
|
|
onClick() {
|
|
if (releaseGroup.removeApp.loading) return;
|
|
confirmDialog({
|
|
title: 'Remove App',
|
|
message: `Are you sure you want to remove the app <b>${row.title}</b>?`,
|
|
onSuccess: ({ hide }) => {
|
|
toast.promise(
|
|
releaseGroup.removeApp.submit({
|
|
app: row.name,
|
|
}),
|
|
{
|
|
loading: 'Removing App...',
|
|
success: () => {
|
|
hide();
|
|
apps.reload();
|
|
return 'App Removed';
|
|
},
|
|
error: (e) => getToastErrorMessage(e),
|
|
},
|
|
);
|
|
},
|
|
});
|
|
},
|
|
},
|
|
{
|
|
label: 'Visit Repo',
|
|
onClick() {
|
|
window.open(
|
|
`${row.repository_url}/tree/${row.branch}`,
|
|
'_blank',
|
|
);
|
|
},
|
|
},
|
|
{
|
|
label: 'Apply Patch',
|
|
onClick: () => {
|
|
renderDialog(
|
|
h(PatchAppDialog, {
|
|
group: releaseGroup.name,
|
|
app: row.name,
|
|
}),
|
|
);
|
|
},
|
|
},
|
|
];
|
|
},
|
|
primaryAction({
|
|
listResource: apps,
|
|
documentResource: releaseGroup,
|
|
}) {
|
|
return {
|
|
label: 'Add App',
|
|
slots: {
|
|
prefix: icon('plus'),
|
|
},
|
|
onClick() {
|
|
renderDialog(
|
|
h(AddAppDialog, {
|
|
group: releaseGroup.pg,
|
|
onAppAdd() {
|
|
apps.reload();
|
|
releaseGroup.reload();
|
|
},
|
|
onNewApp(app, isUpdate) {
|
|
const loading = isUpdate
|
|
? 'Replacing App...'
|
|
: 'Adding App...';
|
|
|
|
toast.promise(
|
|
releaseGroup.addApp.submit({
|
|
app,
|
|
is_update: isUpdate,
|
|
}),
|
|
{
|
|
loading,
|
|
success: () => {
|
|
apps.reload();
|
|
releaseGroup.reload();
|
|
|
|
if (isUpdate) {
|
|
return `App ${app.title} updated`;
|
|
}
|
|
|
|
return `App ${app.title} added`;
|
|
},
|
|
error: (e) => getToastErrorMessage(e),
|
|
},
|
|
);
|
|
},
|
|
}),
|
|
);
|
|
},
|
|
};
|
|
},
|
|
},
|
|
},
|
|
{
|
|
label: 'Deploys',
|
|
route: 'deploys',
|
|
icon: icon('package'),
|
|
childrenRoutes: ['Deploy Candidate'],
|
|
type: 'list',
|
|
list: {
|
|
doctype: 'Deploy Candidate Build',
|
|
route: (row) => ({
|
|
name: 'Deploy Candidate',
|
|
params: { id: row.name },
|
|
}),
|
|
filters: (releaseGroup) => {
|
|
return {
|
|
group: releaseGroup.name,
|
|
};
|
|
},
|
|
orderBy: 'creation desc',
|
|
// fields: [{ apps: ['app'] }],
|
|
filterControls() {
|
|
return [
|
|
{
|
|
type: 'select',
|
|
label: 'Status',
|
|
fieldname: 'status',
|
|
options: [
|
|
'',
|
|
'Draft',
|
|
'Scheduled',
|
|
'Pending',
|
|
'Preparing',
|
|
'Running',
|
|
'Success',
|
|
'Failure',
|
|
],
|
|
},
|
|
];
|
|
},
|
|
banner({ documentResource: releaseGroup }) {
|
|
if (releaseGroup.pg.are_builds_suspended) {
|
|
return {
|
|
title:
|
|
'<b>Builds Suspended:</b> updates will be scheduled to run when builds resume.',
|
|
type: 'warning',
|
|
};
|
|
} else {
|
|
return null;
|
|
}
|
|
},
|
|
columns: [
|
|
{
|
|
label: 'Deploy',
|
|
fieldname: 'creation',
|
|
format(value) {
|
|
return `Deploy on ${date(value, 'llll')}`;
|
|
},
|
|
width: '20rem',
|
|
},
|
|
{
|
|
label: 'Status',
|
|
fieldname: 'status',
|
|
type: 'Badge',
|
|
width: 0.5,
|
|
suffix(row) {
|
|
if (!row.addressable_notification) {
|
|
return;
|
|
}
|
|
|
|
return h(
|
|
Tooltip,
|
|
{
|
|
text: 'Attention required!',
|
|
placement: 'top',
|
|
class: 'rounded-full bg-gray-100 p-1',
|
|
},
|
|
() => h(icon('alert-circle', 'w-3 h-3'), {}),
|
|
);
|
|
},
|
|
},
|
|
{
|
|
label: 'Apps',
|
|
format(value, row) {
|
|
return (row.apps || []).join(', ');
|
|
},
|
|
width: '20rem',
|
|
},
|
|
{
|
|
label: 'Duration',
|
|
fieldname: 'build_duration',
|
|
format: duration,
|
|
class: 'text-gray-600',
|
|
width: 1,
|
|
},
|
|
{
|
|
label: 'Deployed By',
|
|
fieldname: 'owner',
|
|
width: 1,
|
|
},
|
|
],
|
|
primaryAction({ listResource: deploys, documentResource: group }) {
|
|
return {
|
|
label: 'Deploy',
|
|
slots: {
|
|
prefix: icon(LucideRocket),
|
|
},
|
|
onClick() {
|
|
if (group.pg.deploy_information.deploy_in_progress) {
|
|
return toast.error(
|
|
'Deploy is in progress. Please wait for it to complete.',
|
|
);
|
|
} else if (group.pg.deploy_information.update_available) {
|
|
let UpdateReleaseGroupDialog = defineAsyncComponent(
|
|
() =>
|
|
import(
|
|
'../components/group/UpdateReleaseGroupDialog.vue'
|
|
),
|
|
);
|
|
renderDialog(
|
|
h(UpdateReleaseGroupDialog, {
|
|
bench: group.name,
|
|
lastDeploy: true,
|
|
onSuccess(candidate) {
|
|
group.pg.deploy_information.deploy_in_progress = true;
|
|
if (candidate) {
|
|
group.pg.deploy_information.last_deploy.name =
|
|
candidate;
|
|
}
|
|
},
|
|
}),
|
|
);
|
|
} else {
|
|
confirmDialog({
|
|
title: 'Deploy without app updates?',
|
|
message:
|
|
'No app updates detected. Changes in dependencies and environment variables will be applied on deploying.',
|
|
onSuccess: ({ hide }) => {
|
|
toast.promise(group.redeploy.submit(), {
|
|
loading: 'Deploying...',
|
|
success: () => {
|
|
hide();
|
|
deploys.reload();
|
|
return 'Changes Deployed';
|
|
},
|
|
error: (e) => getToastErrorMessage(e),
|
|
});
|
|
},
|
|
});
|
|
}
|
|
},
|
|
};
|
|
},
|
|
},
|
|
},
|
|
getJobsTab('Release Group'),
|
|
{
|
|
label: 'Config',
|
|
icon: icon('settings'),
|
|
route: 'bench-config',
|
|
type: 'list',
|
|
list: {
|
|
doctype: 'Common Site Config',
|
|
filters: (releaseGroup) => {
|
|
return {
|
|
parenttype: 'Release Group',
|
|
parent: releaseGroup.name,
|
|
};
|
|
},
|
|
orderBy: 'creation desc',
|
|
fields: ['name'],
|
|
pageLength: 999,
|
|
columns: [
|
|
{
|
|
label: 'Config Name',
|
|
fieldname: 'key',
|
|
format(value, row) {
|
|
if (row.title) {
|
|
return `${row.title} (${row.key})`;
|
|
}
|
|
return row.key;
|
|
},
|
|
},
|
|
{
|
|
label: 'Config Value',
|
|
fieldname: 'value',
|
|
class: 'font-mono',
|
|
},
|
|
{
|
|
label: 'Type',
|
|
fieldname: 'type',
|
|
type: 'Badge',
|
|
width: '100px',
|
|
},
|
|
],
|
|
primaryAction({
|
|
listResource: configs,
|
|
documentResource: releaseGroup,
|
|
}) {
|
|
return {
|
|
label: 'Add Config',
|
|
slots: {
|
|
prefix: icon('plus'),
|
|
},
|
|
onClick() {
|
|
let ConfigEditorDialog = defineAsyncComponent(
|
|
() => import('../components/ConfigEditorDialog.vue'),
|
|
);
|
|
renderDialog(
|
|
h(ConfigEditorDialog, {
|
|
group: releaseGroup.pg.name,
|
|
onSuccess() {
|
|
configs.reload();
|
|
},
|
|
}),
|
|
);
|
|
},
|
|
};
|
|
},
|
|
secondaryAction({ listResource: configs }) {
|
|
return {
|
|
label: 'Preview',
|
|
slots: {
|
|
prefix: icon('eye'),
|
|
},
|
|
onClick() {
|
|
let ConfigPreviewDialog = defineAsyncComponent(
|
|
() => import('../components/ConfigPreviewDialog.vue'),
|
|
);
|
|
renderDialog(
|
|
h(ConfigPreviewDialog, {
|
|
configs: configs.data,
|
|
}),
|
|
);
|
|
},
|
|
};
|
|
},
|
|
rowActions({
|
|
row,
|
|
listResource: configs,
|
|
documentResource: releaseGroup,
|
|
}) {
|
|
return [
|
|
{
|
|
label: 'Edit',
|
|
onClick() {
|
|
let ConfigEditorDialog = defineAsyncComponent(
|
|
() => import('../components/ConfigEditorDialog.vue'),
|
|
);
|
|
renderDialog(
|
|
h(ConfigEditorDialog, {
|
|
group: releaseGroup.pg.name,
|
|
config: row,
|
|
onSuccess() {
|
|
configs.reload();
|
|
},
|
|
}),
|
|
);
|
|
},
|
|
},
|
|
{
|
|
label: 'Delete',
|
|
onClick() {
|
|
confirmDialog({
|
|
title: 'Delete Config',
|
|
message: `Are you sure you want to delete the config <b>${row.key}</b>?`,
|
|
onSuccess({ hide }) {
|
|
if (releaseGroup.deleteConfig.loading) return;
|
|
toast.promise(
|
|
releaseGroup.deleteConfig.submit(
|
|
{ key: row.key },
|
|
{
|
|
onSuccess: () => {
|
|
configs.reload();
|
|
hide();
|
|
},
|
|
},
|
|
),
|
|
{
|
|
loading: 'Deleting config...',
|
|
success: () => `Config ${row.key} removed`,
|
|
error: (e) => getToastErrorMessage(e),
|
|
},
|
|
);
|
|
},
|
|
});
|
|
},
|
|
},
|
|
];
|
|
},
|
|
},
|
|
},
|
|
{
|
|
label: 'Actions',
|
|
icon: icon('sliders'),
|
|
route: 'actions',
|
|
type: 'Component',
|
|
component: defineAsyncComponent(
|
|
() => import('../components/group/ReleaseGroupActions.vue'),
|
|
),
|
|
props: (releaseGroup) => {
|
|
return { releaseGroup: releaseGroup.name };
|
|
},
|
|
},
|
|
{
|
|
label: 'Regions',
|
|
icon: icon('globe'),
|
|
route: 'regions',
|
|
type: 'list',
|
|
list: {
|
|
doctype: 'Cluster',
|
|
filters: (releaseGroup) => {
|
|
return { group: releaseGroup.name };
|
|
},
|
|
columns: [
|
|
{
|
|
label: 'Region',
|
|
fieldname: 'title',
|
|
},
|
|
{
|
|
label: 'Country',
|
|
fieldname: 'image',
|
|
format(value, row) {
|
|
return '';
|
|
},
|
|
prefix(row) {
|
|
return h('img', {
|
|
src: row.image,
|
|
class: 'w-4 h-4',
|
|
alt: row.title,
|
|
});
|
|
},
|
|
},
|
|
],
|
|
primaryAction({
|
|
listResource: clusters,
|
|
documentResource: releaseGroup,
|
|
}) {
|
|
return {
|
|
label: 'Add Region',
|
|
slots: {
|
|
prefix: icon('plus'),
|
|
},
|
|
onClick() {
|
|
let AddRegionDialog = defineAsyncComponent(
|
|
() => import('../components/group/AddRegionDialog.vue'),
|
|
);
|
|
renderDialog(
|
|
h(AddRegionDialog, {
|
|
group: releaseGroup.pg.name,
|
|
onSuccess() {
|
|
clusters.reload();
|
|
},
|
|
}),
|
|
);
|
|
},
|
|
};
|
|
},
|
|
},
|
|
},
|
|
getPatchesTab(false),
|
|
{
|
|
label: 'Dependencies',
|
|
icon: icon('box'),
|
|
route: 'bench-dependencies',
|
|
type: 'list',
|
|
list: {
|
|
doctype: 'Release Group Dependency',
|
|
filters: (releaseGroup) => {
|
|
return {
|
|
parenttype: 'Release Group',
|
|
parent: releaseGroup.name,
|
|
};
|
|
},
|
|
columns: [
|
|
{
|
|
label: 'Dependency',
|
|
fieldname: 'dependency',
|
|
format(value, row) {
|
|
return row.title;
|
|
},
|
|
},
|
|
{
|
|
label: 'Version',
|
|
fieldname: 'version',
|
|
suffix(row) {
|
|
if (!row.is_custom) {
|
|
return;
|
|
}
|
|
|
|
return h(
|
|
Tooltip,
|
|
{
|
|
text: 'Custom version',
|
|
placement: 'top',
|
|
class: 'rounded-full bg-gray-100 p-1',
|
|
},
|
|
() => h(icon('alert-circle', 'w-3 h-3'), {}),
|
|
);
|
|
},
|
|
},
|
|
],
|
|
rowActions({
|
|
row,
|
|
listResource: dependencies,
|
|
documentResource: releaseGroup,
|
|
}) {
|
|
return [
|
|
{
|
|
label: 'Edit',
|
|
onClick() {
|
|
let DependencyEditorDialog = defineAsyncComponent(
|
|
() =>
|
|
import('../components/group/DependencyEditorDialog.vue'),
|
|
);
|
|
renderDialog(
|
|
h(DependencyEditorDialog, {
|
|
group: releaseGroup.pg,
|
|
dependency: row,
|
|
onSuccess() {
|
|
dependencies.reload();
|
|
},
|
|
}),
|
|
);
|
|
},
|
|
},
|
|
];
|
|
},
|
|
},
|
|
},
|
|
{
|
|
label: 'Env',
|
|
icon: icon('tool'),
|
|
route: 'bench-environment-variable',
|
|
type: 'list',
|
|
list: {
|
|
doctype: 'Release Group Variable',
|
|
filters: (releaseGroup) => {
|
|
return {
|
|
parenttype: 'Release Group',
|
|
parent: releaseGroup.name,
|
|
};
|
|
},
|
|
orderBy: 'creation desc',
|
|
fields: ['name'],
|
|
columns: [
|
|
{
|
|
label: 'Environment Variable Name',
|
|
fieldname: 'key',
|
|
},
|
|
{
|
|
label: 'Environment Variable Value',
|
|
fieldname: 'value',
|
|
},
|
|
],
|
|
primaryAction({
|
|
listResource: environmentVariables,
|
|
documentResource: releaseGroup,
|
|
}) {
|
|
return {
|
|
label: 'Add Environment Variable',
|
|
slots: {
|
|
prefix: icon('plus'),
|
|
},
|
|
onClick() {
|
|
let EnvironmentVariableEditorDialog = defineAsyncComponent(
|
|
() =>
|
|
import('../components/EnvironmentVariableEditorDialog.vue'),
|
|
);
|
|
renderDialog(
|
|
h(EnvironmentVariableEditorDialog, {
|
|
group: releaseGroup.pg.name,
|
|
onSuccess() {
|
|
environmentVariables.reload();
|
|
},
|
|
}),
|
|
);
|
|
},
|
|
};
|
|
},
|
|
rowActions({
|
|
row,
|
|
listResource: environmentVariables,
|
|
documentResource: releaseGroup,
|
|
}) {
|
|
return [
|
|
{
|
|
label: 'Edit',
|
|
onClick() {
|
|
let ConfigEditorDialog = defineAsyncComponent(
|
|
() =>
|
|
import(
|
|
'../components/EnvironmentVariableEditorDialog.vue'
|
|
),
|
|
);
|
|
renderDialog(
|
|
h(ConfigEditorDialog, {
|
|
group: releaseGroup.pg.name,
|
|
environment_variable: row,
|
|
onSuccess() {
|
|
environmentVariables.reload();
|
|
},
|
|
}),
|
|
);
|
|
},
|
|
},
|
|
{
|
|
label: 'Delete',
|
|
onClick() {
|
|
confirmDialog({
|
|
title: 'Delete Environment Variable',
|
|
message: `Are you sure you want to delete the environment variable <b>${row.key}</b>?`,
|
|
onSuccess({ hide }) {
|
|
if (releaseGroup.deleteEnvironmentVariable.loading)
|
|
return;
|
|
toast.promise(
|
|
releaseGroup.deleteEnvironmentVariable.submit(
|
|
{ key: row.key },
|
|
{
|
|
onSuccess: () => {
|
|
environmentVariables.reload();
|
|
hide();
|
|
},
|
|
},
|
|
),
|
|
{
|
|
loading: 'Deleting environment variable...',
|
|
success: () =>
|
|
`Environment variable ${row.key} removed`,
|
|
error: (e) => getToastErrorMessage(e),
|
|
},
|
|
);
|
|
},
|
|
});
|
|
},
|
|
},
|
|
];
|
|
},
|
|
},
|
|
},
|
|
tagTab('Release Group'),
|
|
],
|
|
actions(context) {
|
|
let { documentResource: group } = context;
|
|
let team = getTeam();
|
|
|
|
return [
|
|
{
|
|
label: 'Impersonate Group Owner',
|
|
title: 'Impersonate Group Owner', // for label to pop-up on hover
|
|
slots: {
|
|
icon: icon(LucideVenetianMask),
|
|
},
|
|
condition: () =>
|
|
team.pg?.is_desk_user && group.pg.team !== team.name,
|
|
onClick() {
|
|
switchToTeam(group.pg.team);
|
|
},
|
|
},
|
|
{
|
|
label: group.pg?.deploy_information?.last_deploy
|
|
? 'Update Available'
|
|
: 'Deploy Now',
|
|
slots: {
|
|
prefix: group.pg?.deploy_information?.last_deploy
|
|
? icon(LucideHardDriveDownload)
|
|
: icon(LucideRocket),
|
|
},
|
|
variant: 'solid',
|
|
condition: () =>
|
|
!group.pg.deploy_information.deploy_in_progress &&
|
|
group.pg.deploy_information.update_available &&
|
|
['Awaiting Deploy', 'Active'].includes(group.pg.status),
|
|
onClick() {
|
|
let UpdateReleaseGroupDialog = defineAsyncComponent(
|
|
() => import('../components/group/UpdateReleaseGroupDialog.vue'),
|
|
);
|
|
renderDialog(
|
|
h(UpdateReleaseGroupDialog, {
|
|
bench: group.name,
|
|
lastDeploy: group.pg?.deploy_information?.last_deploy,
|
|
onSuccess(candidate) {
|
|
group.pg.deploy_information.deploy_in_progress = true;
|
|
if (candidate) {
|
|
group.pg.deploy_information.last_deploy = {
|
|
name: candidate,
|
|
};
|
|
}
|
|
},
|
|
}),
|
|
);
|
|
},
|
|
},
|
|
{
|
|
label: 'Deploy in progress',
|
|
slots: {
|
|
prefix: () => h(LoadingIndicator, { class: 'w-4 h-4' }),
|
|
},
|
|
theme: 'green',
|
|
condition: () => group.pg.deploy_information.deploy_in_progress,
|
|
route: {
|
|
name: 'Deploy Candidate',
|
|
params: { id: group.pg?.deploy_information?.last_deploy?.name },
|
|
},
|
|
},
|
|
{
|
|
label: 'Options',
|
|
condition: () => team.pg?.is_desk_user,
|
|
options: [
|
|
{
|
|
label: 'View in Desk',
|
|
icon: icon('external-link'),
|
|
condition: () => team.pg?.is_desk_user,
|
|
onClick() {
|
|
window.open(
|
|
`${window.location.protocol}//${window.location.host}/app/release-group/${group.name}`,
|
|
'_blank',
|
|
);
|
|
},
|
|
},
|
|
],
|
|
},
|
|
];
|
|
},
|
|
},
|
|
routes: [
|
|
{
|
|
name: 'Deploy Candidate',
|
|
path: 'deploys/:id',
|
|
component: () => import('../pages/DeployCandidate.vue'),
|
|
},
|
|
{
|
|
name: 'Release Group Job',
|
|
path: 'jobs/:id',
|
|
component: () => import('../pages/JobPage.vue'),
|
|
},
|
|
],
|
|
};
|