forked from cerc-io/snowballtools-base
Compare commits
3 Commits
78c37678e2
...
a401e09781
Author | SHA1 | Date | |
---|---|---|---|
a401e09781 | |||
48122d8497 | |||
dc6d992c44 |
@ -34,8 +34,9 @@ const nanoid = customAlphabet(lowercase + numbers, 8);
|
|||||||
// TODO: Fix order of methods
|
// TODO: Fix order of methods
|
||||||
export class Database {
|
export class Database {
|
||||||
private dataSource: DataSource;
|
private dataSource: DataSource;
|
||||||
|
private projectDomain: string;
|
||||||
|
|
||||||
constructor({ dbPath }: DatabaseConfig) {
|
constructor({ dbPath }: DatabaseConfig, { projectDomain }: MiscConfig) {
|
||||||
this.dataSource = new DataSource({
|
this.dataSource = new DataSource({
|
||||||
type: 'better-sqlite3',
|
type: 'better-sqlite3',
|
||||||
database: dbPath,
|
database: dbPath,
|
||||||
@ -43,6 +44,8 @@ export class Database {
|
|||||||
synchronize: true,
|
synchronize: true,
|
||||||
logging: false
|
logging: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.projectDomain = projectDomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
async init(): Promise<void> {
|
async init(): Promise<void> {
|
||||||
@ -488,13 +491,13 @@ export class Database {
|
|||||||
return projectRepository.save(newProject);
|
return projectRepository.save(newProject);
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveProject(project: Project): Promise<Project> {
|
async saveProject (project: Project): Promise<Project> {
|
||||||
const projectRepository = this.dataSource.getRepository(Project);
|
const projectRepository = this.dataSource.getRepository(Project);
|
||||||
|
|
||||||
return projectRepository.save(project);
|
return projectRepository.save(project);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateProjectById(
|
async updateProjectById (
|
||||||
projectId: string,
|
projectId: string,
|
||||||
data: DeepPartial<Project>
|
data: DeepPartial<Project>
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
@ -580,22 +583,17 @@ export class Database {
|
|||||||
return domains;
|
return domains;
|
||||||
}
|
}
|
||||||
|
|
||||||
async addDeployer(data: DeepPartial<Deployer>): Promise<Deployer> {
|
async addDeployer (data: DeepPartial<Deployer>): Promise<Deployer> {
|
||||||
const deployerRepository = this.dataSource.getRepository(Deployer);
|
const deployerRepository = this.dataSource.getRepository(Deployer);
|
||||||
const newDomain = await deployerRepository.save(data);
|
const newDomain = await deployerRepository.save(data);
|
||||||
|
|
||||||
return newDomain;
|
return newDomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDeployers(): Promise<Deployer[]> {
|
async getDeployerById (deployerId: string): Promise<Deployer | null> {
|
||||||
const deployerRepository = this.dataSource.getRepository(Deployer);
|
const deployerRepository = this.dataSource.getRepository(Deployer);
|
||||||
const deployers = await deployerRepository.find();
|
|
||||||
return deployers;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDeployerByLRN(deployerLrn: string): Promise<Deployer | null> {
|
const deployer = await deployerRepository.findOne({ where: { deployerId } });
|
||||||
const deployerRepository = this.dataSource.getRepository(Deployer);
|
|
||||||
const deployer = await deployerRepository.findOne({ where: { deployerLrn } });
|
|
||||||
|
|
||||||
return deployer;
|
return deployer;
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,10 @@ import { Project } from './Project';
|
|||||||
@Entity()
|
@Entity()
|
||||||
export class Deployer {
|
export class Deployer {
|
||||||
@PrimaryColumn('varchar')
|
@PrimaryColumn('varchar')
|
||||||
deployerLrn!: string;
|
deployerId!: string;
|
||||||
|
|
||||||
@Column('varchar')
|
@Column('varchar')
|
||||||
deployerId!: string;
|
deployerLrn!: string;
|
||||||
|
|
||||||
@Column('varchar')
|
@Column('varchar')
|
||||||
deployerApiUrl!: string;
|
deployerApiUrl!: string;
|
||||||
|
@ -129,7 +129,7 @@ export class Deployment {
|
|||||||
applicationDeploymentRemovalRecordData!: AppDeploymentRemovalRecordAttributes | null;
|
applicationDeploymentRemovalRecordData!: AppDeploymentRemovalRecordAttributes | null;
|
||||||
|
|
||||||
@ManyToOne(() => Deployer)
|
@ManyToOne(() => Deployer)
|
||||||
@JoinColumn({ name: 'deployerLrn' })
|
@JoinColumn({ name: 'deployerId' })
|
||||||
deployer!: Deployer;
|
deployer!: Deployer;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
|
@ -25,7 +25,7 @@ export const main = async (): Promise<void> => {
|
|||||||
clientSecret: gitHub.oAuth.clientSecret,
|
clientSecret: gitHub.oAuth.clientSecret,
|
||||||
});
|
});
|
||||||
|
|
||||||
const db = new Database(database);
|
const db = new Database(database, misc);
|
||||||
await db.init();
|
await db.init();
|
||||||
|
|
||||||
const registry = new Registry(registryConfig);
|
const registry = new Registry(registryConfig);
|
||||||
|
@ -283,7 +283,6 @@ export class Registry {
|
|||||||
this.registryConfig.privateKey,
|
this.registryConfig.privateKey,
|
||||||
fee
|
fee
|
||||||
);
|
);
|
||||||
|
|
||||||
log(`Application deployment request record published: ${result.id}`);
|
log(`Application deployment request record published: ${result.id}`);
|
||||||
log('Application deployment request data:', applicationDeploymentRequest);
|
log('Application deployment request data:', applicationDeploymentRequest);
|
||||||
|
|
||||||
|
@ -76,10 +76,6 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
|||||||
) => {
|
) => {
|
||||||
return service.getAuctionData(auctionId);
|
return service.getAuctionData(auctionId);
|
||||||
},
|
},
|
||||||
|
|
||||||
deployers: async (_: any, __: any, context: any) => {
|
|
||||||
return service.getDeployers();
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: Return error in GQL response
|
// TODO: Return error in GQL response
|
||||||
|
@ -134,8 +134,8 @@ type EnvironmentVariable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Deployer {
|
type Deployer {
|
||||||
deployerLrn: String!
|
|
||||||
deployerId: String!
|
deployerId: String!
|
||||||
|
deployerLrn: String!
|
||||||
deployerApiUrl: String!
|
deployerApiUrl: String!
|
||||||
createdAt: String!
|
createdAt: String!
|
||||||
updatedAt: String!
|
updatedAt: String!
|
||||||
@ -257,7 +257,6 @@ type Query {
|
|||||||
searchProjects(searchText: String!): [Project!]
|
searchProjects(searchText: String!): [Project!]
|
||||||
getAuctionData(auctionId: String!): Auction!
|
getAuctionData(auctionId: String!): Auction!
|
||||||
domains(projectId: String!, filter: FilterDomainsInput): [Domain]
|
domains(projectId: String!, filter: FilterDomainsInput): [Domain]
|
||||||
deployers: [Deployer]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
|
@ -21,7 +21,6 @@ import {
|
|||||||
AppDeploymentRecord,
|
AppDeploymentRecord,
|
||||||
AppDeploymentRemovalRecord,
|
AppDeploymentRemovalRecord,
|
||||||
AuctionParams,
|
AuctionParams,
|
||||||
DeployerRecord,
|
|
||||||
EnvironmentVariables,
|
EnvironmentVariables,
|
||||||
GitPushEventPayload,
|
GitPushEventPayload,
|
||||||
} from './types';
|
} from './types';
|
||||||
@ -310,13 +309,35 @@ export class Service {
|
|||||||
if (!deployerRecords) {
|
if (!deployerRecords) {
|
||||||
log(`No winning deployer for auction ${project!.auctionId}`);
|
log(`No winning deployer for auction ${project!.auctionId}`);
|
||||||
} else {
|
} else {
|
||||||
const deployers = await this.saveDeployersByDeployerRecords(deployerRecords);
|
const deployerIds = [];
|
||||||
for (const deployer of deployers) {
|
|
||||||
log(`Creating deployment for deployer ${deployer.deployerLrn}`);
|
for (const record of deployerRecords) {
|
||||||
await this.createDeploymentFromAuction(project, deployer);
|
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
|
// Update project with deployer
|
||||||
await this.updateProjectWithDeployer(project.id, deployer);
|
await this.updateProjectWithDeployer(project.id, deployer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const deployer of deployerIds) {
|
||||||
|
log(`Creating deployment for deployer LRN ${deployer}`);
|
||||||
|
await this.createDeploymentFromAuction(project, deployer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -623,12 +644,12 @@ export class Service {
|
|||||||
|
|
||||||
let deployer;
|
let deployer;
|
||||||
if (deployerLrn) {
|
if (deployerLrn) {
|
||||||
deployer = await this.db.getDeployerByLRN(deployerLrn);
|
deployer = await this.createDeployerFromLRN(deployerLrn);
|
||||||
} else {
|
} else {
|
||||||
deployer = data.deployer;
|
deployer = data.deployer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newDeployment = await this.createDeploymentFromData(userId, data, deployer!.deployerLrn!, applicationRecordId, applicationRecordData);
|
const newDeployment = await this.createDeploymentFromData(userId, data, deployer!.deployerId!, applicationRecordId, applicationRecordData);
|
||||||
|
|
||||||
const { repo, repoUrl } = await getRepoDetails(octokit, data.project.repository, data.commitHash);
|
const { repo, repoUrl } = await getRepoDetails(octokit, data.project.repository, data.commitHash);
|
||||||
const environmentVariablesObj = await this.getEnvVariables(data.project!.id!);
|
const environmentVariablesObj = await this.getEnvVariables(data.project!.id!);
|
||||||
@ -666,7 +687,7 @@ export class Service {
|
|||||||
|
|
||||||
async createDeploymentFromAuction(
|
async createDeploymentFromAuction(
|
||||||
project: DeepPartial<Project>,
|
project: DeepPartial<Project>,
|
||||||
deployer: Deployer
|
deployerId: string
|
||||||
): Promise<Deployment> {
|
): Promise<Deployment> {
|
||||||
const octokit = await this.getOctokit(project.ownerId!);
|
const octokit = await this.getOctokit(project.ownerId!);
|
||||||
const [owner, repo] = project.repository!.split('/');
|
const [owner, repo] = project.repository!.split('/');
|
||||||
@ -692,6 +713,7 @@ export class Service {
|
|||||||
const applicationRecordId = record.id;
|
const applicationRecordId = record.id;
|
||||||
const applicationRecordData = record.attributes;
|
const applicationRecordData = record.attributes;
|
||||||
|
|
||||||
|
const deployer = await this.db.getDeployerById(deployerId);
|
||||||
const deployerLrn = deployer!.deployerLrn
|
const deployerLrn = deployer!.deployerLrn
|
||||||
|
|
||||||
// Create deployment with prod branch and latest commit
|
// Create deployment with prod branch and latest commit
|
||||||
@ -704,7 +726,7 @@ export class Service {
|
|||||||
commitMessage: latestCommit.commit.message,
|
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!);
|
const environmentVariablesObj = await this.getEnvVariables(project!.id!);
|
||||||
// To set project DNS
|
// To set project DNS
|
||||||
@ -745,7 +767,7 @@ export class Service {
|
|||||||
async createDeploymentFromData(
|
async createDeploymentFromData(
|
||||||
userId: string,
|
userId: string,
|
||||||
data: DeepPartial<Deployment>,
|
data: DeepPartial<Deployment>,
|
||||||
deployerLrn: string,
|
deployerId: string,
|
||||||
applicationRecordId: string,
|
applicationRecordId: string,
|
||||||
applicationRecordData: ApplicationRecord,
|
applicationRecordData: ApplicationRecord,
|
||||||
): Promise<Deployment> {
|
): Promise<Deployment> {
|
||||||
@ -763,7 +785,7 @@ export class Service {
|
|||||||
id: userId,
|
id: userId,
|
||||||
}),
|
}),
|
||||||
deployer: Object.assign(new Deployer(), {
|
deployer: Object.assign(new Deployer(), {
|
||||||
deployerLrn,
|
deployerId,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -772,6 +794,30 @@ export class Service {
|
|||||||
return newDeployment;
|
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(
|
async updateProjectWithDeployer(
|
||||||
projectId: string,
|
projectId: string,
|
||||||
deployer: Deployer
|
deployer: Deployer
|
||||||
@ -1043,7 +1089,7 @@ export class Service {
|
|||||||
let newDeployment: Deployment;
|
let newDeployment: Deployment;
|
||||||
|
|
||||||
if (oldDeployment.project.auctionId) {
|
if (oldDeployment.project.auctionId) {
|
||||||
newDeployment = await this.createDeploymentFromAuction(oldDeployment.project, oldDeployment.deployer);
|
newDeployment = await this.createDeploymentFromAuction(oldDeployment.project, oldDeployment.deployer.deployerId);
|
||||||
} else {
|
} else {
|
||||||
newDeployment = await this.createDeployment(user.id, octokit,
|
newDeployment = await this.createDeployment(user.id, octokit,
|
||||||
{
|
{
|
||||||
@ -1323,50 +1369,4 @@ export class Service {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDeployers(): Promise<Deployer[]> {
|
|
||||||
const dbDeployers = await this.db.getDeployers();
|
|
||||||
|
|
||||||
if (dbDeployers.length > 0) {
|
|
||||||
// Call asynchronously to fetch the records from the registry and update the DB
|
|
||||||
this.updateDeployersFromRegistry();
|
|
||||||
return dbDeployers;
|
|
||||||
} else {
|
|
||||||
// Fetch from the registry and populate empty DB
|
|
||||||
return await this.updateDeployersFromRegistry();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateDeployersFromRegistry(): Promise<Deployer[]> {
|
|
||||||
const deployerRecords = await this.laconicRegistry.getDeployerRecordsByFilter({});
|
|
||||||
await this.saveDeployersByDeployerRecords(deployerRecords);
|
|
||||||
|
|
||||||
return await this.db.getDeployers();
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveDeployersByDeployerRecords(deployerRecords: DeployerRecord[]): Promise<Deployer[]> {
|
|
||||||
const deployers: Deployer[] = [];
|
|
||||||
|
|
||||||
for (const record of deployerRecords) {
|
|
||||||
if (record.names.length > 0) {
|
|
||||||
const deployerId = record.id;
|
|
||||||
const deployerLrn = record.names[0];
|
|
||||||
const deployerApiUrl = record.attributes.apiUrl;
|
|
||||||
const baseDomain = deployerApiUrl.substring(deployerApiUrl.indexOf('.') + 1);
|
|
||||||
|
|
||||||
const deployerData = {
|
|
||||||
deployerLrn,
|
|
||||||
deployerId,
|
|
||||||
deployerApiUrl,
|
|
||||||
baseDomain
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Update deployers table in a separate job
|
|
||||||
const deployer = await this.db.addDeployer(deployerData);
|
|
||||||
deployers.push(deployer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return deployers;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ async function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for await (const deployment of deployments) {
|
for await (const deployment of deployments) {
|
||||||
const url = `https://${(deployment.project.name).toLowerCase()}-${deployment.id}.${deployment.deployer.baseDomain}`;
|
const url = `https://${deployment.project.name}-${deployment.id}.${misc.projectDomain}`;
|
||||||
|
|
||||||
const applicationDeploymentRecord = {
|
const applicationDeploymentRecord = {
|
||||||
type: 'ApplicationDeploymentRecord',
|
type: 'ApplicationDeploymentRecord',
|
||||||
@ -73,7 +73,7 @@ async function main() {
|
|||||||
|
|
||||||
// Remove deployment for project subdomain if deployment is for production environment
|
// Remove deployment for project subdomain if deployment is for production environment
|
||||||
if (deployment.environment === Environment.Production) {
|
if (deployment.environment === Environment.Production) {
|
||||||
applicationDeploymentRecord.url = `https://${deployment.project.name}.${deployment.deployer.baseDomain}`;
|
applicationDeploymentRecord.url = `https://${deployment.project.name}.${deployment.baseDomain}`;
|
||||||
|
|
||||||
await registry.setRecord(
|
await registry.setRecord(
|
||||||
{
|
{
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
import ConfirmDialog, {
|
|
||||||
ConfirmDialogProps,
|
|
||||||
} from 'components/shared/ConfirmDialog';
|
|
||||||
import { ArrowRightCircleFilledIcon, LoadingIcon } from 'components/shared/CustomIcon';
|
|
||||||
|
|
||||||
interface DeleteDeploymentDialogProps extends ConfirmDialogProps {
|
|
||||||
isConfirmButtonLoading?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DeleteDeploymentDialog = ({
|
|
||||||
open,
|
|
||||||
handleCancel,
|
|
||||||
handleConfirm,
|
|
||||||
isConfirmButtonLoading,
|
|
||||||
...props
|
|
||||||
}: DeleteDeploymentDialogProps) => {
|
|
||||||
return (
|
|
||||||
<ConfirmDialog
|
|
||||||
{...props}
|
|
||||||
dialogTitle="Delete deployment?"
|
|
||||||
handleCancel={handleCancel}
|
|
||||||
open={open}
|
|
||||||
confirmButtonTitle={isConfirmButtonLoading ? "Deleting deployment" : "Yes, delete deployment"}
|
|
||||||
handleConfirm={handleConfirm}
|
|
||||||
confirmButtonProps={{
|
|
||||||
variant: 'danger',
|
|
||||||
disabled: isConfirmButtonLoading,
|
|
||||||
rightIcon: isConfirmButtonLoading ? (
|
|
||||||
<LoadingIcon className="animate-spin" />
|
|
||||||
) : (
|
|
||||||
<ArrowRightCircleFilledIcon />
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<p className="text-sm text-elements-high-em">
|
|
||||||
Once deleted, the deployment will not be accessible.
|
|
||||||
</p>
|
|
||||||
</ConfirmDialog>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,11 +1,9 @@
|
|||||||
import { useCallback, useState, useEffect } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { useForm, Controller } from 'react-hook-form';
|
import { useForm, Controller } from 'react-hook-form';
|
||||||
import { FormProvider, FieldValues } from 'react-hook-form';
|
import { FormProvider, FieldValues } from 'react-hook-form';
|
||||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||||
import { useMediaQuery } from 'usehooks-ts';
|
import { useMediaQuery } from 'usehooks-ts';
|
||||||
import { AddEnvironmentVariableInput, AuctionParams, Deployer } from 'gql-client';
|
import { AddEnvironmentVariableInput, AuctionParams } from 'gql-client';
|
||||||
|
|
||||||
import { Select, MenuItem, FormControl, FormHelperText } from '@mui/material';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ArrowRightCircleFilledIcon,
|
ArrowRightCircleFilledIcon,
|
||||||
@ -13,6 +11,7 @@ import {
|
|||||||
} from 'components/shared/CustomIcon';
|
} from 'components/shared/CustomIcon';
|
||||||
import { Heading } from '../../shared/Heading';
|
import { Heading } from '../../shared/Heading';
|
||||||
import { Button } from '../../shared/Button';
|
import { Button } from '../../shared/Button';
|
||||||
|
import { Select, SelectOption } from 'components/shared/Select';
|
||||||
import { Input } from 'components/shared/Input';
|
import { Input } from 'components/shared/Input';
|
||||||
import { useToast } from 'components/shared/Toast';
|
import { useToast } from 'components/shared/Toast';
|
||||||
import { useGQLClient } from '../../../context/GQLClientContext';
|
import { useGQLClient } from '../../../context/GQLClientContext';
|
||||||
@ -31,8 +30,6 @@ type ConfigureFormValues = ConfigureDeploymentFormValues &
|
|||||||
|
|
||||||
const Configure = () => {
|
const Configure = () => {
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [deployers, setDeployers] = useState<Deployer[]>([]);
|
|
||||||
|
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const templateId = searchParams.get('templateId');
|
const templateId = searchParams.get('templateId');
|
||||||
const queryParams = new URLSearchParams(location.search);
|
const queryParams = new URLSearchParams(location.search);
|
||||||
@ -51,7 +48,7 @@ const Configure = () => {
|
|||||||
const client = useGQLClient();
|
const client = useGQLClient();
|
||||||
|
|
||||||
const methods = useForm<ConfigureFormValues>({
|
const methods = useForm<ConfigureFormValues>({
|
||||||
defaultValues: { option: 'Auction' },
|
defaultValues: { option: 'LRN' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectedOption = methods.watch('option');
|
const selectedOption = methods.watch('option');
|
||||||
@ -156,33 +153,24 @@ const Configure = () => {
|
|||||||
if (templateId) {
|
if (templateId) {
|
||||||
createFormData.option === 'Auction'
|
createFormData.option === 'Auction'
|
||||||
? navigate(
|
? navigate(
|
||||||
`/${orgSlug}/projects/create/success/${projectId}?isAuction=true`,
|
`/${orgSlug}/projects/create/success/${projectId}?isAuction=true`,
|
||||||
)
|
)
|
||||||
: navigate(
|
: navigate(
|
||||||
`/${orgSlug}/projects/create/template/deploy?projectId=${projectId}&templateId=${templateId}`,
|
`/${orgSlug}/projects/create/template/deploy?projectId=${projectId}&templateId=${templateId}`,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
createFormData.option === 'Auction'
|
createFormData.option === 'Auction'
|
||||||
? navigate(
|
? navigate(
|
||||||
`/${orgSlug}/projects/create/success/${projectId}?isAuction=true`,
|
`/${orgSlug}/projects/create/success/${projectId}?isAuction=true`,
|
||||||
)
|
)
|
||||||
: navigate(
|
: navigate(
|
||||||
`/${orgSlug}/projects/create/deploy?projectId=${projectId}`,
|
`/${orgSlug}/projects/create/deploy?projectId=${projectId}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[client, createProject, dismiss, toast],
|
[client, createProject, dismiss, toast],
|
||||||
);
|
);
|
||||||
|
|
||||||
const fetchDeployers = useCallback(async () => {
|
|
||||||
const res = await client.getDeployers()
|
|
||||||
setDeployers(res.deployers)
|
|
||||||
}, [client])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchDeployers()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-7 px-4 py-6">
|
<div className="space-y-7 px-4 py-6">
|
||||||
<div className="flex justify-between mb-6">
|
<div className="flex justify-between mb-6">
|
||||||
@ -207,14 +195,24 @@ const Configure = () => {
|
|||||||
control={methods.control}
|
control={methods.control}
|
||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<Select
|
<Select
|
||||||
value={value}
|
label="Configuration Options"
|
||||||
onChange={(event) => onChange(event.target.value)}
|
value={
|
||||||
size='small'
|
{
|
||||||
displayEmpty
|
value: value || 'LRN',
|
||||||
>
|
label:
|
||||||
<MenuItem value="LRN">Deployer LRN</MenuItem>
|
value === 'Auction'
|
||||||
<MenuItem value="Auction">Create Auction</MenuItem>
|
? 'Create Auction'
|
||||||
</Select>
|
: 'Deployer LRN',
|
||||||
|
} as SelectOption
|
||||||
|
}
|
||||||
|
onChange={(value) =>
|
||||||
|
onChange((value as SelectOption).value)
|
||||||
|
}
|
||||||
|
options={[
|
||||||
|
{ value: 'LRN', label: 'Deployer LRN' },
|
||||||
|
{ value: 'Auction', label: 'Create Auction' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -227,29 +225,15 @@ const Configure = () => {
|
|||||||
>
|
>
|
||||||
The app will be deployed by the configured deployer
|
The app will be deployed by the configured deployer
|
||||||
</Heading>
|
</Heading>
|
||||||
|
<span className="text-sm text-elements-high-em">
|
||||||
|
Enter LRN for deployer
|
||||||
|
</span>
|
||||||
<Controller
|
<Controller
|
||||||
name="lrn"
|
name="lrn"
|
||||||
control={methods.control}
|
control={methods.control}
|
||||||
rules={{ required: true }}
|
rules={{ required: true }}
|
||||||
render={({ field: { value, onChange }, fieldState }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<FormControl fullWidth error={Boolean(fieldState.error)}>
|
<Input value={value} onChange={onChange} />
|
||||||
<span className="text-sm text-elements-high-em mb-4">
|
|
||||||
Select deployer LRN
|
|
||||||
</span>
|
|
||||||
<Select
|
|
||||||
value={value}
|
|
||||||
onChange={(event) => onChange(event.target.value)}
|
|
||||||
displayEmpty
|
|
||||||
size='small'
|
|
||||||
>
|
|
||||||
{deployers.map((deployer) => (
|
|
||||||
<MenuItem key={deployer.deployerLrn} value={deployer.deployerLrn}>
|
|
||||||
{deployer.deployerLrn}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
{fieldState.error && <FormHelperText>{fieldState.error.message}</FormHelperText>}
|
|
||||||
</FormControl>
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -91,7 +91,7 @@ const DeploymentDetailsCard = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchDeploymentLogs = async () => {
|
const fetchDeploymentLogs = useCallback(async () => {
|
||||||
let url = `${deployment.deployer.deployerApiUrl}/log/${deployment.applicationDeploymentRequestId}`;
|
let url = `${deployment.deployer.deployerApiUrl}/log/${deployment.applicationDeploymentRequestId}`;
|
||||||
const res = await fetch(url, { cache: 'no-store' });
|
const res = await fetch(url, { cache: 'no-store' });
|
||||||
handleOpenDialog();
|
handleOpenDialog();
|
||||||
@ -99,7 +99,11 @@ const DeploymentDetailsCard = ({
|
|||||||
const logs = await res.text();
|
const logs = await res.text();
|
||||||
setDeploymentLogs(logs);
|
setDeploymentLogs(logs);
|
||||||
}
|
}
|
||||||
};
|
}, [
|
||||||
|
deployment.deployer.deployerApiUrl,
|
||||||
|
deployment.applicationDeploymentRequestId,
|
||||||
|
handleOpenDialog,
|
||||||
|
]);
|
||||||
|
|
||||||
const renderDeploymentStatus = useCallback(
|
const renderDeploymentStatus = useCallback(
|
||||||
(className?: string) => {
|
(className?: string) => {
|
||||||
@ -185,8 +189,8 @@ const DeploymentDetailsCard = ({
|
|||||||
type="orange"
|
type="orange"
|
||||||
initials={getInitials(deployment.createdBy.name ?? '')}
|
initials={getInitials(deployment.createdBy.name ?? '')}
|
||||||
className="lg:size-5 2xl:size-6"
|
className="lg:size-5 2xl:size-6"
|
||||||
// TODO: Add avatarUrl
|
// TODO: Add avatarUrl
|
||||||
// imageSrc={deployment.createdBy.avatarUrl}
|
// imageSrc={deployment.createdBy.avatarUrl}
|
||||||
></Avatar>
|
></Avatar>
|
||||||
</div>
|
</div>
|
||||||
<OverflownText
|
<OverflownText
|
||||||
|
@ -23,7 +23,6 @@ import { useGQLClient } from 'context/GQLClientContext';
|
|||||||
import { cn } from 'utils/classnames';
|
import { cn } from 'utils/classnames';
|
||||||
import { ChangeStateToProductionDialog } from 'components/projects/Dialog/ChangeStateToProductionDialog';
|
import { ChangeStateToProductionDialog } from 'components/projects/Dialog/ChangeStateToProductionDialog';
|
||||||
import { useToast } from 'components/shared/Toast';
|
import { useToast } from 'components/shared/Toast';
|
||||||
import { DeleteDeploymentDialog } from 'components/projects/Dialog/DeleteDeploymentDialog';
|
|
||||||
|
|
||||||
interface DeploymentMenuProps extends ComponentPropsWithRef<'div'> {
|
interface DeploymentMenuProps extends ComponentPropsWithRef<'div'> {
|
||||||
deployment: Deployment;
|
deployment: Deployment;
|
||||||
@ -47,8 +46,6 @@ export const DeploymentMenu = ({
|
|||||||
|
|
||||||
const [changeToProduction, setChangeToProduction] = useState(false);
|
const [changeToProduction, setChangeToProduction] = useState(false);
|
||||||
const [redeployToProduction, setRedeployToProduction] = useState(false);
|
const [redeployToProduction, setRedeployToProduction] = useState(false);
|
||||||
const [deleteDeploymentDialog, setDeleteDeploymentDialog] = useState(false);
|
|
||||||
const [isConfirmDeleteLoading, setIsConfirmDeleteLoading] = useState(false);
|
|
||||||
const [rollbackDeployment, setRollbackDeployment] = useState(false);
|
const [rollbackDeployment, setRollbackDeployment] = useState(false);
|
||||||
const [assignDomainDialog, setAssignDomainDialog] = useState(false);
|
const [assignDomainDialog, setAssignDomainDialog] = useState(false);
|
||||||
const [isConfirmButtonLoading, setConfirmButtonLoadingLoading] =
|
const [isConfirmButtonLoading, setConfirmButtonLoadingLoading] =
|
||||||
@ -119,11 +116,14 @@ export const DeploymentMenu = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const deleteDeployment = async () => {
|
const deleteDeployment = async () => {
|
||||||
|
toast({
|
||||||
|
id: 'deleting_deployment',
|
||||||
|
title: 'Deleting deployment....',
|
||||||
|
variant: 'success',
|
||||||
|
onDismiss: dismiss,
|
||||||
|
});
|
||||||
|
|
||||||
const isDeleted = await client.deleteDeployment(deployment.id);
|
const isDeleted = await client.deleteDeployment(deployment.id);
|
||||||
|
|
||||||
setIsConfirmDeleteLoading(false);
|
|
||||||
setDeleteDeploymentDialog((preVal) => !preVal);
|
|
||||||
|
|
||||||
if (isDeleted) {
|
if (isDeleted) {
|
||||||
await onUpdate();
|
await onUpdate();
|
||||||
toast({
|
toast({
|
||||||
@ -212,7 +212,7 @@ export const DeploymentMenu = ({
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
className="hover:bg-base-bg-emphasized flex items-center gap-3"
|
className="hover:bg-base-bg-emphasized flex items-center gap-3"
|
||||||
onClick={() => setDeleteDeploymentDialog((preVal) => !preVal)}
|
onClick={() => deleteDeployment()}
|
||||||
>
|
>
|
||||||
<CrossCircleIcon /> Delete deployment
|
<CrossCircleIcon /> Delete deployment
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
@ -265,15 +265,6 @@ export const DeploymentMenu = ({
|
|||||||
open={assignDomainDialog}
|
open={assignDomainDialog}
|
||||||
handleOpen={() => setAssignDomainDialog(!assignDomainDialog)}
|
handleOpen={() => setAssignDomainDialog(!assignDomainDialog)}
|
||||||
/>
|
/>
|
||||||
<DeleteDeploymentDialog
|
|
||||||
open={deleteDeploymentDialog}
|
|
||||||
handleConfirm={async () => {
|
|
||||||
setIsConfirmDeleteLoading(true);
|
|
||||||
await deleteDeployment();
|
|
||||||
}}
|
|
||||||
handleCancel={() => setDeleteDeploymentDialog((preVal) => !preVal)}
|
|
||||||
isConfirmButtonLoading={isConfirmDeleteLoading}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -17,16 +17,6 @@ import { Button, Heading, Tag } from 'components/shared';
|
|||||||
|
|
||||||
const WAIT_DURATION = 5000;
|
const WAIT_DURATION = 5000;
|
||||||
|
|
||||||
const DIALOG_STYLE = {
|
|
||||||
backgroundColor: 'rgba(0,0,0, .9)',
|
|
||||||
padding: '2em',
|
|
||||||
borderRadius: '0.5em',
|
|
||||||
marginLeft: '0.5em',
|
|
||||||
marginRight: '0.5em',
|
|
||||||
color: 'gray',
|
|
||||||
fontSize: 'small',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AuctionCard = ({ project }: { project: Project }) => {
|
export const AuctionCard = ({ project }: { project: Project }) => {
|
||||||
const [auctionStatus, setAuctionStatus] = useState<string>('');
|
const [auctionStatus, setAuctionStatus] = useState<string>('');
|
||||||
const [deployers, setDeployers] = useState<Deployer[]>([]);
|
const [deployers, setDeployers] = useState<Deployer[]>([]);
|
||||||
@ -96,6 +86,13 @@ export const AuctionCard = ({ project }: { project: Project }) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-between items-center mt-1">
|
||||||
|
<span className="text-elements-high-em text-sm font-medium tracking-tight">
|
||||||
|
Auction Status
|
||||||
|
</span>
|
||||||
|
<div className="ml-2">{renderAuctionStatus()}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-between items-center mt-2">
|
<div className="flex justify-between items-center mt-2">
|
||||||
<span className="text-elements-high-em text-sm font-medium tracking-tight">
|
<span className="text-elements-high-em text-sm font-medium tracking-tight">
|
||||||
Auction Id
|
Auction Id
|
||||||
@ -105,47 +102,29 @@ export const AuctionCard = ({ project }: { project: Project }) => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{deployers?.length > 0 && (
|
||||||
|
<div className="mt-3">
|
||||||
|
<span className="text-elements-high-em text-sm font-medium tracking-tight">
|
||||||
|
Deployer LRNs
|
||||||
|
</span>
|
||||||
|
{deployers.map((deployer, index) => (
|
||||||
|
<p key={index} className="text-elements-mid-em text-sm">
|
||||||
|
{'\u2022'} {deployer.deployerLrn}
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="flex justify-between items-center mt-1">
|
<div className="flex justify-between items-center mt-1">
|
||||||
<span className="text-elements-high-em text-sm font-medium tracking-tight">
|
<span className="text-elements-high-em text-sm font-medium tracking-tight">
|
||||||
Auction Status
|
Deployer Funds Status
|
||||||
</span>
|
</span>
|
||||||
<div className="ml-2">{renderAuctionStatus()}</div>
|
<div className="ml-2">
|
||||||
|
<Tag size="xs" type={fundsStatus ? 'positive' : 'emphasized'}>
|
||||||
|
{fundsStatus ? 'RELEASED' : 'LOCKED'}
|
||||||
|
</Tag>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{auctionStatus === 'completed' && (
|
|
||||||
<>
|
|
||||||
{deployers?.length > 0 ? (
|
|
||||||
<div>
|
|
||||||
<span className="text-elements-high-em text-sm font-medium tracking-tight">
|
|
||||||
Deployer LRNs
|
|
||||||
</span>
|
|
||||||
{deployers.map((deployer, index) => (
|
|
||||||
<p key={index} className="text-elements-mid-em text-sm">
|
|
||||||
{'\u2022'} {deployer.deployerLrn}
|
|
||||||
</p>
|
|
||||||
))}
|
|
||||||
|
|
||||||
<div className="flex justify-between items-center mt-1">
|
|
||||||
<span className="text-elements-high-em text-sm font-medium tracking-tight">
|
|
||||||
Deployer Funds Status
|
|
||||||
</span>
|
|
||||||
<div className="ml-2">
|
|
||||||
<Tag size="xs" type={fundsStatus ? 'positive' : 'emphasized'}>
|
|
||||||
{fundsStatus ? 'RELEASED' : 'LOCKED'}
|
|
||||||
</Tag>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="mt-3">
|
|
||||||
<span className="text-elements-high-em text-sm font-medium tracking-tight">
|
|
||||||
No winning deployers
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
@ -155,7 +134,7 @@ export const AuctionCard = ({ project }: { project: Project }) => {
|
|||||||
maxWidth="md"
|
maxWidth="md"
|
||||||
>
|
>
|
||||||
<DialogTitle>Auction Details</DialogTitle>
|
<DialogTitle>Auction Details</DialogTitle>
|
||||||
<DialogContent style={DIALOG_STYLE}>
|
<DialogContent>
|
||||||
{auctionDetails && (
|
{auctionDetails && (
|
||||||
<pre>{JSON.stringify(auctionDetails, null, 2)}</pre>
|
<pre>{JSON.stringify(auctionDetails, null, 2)}</pre>
|
||||||
)}
|
)}
|
||||||
|
@ -424,12 +424,4 @@ export class GQLClient {
|
|||||||
|
|
||||||
return data.getAuctionData;
|
return data.getAuctionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDeployers(): Promise<types.GetDeployersResponse> {
|
|
||||||
const { data } = await this.client.query({
|
|
||||||
query: queries.getDeployers,
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,9 @@ query ($projectId: String!) {
|
|||||||
prodBranch
|
prodBranch
|
||||||
auctionId
|
auctionId
|
||||||
deployers {
|
deployers {
|
||||||
deployerLrn
|
|
||||||
deployerId
|
|
||||||
deployerApiUrl
|
deployerApiUrl
|
||||||
|
deployerId
|
||||||
|
deployerLrn
|
||||||
}
|
}
|
||||||
fundsReleased
|
fundsReleased
|
||||||
framework
|
framework
|
||||||
@ -81,9 +81,9 @@ query ($organizationSlug: String!) {
|
|||||||
framework
|
framework
|
||||||
auctionId
|
auctionId
|
||||||
deployers {
|
deployers {
|
||||||
deployerLrn
|
|
||||||
deployerId
|
|
||||||
deployerApiUrl
|
deployerApiUrl
|
||||||
|
deployerId
|
||||||
|
deployerLrn
|
||||||
}
|
}
|
||||||
fundsReleased
|
fundsReleased
|
||||||
prodBranch
|
prodBranch
|
||||||
@ -145,9 +145,9 @@ query ($projectId: String!) {
|
|||||||
commitMessage
|
commitMessage
|
||||||
url
|
url
|
||||||
deployer {
|
deployer {
|
||||||
deployerLrn
|
|
||||||
deployerId
|
deployerId
|
||||||
deployerApiUrl
|
deployerLrn,
|
||||||
|
deployerApiUrl,
|
||||||
}
|
}
|
||||||
environment
|
environment
|
||||||
isCurrent
|
isCurrent
|
||||||
@ -208,9 +208,9 @@ query ($searchText: String!) {
|
|||||||
framework
|
framework
|
||||||
auctionId
|
auctionId
|
||||||
deployers {
|
deployers {
|
||||||
deployerLrn
|
|
||||||
deployerId
|
|
||||||
deployerApiUrl
|
deployerApiUrl
|
||||||
|
deployerId
|
||||||
|
deployerLrn
|
||||||
}
|
}
|
||||||
fundsReleased
|
fundsReleased
|
||||||
prodBranch
|
prodBranch
|
||||||
@ -307,13 +307,3 @@ query ($auctionId: String!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const getDeployers = gql`
|
|
||||||
query {
|
|
||||||
deployers {
|
|
||||||
deployerLrn
|
|
||||||
deployerId
|
|
||||||
deployerApiUrl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
@ -117,9 +117,9 @@ export type Deployment = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type Deployer = {
|
export type Deployer = {
|
||||||
deployerLrn: string;
|
|
||||||
deployerId: string;
|
|
||||||
deployerApiUrl: string;
|
deployerApiUrl: string;
|
||||||
|
deployerId: string;
|
||||||
|
deployerLrn: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OrganizationMember = {
|
export type OrganizationMember = {
|
||||||
@ -233,10 +233,6 @@ export type GetDomainsResponse = {
|
|||||||
domains: Domain[];
|
domains: Domain[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GetDeployersResponse = {
|
|
||||||
deployers: Deployer[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type SearchProjectsResponse = {
|
export type SearchProjectsResponse = {
|
||||||
searchProjects: Project[];
|
searchProjects: Project[];
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user