Display deployment build logs (#8)
All checks were successful
Lint / lint (20.x) (push) Successful in 4m53s

Part of [Service provider auctions for web deployments](https://www.notion.so/Service-provider-auctions-for-web-deployments-104a6b22d47280dbad51d28aa3a91d75)

Co-authored-by: Adw8 <adwaitgharpure@gmail.com>
Co-authored-by: Neeraj <neeraj.rtly@gmail.com>
Co-authored-by: IshaVenikar <ishavenikar7@gmail.com>
Reviewed-on: #8
This commit is contained in:
nabarun 2024-10-22 09:12:59 +00:00
parent ef26f9b39e
commit 5152952a45
14 changed files with 316 additions and 115 deletions

View File

@ -23,6 +23,7 @@ import { EnvironmentVariable } from './entity/EnvironmentVariable';
import { Domain } from './entity/Domain';
import { getEntities, loadAndSaveData } from './utils';
import { UserOrganization } from './entity/UserOrganization';
import { Deployer } from './entity/Deployer';
const ORGANIZATION_DATA_PATH = '../test/fixtures/organizations.json';
@ -215,7 +216,8 @@ export class Database {
relations: {
project: true,
domain: true,
createdBy: true
createdBy: true,
deployer: true,
},
where: {
project: {
@ -488,7 +490,13 @@ export class Database {
return projectRepository.save(newProject);
}
async updateProjectById(
async saveProject (project: Project): Promise<Project> {
const projectRepository = this.dataSource.getRepository(Project);
return projectRepository.save(project);
}
async updateProjectById (
projectId: string,
data: DeepPartial<Project>
): Promise<boolean> {
@ -573,4 +581,19 @@ export class Database {
return domains;
}
async addDeployer (data: DeepPartial<Deployer>): Promise<Deployer> {
const deployerRepository = this.dataSource.getRepository(Deployer);
const newDomain = await deployerRepository.save(data);
return newDomain;
}
async getDeployerById (deployerId: string): Promise<Deployer | null> {
const deployerRepository = this.dataSource.getRepository(Deployer);
const deployer = await deployerRepository.findOne({ where: { deployerId } });
return deployer;
}
}

View File

@ -0,0 +1,20 @@
import { Entity, PrimaryColumn, Column, ManyToMany } from 'typeorm';
import { Project } from './Project';
@Entity()
export class Deployer {
@PrimaryColumn('varchar')
deployerId!: string;
@Column('varchar')
deployerLrn!: string;
@Column('varchar')
deployerApiUrl!: string;
@Column('varchar')
baseDomain!: string;
@ManyToMany(() => Project, (project) => project.deployers)
projects!: Project[];
}

View File

@ -13,6 +13,7 @@ import {
import { Project } from './Project';
import { Domain } from './Domain';
import { User } from './User';
import { Deployer } from './Deployer';
import { AppDeploymentRecordAttributes, AppDeploymentRemovalRecordAttributes } from '../types';
export enum Environment {
@ -127,8 +128,9 @@ export class Deployment {
@Column('simple-json', { nullable: true })
applicationDeploymentRemovalRecordData!: AppDeploymentRemovalRecordAttributes | null;
@Column('varchar')
deployerLrn!: string;
@ManyToOne(() => Deployer)
@JoinColumn({ name: 'deployerId' })
deployer!: Deployer;
@Column({
enum: Environment
@ -138,9 +140,6 @@ export class Deployment {
@Column('boolean', { default: false })
isCurrent!: boolean;
@Column('varchar', { nullable: true })
baseDomain!: string | null;
@Column({
enum: DeploymentStatus
})

View File

@ -7,13 +7,16 @@ import {
ManyToOne,
JoinColumn,
OneToMany,
DeleteDateColumn
DeleteDateColumn,
JoinTable,
ManyToMany
} from 'typeorm';
import { User } from './User';
import { Organization } from './Organization';
import { ProjectMember } from './ProjectMember';
import { Deployment } from './Deployment';
import { Deployer } from './Deployer';
@Entity()
export class Project {
@ -49,8 +52,9 @@ export class Project {
@Column('varchar', { nullable: true })
auctionId!: string | null;
@Column({ type: 'simple-array', nullable: true })
deployerLrns!: string[] | null;
@ManyToMany(() => Deployer, (deployer) => (deployer.projects))
@JoinTable()
deployers!: Deployer[]
@Column('boolean', { default: false, nullable: true })
fundsReleased!: boolean;
@ -70,9 +74,6 @@ export class Project {
@Column('varchar')
icon!: string;
@Column({ type: 'simple-array', nullable: true })
baseDomains!: string[] | null;
@CreateDateColumn()
createdAt!: Date;

View File

@ -14,7 +14,7 @@ import {
ApplicationDeploymentRequest,
ApplicationDeploymentRemovalRequest
} from './entity/Deployment';
import { AppDeploymentRecord, AppDeploymentRemovalRecord, AuctionParams } from './types';
import { AppDeploymentRecord, AppDeploymentRemovalRecord, AuctionParams, DeployerRecord } from './types';
import { getConfig, getRepoDetails, sleep } from './utils';
const log = debug('snowball:registry');
@ -25,6 +25,7 @@ const APP_DEPLOYMENT_REQUEST_TYPE = 'ApplicationDeploymentRequest';
const APP_DEPLOYMENT_REMOVAL_REQUEST_TYPE = 'ApplicationDeploymentRemovalRequest';
const APP_DEPLOYMENT_RECORD_TYPE = 'ApplicationDeploymentRecord';
const APP_DEPLOYMENT_REMOVAL_RECORD_TYPE = 'ApplicationDeploymentRemovalRecord';
const WEBAPP_DEPLOYER_RECORD_TYPE = 'WebappDeployer'
const SLEEP_DURATION = 1000;
// TODO: Move registry code to registry-sdk/watcher-ts
@ -291,32 +292,29 @@ export class Registry {
};
}
async getAuctionWinningDeployers(
async getAuctionWinningDeployerRecords(
auctionId: string
): Promise<string[]> {
): Promise<DeployerRecord[]> {
const records = await this.registry.getAuctionsByIds([auctionId]);
const auctionResult = records[0];
let deployerLrns = [];
let deployerRecords = [];
const { winnerAddresses } = auctionResult;
for (const auctionWinner of winnerAddresses) {
const deployerRecords = await this.registry.queryRecords(
{
paymentAddress: auctionWinner,
},
true
);
const records = await this.getDeployerRecordsByFilter({
paymentAddress: auctionWinner,
});
for (const record of deployerRecords) {
if (record.names && record.names.length > 0) {
deployerLrns.push(record.names[0]);
for (const record of records) {
if (record.id) {
deployerRecords.push(record);
break;
}
}
}
return deployerLrns;
return deployerRecords;
}
async releaseDeployerFunds(
@ -359,6 +357,19 @@ export class Registry {
);
}
/**
* Fetch WebappDeployer Records by filter
*/
async getDeployerRecordsByFilter(filter: { [key: string]: any }): Promise<DeployerRecord[]> {
return this.registry.queryRecords(
{
type: WEBAPP_DEPLOYER_RECORD_TYPE,
...filter
},
true
);
}
/**
* Fetch ApplicationDeploymentRecords by filter
*/
@ -439,8 +450,8 @@ export class Registry {
const auctions = await this.registry.getAuctionsByIds(auctionIds);
const completedAuctions = auctions
.filter((auction: { id: string, status: string }) => auction.status === 'completed')
.map((auction: { id: string, status: string }) => auction.id);
.filter((auction: { id: string, status: string }) => auction.status === 'completed')
.map((auction: { id: string, status: string }) => auction.id);
return completedAuctions;
}

View File

@ -104,7 +104,8 @@ type Deployment {
commitMessage: String!
url: String
environment: Environment!
deployerLrn: String
deployer: Deployer
applicationDeploymentRequestId: String
isCurrent: Boolean!
baseDomain: String
status: DeploymentStatus!
@ -132,6 +133,14 @@ type EnvironmentVariable {
updatedAt: String!
}
type Deployer {
deployerId: String!
deployerLrn: String!
deployerApiUrl: String!
createdAt: String!
updatedAt: String!
}
type AuthResult {
token: String!
}

View File

@ -14,6 +14,7 @@ import { Project } from './entity/Project';
import { Permission, ProjectMember } from './entity/ProjectMember';
import { User } from './entity/User';
import { Registry } from './registry';
import { Deployer } from './entity/Deployer';
import { GitHubConfig, RegistryConfig } from './config';
import {
AddProjectFromTemplateInput,
@ -174,6 +175,7 @@ export class Service {
applicationDeploymentRequestId: record.attributes.request,
})),
relations: {
deployer: true,
project: true,
},
order: {
@ -193,37 +195,31 @@ export class Service {
const deploymentUpdatePromises = records.map(async (record) => {
const deployment = recordToDeploymentsMap[record.attributes.request];
const parts = record.attributes.url.replace('https://', '').split('.');
const baseDomain = parts.slice(1).join('.');
if (!deployment.project) {
log(`Project ${deployment.projectId} not found`);
return;
} else {
deployment.applicationDeploymentRecordId = record.id;
deployment.applicationDeploymentRecordData = record.attributes;
deployment.url = record.attributes.url;
deployment.status = DeploymentStatus.Ready;
deployment.isCurrent = deployment.environment === Environment.Production;
deployment.applicationDeploymentRecordId = record.id;
deployment.applicationDeploymentRecordData = record.attributes;
deployment.url = record.attributes.url;
deployment.baseDomain = baseDomain;
deployment.status = DeploymentStatus.Ready;
deployment.isCurrent = deployment.environment === Environment.Production;
await this.db.updateDeploymentById(deployment.id, deployment);
await this.db.updateDeploymentById(deployment.id, deployment);
// Release deployer funds on successful deployment
if (!deployment.project.fundsReleased) {
const fundsReleased = await this.releaseDeployerFundsByProjectId(deployment.projectId);
const baseDomains = deployment.project.baseDomains || [];
await this.db.updateProjectById(deployment.projectId, {
fundsReleased,
});
}
if (!baseDomains.includes(baseDomain)) {
baseDomains.push(baseDomain);
log(
`Updated deployment ${deployment.id} with URL ${record.attributes.url}`,
);
}
// Release deployer funds on successful deployment
if (!deployment.project.fundsReleased) {
const fundsReleased = await this.releaseDeployerFundsByProjectId(deployment.projectId);
await this.db.updateProjectById(deployment.projectId, {
baseDomains,
fundsReleased,
});
}
log(
`Updated deployment ${deployment.id} with URL ${record.attributes.url}`,
);
});
await Promise.all(deploymentUpdatePromises);
@ -235,7 +231,7 @@ export class Service {
for (const deployment of prodDeployments) {
const projectDeployments = await this.db.getDeploymentsByProjectId(deployment.projectId);
const oldDeployments = projectDeployments
.filter(projectDeployment => projectDeployment.deployerLrn === deployment.deployerLrn && projectDeployment.id !== deployment.id);
.filter(projectDeployment => projectDeployment.deployer.deployerLrn === deployment.deployer.deployerLrn && projectDeployment.id !== deployment.id);
for (const oldDeployment of oldDeployments) {
await this.db.updateDeployment(
{ id: oldDeployment.id },
@ -308,17 +304,37 @@ export class Service {
);
for (const project of projectsToBedeployed) {
const deployerLrns = await this.laconicRegistry.getAuctionWinningDeployers(project.auctionId!);
const deployerRecords = await this.laconicRegistry.getAuctionWinningDeployerRecords(project!.auctionId!);
if (!deployerLrns) {
if (!deployerRecords) {
log(`No winning deployer for auction ${project!.auctionId}`);
} else {
// Update project with deployer LRNs
await this.db.updateProjectById(project.id!, {
deployerLrns
});
const deployerIds = [];
for (const deployer of deployerLrns) {
for (const record of deployerRecords) {
const deployerId = record.id;
const deployerLrn = record.names[0];
deployerIds.push(deployerId);
const deployerApiUrl = record.attributes.apiUrl;
const baseDomain = deployerApiUrl.substring(deployerApiUrl.indexOf('.') + 1);
const deployerData = {
deployerId,
deployerLrn,
deployerApiUrl,
baseDomain
};
// Store the deployer in the DB
const deployer = await this.db.addDeployer(deployerData);
// Update project with deployer
await this.updateProjectWithDeployer(project.id, deployer);
}
for (const deployer of deployerIds) {
log(`Creating deployment for deployer LRN ${deployer}`);
await this.createDeploymentFromAuction(project, deployer);
}
@ -587,7 +603,7 @@ export class Service {
domain: prodBranchDomains[0],
commitHash: oldDeployment.commitHash,
commitMessage: oldDeployment.commitMessage,
deployerLrn: oldDeployment.deployerLrn
deployer: oldDeployment.deployer
});
return newDeployment;
@ -596,7 +612,8 @@ export class Service {
async createDeployment(
userId: string,
octokit: Octokit,
data: DeepPartial<Deployment>
data: DeepPartial<Deployment>,
deployerLrn?: string
): Promise<Deployment> {
assert(data.project?.repository, 'Project repository not found');
log(
@ -625,7 +642,14 @@ export class Service {
);
}
const newDeployment = await this.createDeploymentFromData(userId, data, data.deployerLrn!, applicationRecordId, applicationRecordData);
let deployer;
if (deployerLrn) {
deployer = await this.createDeployerFromLRN(deployerLrn);
} else {
deployer = data.deployer;
}
const newDeployment = await this.createDeploymentFromData(userId, data, deployer!.deployerId!, applicationRecordId, applicationRecordData);
const { repo, repoUrl } = await getRepoDetails(octokit, data.project.repository, data.commitHash);
const environmentVariablesObj = await this.getEnvVariables(data.project!.id!);
@ -639,7 +663,7 @@ export class Service {
repository: repoUrl,
environmentVariables: environmentVariablesObj,
dns: `${newDeployment.project.name}`,
lrn: data.deployerLrn!
lrn: deployer!.deployerLrn!
});
}
@ -648,7 +672,7 @@ export class Service {
deployment: newDeployment,
appName: repo,
repository: repoUrl,
lrn: data.deployerLrn!,
lrn: deployer!.deployerLrn!,
environmentVariables: environmentVariablesObj,
dns: `${newDeployment.project.name}-${newDeployment.id}`,
});
@ -663,7 +687,7 @@ export class Service {
async createDeploymentFromAuction(
project: DeepPartial<Project>,
deployerLrn: string
deployerId: string
): Promise<Deployment> {
const octokit = await this.getOctokit(project.ownerId!);
const [owner, repo] = project.repository!.split('/');
@ -689,6 +713,9 @@ export class Service {
const applicationRecordId = record.id;
const applicationRecordData = record.attributes;
const deployer = await this.db.getDeployerById(deployerId);
const deployerLrn = deployer!.deployerLrn
// Create deployment with prod branch and latest commit
const deploymentData = {
project,
@ -699,7 +726,7 @@ export class Service {
commitMessage: latestCommit.commit.message,
};
const newDeployment = await this.createDeploymentFromData(project.ownerId!, deploymentData, deployerLrn, applicationRecordId, applicationRecordData);
const newDeployment = await this.createDeploymentFromData(project.ownerId!, deploymentData, deployerId, applicationRecordId, applicationRecordData);
const environmentVariablesObj = await this.getEnvVariables(project!.id!);
// To set project DNS
@ -740,7 +767,7 @@ export class Service {
async createDeploymentFromData(
userId: string,
data: DeepPartial<Deployment>,
deployerLrn: string,
deployerId: string,
applicationRecordId: string,
applicationRecordData: ApplicationRecord,
): Promise<Deployment> {
@ -757,7 +784,9 @@ export class Service {
createdBy: Object.assign(new User(), {
id: userId,
}),
deployerLrn,
deployer: Object.assign(new Deployer(), {
deployerId,
}),
});
log(`Created deployment ${newDeployment.id}`);
@ -765,6 +794,50 @@ export class Service {
return newDeployment;
}
async createDeployerFromLRN(deployerLrn: string): Promise<Deployer | null> {
const records = await this.laconicRegistry.getRecordsByName(deployerLrn);
if (records.length === 0) {
log('No records found for deployer LRN:', deployerLrn);
return null;
}
const deployerId = records[0].id;
const deployerApiUrl = records[0].attributes.apiUrl;
const baseDomain = deployerApiUrl.substring(deployerApiUrl.indexOf('.') + 1);
const deployerData = {
deployerId,
deployerLrn,
deployerApiUrl,
baseDomain
};
const deployer = await this.db.addDeployer(deployerData);
return deployer;
}
async updateProjectWithDeployer(
projectId: string,
deployer: Deployer
): Promise<Deployer> {
const deploymentProject = await this.db.getProjects({
where: { id: projectId },
relations: ['deployers']
});
if (!deploymentProject[0].deployers) {
deploymentProject[0].deployers = [];
}
deploymentProject[0].deployers.push(deployer);
await this.db.saveProject(deploymentProject[0]);
return deployer;
}
async addProjectFromTemplate(
user: User,
organizationSlug: string,
@ -828,6 +901,7 @@ export class Service {
slug: organizationSlug,
},
});
if (!organization) {
throw new Error('Organization does not exist');
}
@ -858,15 +932,15 @@ export class Service {
domain: null,
commitHash: latestCommit.sha,
commitMessage: latestCommit.commit.message,
deployerLrn: lrn
};
if (auctionParams) {
const { applicationDeploymentAuctionId } = await this.laconicRegistry.createApplicationDeploymentAuction(repo, octokit, auctionParams!, deploymentData);
await this.updateProject(project.id, { auctionId: applicationDeploymentAuctionId })
await this.updateProject(project.id, { auctionId: applicationDeploymentAuctionId });
} else {
await this.createDeployment(user.id, octokit, deploymentData);
await this.updateProject(project.id, { deployerLrns: [lrn!] })
const newDeployment = await this.createDeployment(user.id, octokit, deploymentData, lrn);
// Update project with deployer
await this.updateProjectWithDeployer(newDeployment.projectId, newDeployment.deployer);
}
await this.createRepoHook(octokit, project);
@ -920,6 +994,9 @@ export class Service {
);
const projects = await this.db.getProjects({
where: { repository: repository.full_name },
relations: {
deployers: true,
}
});
if (!projects.length) {
@ -936,7 +1013,7 @@ export class Service {
branch,
});
const deployers = project.deployerLrns;
const deployers = project.deployers;
if (!deployers) {
log(`No deployer present for project ${project.id}`)
return;
@ -955,7 +1032,7 @@ export class Service {
domain,
commitHash: headCommit.id,
commitMessage: headCommit.message,
deployerLrn: deployer
deployer: deployer
},
);
}
@ -995,6 +1072,7 @@ export class Service {
relations: {
project: true,
domain: true,
deployer: true,
createdBy: true,
},
where: {
@ -1011,8 +1089,7 @@ export class Service {
let newDeployment: Deployment;
if (oldDeployment.project.auctionId) {
// TODO: Discuss creating applicationRecord for redeployments
newDeployment = await this.createDeploymentFromAuction(oldDeployment.project, oldDeployment.deployerLrn);
newDeployment = await this.createDeploymentFromAuction(oldDeployment.project, oldDeployment.deployer.deployerId);
} else {
newDeployment = await this.createDeployment(user.id, octokit,
{
@ -1023,7 +1100,7 @@ export class Service {
domain: oldDeployment.domain,
commitHash: oldDeployment.commitHash,
commitMessage: oldDeployment.commitMessage,
deployerLrn: oldDeployment.deployerLrn
deployer: oldDeployment.deployer
}
);
}
@ -1072,13 +1149,14 @@ export class Service {
},
relations: {
project: true,
deployer: true,
},
});
if (deployment && deployment.applicationDeploymentRecordId) {
// If deployment is current, remove deployment for project subdomain as well
if (deployment.isCurrent) {
const currentDeploymentURL = `https://${(deployment.project.name).toLowerCase()}.${deployment.baseDomain}`;
const currentDeploymentURL = `https://${(deployment.project.name).toLowerCase()}.${deployment.deployer.baseDomain}`;
// TODO: Store the latest DNS deployment record
const deploymentRecords =
@ -1101,14 +1179,14 @@ export class Service {
await this.laconicRegistry.createApplicationDeploymentRemovalRequest({
deploymentId: latestRecord.id,
deployerLrn: deployment.deployerLrn
deployerLrn: deployment.deployer.deployerLrn
});
}
const result =
await this.laconicRegistry.createApplicationDeploymentRemovalRequest({
deploymentId: deployment.applicationDeploymentRecordId,
deployerLrn: deployment.deployerLrn
deployerLrn: deployment.deployer.deployerLrn
});
await this.db.updateDeploymentById(deployment.id, {

View File

@ -82,3 +82,20 @@ export interface EnvironmentVariables {
key: string,
value: string,
}
export interface DeployerRecord {
id: string;
names: string[];
owners: string[];
bondId: string;
createTime: string;
expiryTime: string;
attributes: {
apiUrl: string;
name: string;
paymentAddress: string;
publicKey: string;
type: string;
version: string;
};
}

View File

@ -139,30 +139,8 @@ const Configure = () => {
const projectId = await createProject(createFormData, environmentVariables);
const { environmentVariables: isEnvironmentVariablesAdded } =
await client.getEnvironmentVariables(projectId);
await client.getEnvironmentVariables(projectId);
if (isEnvironmentVariablesAdded.length > 0) {
toast({
id:
createFormData.variables.length > 1
? 'env_variable_added'
: 'env_variables_added',
title:
createFormData.variables.length > 1
? `${createFormData.variables.length} variables added`
: `Variable added`,
variant: 'success',
onDismiss: dismiss,
});
} else {
toast({
id: 'env_variables_not_added',
title: 'Environment variables not added',
variant: 'error',
onDismiss: dismiss,
});
}
if (templateId) {
createFormData.option === 'Auction'
? navigate(

View File

@ -1,4 +1,4 @@
import { useCallback } from 'react';
import { useCallback, useState } from 'react';
import {
Deployment,
DeploymentStatus,
@ -6,6 +6,14 @@ import {
Environment,
Project,
} from 'gql-client';
import {
Dialog,
DialogTitle,
DialogContent,
DialogActions,
} from '@mui/material';
import { Avatar } from 'components/shared/Avatar';
import {
BranchStrokeIcon,
@ -18,12 +26,23 @@ import {
import { Heading } from 'components/shared/Heading';
import { OverflownText } from 'components/shared/OverflownText';
import { Tag, TagTheme } from 'components/shared/Tag';
import { Button } from 'components/shared/Button';
import { getInitials } from 'utils/geInitials';
import { relativeTimeMs } from 'utils/time';
import { SHORT_COMMIT_HASH_LENGTH } from '../../../../constants';
import { formatAddress } from '../../../../utils/format';
import { DeploymentMenu } from './DeploymentMenu';
const DEPLOYMENT_LOGS_STYLE = {
backgroundColor: "rgba(0,0,0, .9)",
padding: "2em",
borderRadius: "0.5em",
marginLeft: "0.5em",
marginRight: "0.5em",
color: "gray",
fontSize: "small",
};
interface DeployDetailsCardProps {
deployment: Deployment;
currentDeployment: Deployment;
@ -48,6 +67,12 @@ const DeploymentDetailsCard = ({
project,
prodBranchDomains,
}: DeployDetailsCardProps) => {
const [openDialog, setOpenDialog] = useState<boolean>(false);
const [deploymentLogs, setDeploymentLogs] = useState<string>();
const handleOpenDialog = () => setOpenDialog(true);
const handleCloseDialog = () => setOpenDialog(false);
const getIconByDeploymentStatus = (status: DeploymentStatus) => {
if (
status === DeploymentStatus.Building ||
@ -64,6 +89,14 @@ const DeploymentDetailsCard = ({
}
};
const fetchDeploymentLogs = useCallback(async () => {
let url = `${deployment.deployer.deployerApiUrl}/log/${deployment.applicationDeploymentRequestId}`;
const res = await fetch(url, { cache: 'no-store' });
const logs = await res.text();
setDeploymentLogs(logs);
handleOpenDialog();
}, [deployment.deployer.deployerApiUrl, deployment.applicationDeploymentRequestId, handleOpenDialog]);
const renderDeploymentStatus = useCallback(
(className?: string) => {
return (
@ -72,6 +105,7 @@ const DeploymentDetailsCard = ({
leftIcon={getIconByDeploymentStatus(deployment.status)}
size="xs"
type={STATUS_COLORS[deployment.status] ?? 'neutral'}
onClick={fetchDeploymentLogs}
>
{deployment.status}
</Tag>
@ -96,9 +130,9 @@ const DeploymentDetailsCard = ({
</OverflownText>
</Heading>
)}
{deployment.deployerLrn && (
{deployment.deployer.deployerLrn && (
<span className="text-sm text-elements-low-em tracking-tight block mt-2">
Deployer LRN: {deployment.deployerLrn}
Deployer LRN: {deployment.deployer.deployerLrn}
</span>
)}
<span className="text-sm text-elements-low-em tracking-tight block">
@ -167,6 +201,15 @@ const DeploymentDetailsCard = ({
prodBranchDomains={prodBranchDomains}
/>
</div>
<Dialog open={openDialog} onClose={handleCloseDialog} fullWidth maxWidth="md">
<DialogTitle>Deployment logs</DialogTitle>
<DialogContent style={DEPLOYMENT_LOGS_STYLE} >
{deploymentLogs && <pre >{deploymentLogs}</pre>}
</DialogContent>
<DialogActions>
<Button onClick={handleCloseDialog}>Close</Button>
</DialogActions>
</Dialog>
</div>
);
};

View File

@ -36,7 +36,11 @@ const deployment: Deployment = {
url: 'https://deploy1.example.com',
environment: Environment.Production,
isCurrent: true,
deployerLrn: 'lrn://example/deployers/webapp-deployer-api.test.com',
deployer: {
deployerApiUrl: 'https://webapp-deployer-api.example.com',
deployerId: 'bafyreicrtgmkir4evvvysxdqxddf2ftdq2wrzuodgvwnxr4rmubi4obdfu',
deployerLrn:'lrn://example/deployers/webapp-deployer-api.example.com'
},
status: DeploymentStatus.Ready,
createdBy: {
id: 'user1',
@ -49,6 +53,7 @@ const deployment: Deployment = {
},
createdAt: '1677676800', // 2023-03-01T12:00:00Z
updatedAt: '1677680400', // 2023-03-01T13:00:00Z
applicationDeploymentRequestId: 'bafyreiaycvq6imoppnpwdve4smj6t6ql5svt5zl3x6rimu4qwyzgjorize',
};
const domains: Domain[] = [

View File

@ -102,7 +102,12 @@ export const deployment0: Deployment = {
domain: domain0,
commitMessage: 'Commit Message',
createdBy: user,
deployerLrn: 'lrn://deployer.apps.snowballtools.com ',
deployer: {
deployerApiUrl: 'https://webapp-deployer-api.example.com',
deployerId: 'bafyreicrtgmkir4evvvysxdqxddf2ftdq2wrzuodgvwnxr4rmubi4obdfu',
deployerLrn:'lrn://deployer.apps.snowballtools.com '
},
applicationDeploymentRequestId: 'bafyreiaycvq6imoppnpwdve4smj6t6ql5svt5zl3x6rimu4qwyzgjorize',
};
export const project: Project = {

View File

@ -136,7 +136,11 @@ query ($projectId: String!) {
commitHash
commitMessage
url
deployerLrn
deployer {
deployerId
deployerLrn,
deployerApiUrl,
}
environment
isCurrent
baseDomain
@ -148,6 +152,7 @@ query ($projectId: String!) {
name
email
}
applicationDeploymentRequestId
}
}
`;

View File

@ -105,7 +105,7 @@ export type Deployment = {
commitHash: string;
commitMessage: string;
url?: string;
deployerLrn: string;
deployer: Deployer;
environment: Environment;
isCurrent: boolean;
baseDomain?: string;
@ -113,8 +113,15 @@ export type Deployment = {
createdBy: User;
createdAt: string;
updatedAt: string;
applicationDeploymentRequestId: string;
};
export type Deployer = {
deployerApiUrl: string;
deployerId: string;
deployerLrn: string;
}
export type OrganizationMember = {
id: string;
member: User;