From 9144d42f703aa96f67586e23b1468fef90adb7e0 Mon Sep 17 00:00:00 2001 From: Nabarun Gogoi Date: Wed, 14 Feb 2024 11:03:22 +0530 Subject: [PATCH] Set record data with repo commit hash and package.json content (#65) * Get latest commit hash from repo when adding project * Update UI/UX * Fill registry record with data from package.json * Add package json type * Correct record data based on laconic console * Update README --------- Co-authored-by: neeraj --- README.md | 22 +++-- packages/backend/package.json | 2 + packages/backend/src/entity/Deployment.ts | 14 ++-- packages/backend/src/entity/Project.ts | 10 +-- packages/backend/src/registry.ts | 84 ++++++++++++------- packages/backend/src/service.ts | 75 ++++++++++++++--- packages/backend/src/types.ts | 9 ++ .../backend/test/fixtures/deployments.json | 20 ++--- packages/backend/test/fixtures/projects.json | 20 ++--- .../src/components/projects/ProjectCard.tsx | 7 +- .../components/projects/ProjectSearchBar.tsx | 3 +- .../projects/create/ConnectAccount.tsx | 5 +- .../deployments/AssignDomainDialog.tsx | 4 +- .../deployments/DeploymentDetailsCard.tsx | 6 +- .../deployments/DeploymentDialogBodyCard.tsx | 4 +- packages/frontend/src/constants.ts | 2 + .../pages/org-slug/projects/create/Import.tsx | 5 +- .../org-slug/projects/create/Template.tsx | 10 ++- .../pages/org-slug/projects/id/Overview.tsx | 6 +- 19 files changed, 203 insertions(+), 105 deletions(-) create mode 100644 packages/backend/src/types.ts diff --git a/README.md b/README.md index 2cba10b..4db7583 100644 --- a/README.md +++ b/README.md @@ -77,21 +77,31 @@ # 0.0.0.0:32771 ``` -- Reserve authority for `snowball` +- Reserve authorities for `snowballtools` and `cerc-io` ```bash - laconic-so --stack fixturenet-laconic-loaded deploy exec cli "laconic cns authority reserve snowball" + laconic-so --stack fixturenet-laconic-loaded deploy exec cli "laconic cns authority reserve snowballtools" # {"success":true} ``` -- Set authority bond - ```bash - laconic-so --stack fixturenet-laconic-loaded deploy exec cli "laconic cns authority bond set snowball $BOND_ID" + laconic-so --stack fixturenet-laconic-loaded deploy exec cli "laconic cns authority reserve cerc-io" # {"success":true} ``` -- Start the server +- Set authority bond for `snowballtools` and `cerc-io` + + ```bash + laconic-so --stack fixturenet-laconic-loaded deploy exec cli "laconic cns authority bond set snowballtools $BOND_ID" + # {"success":true} + ``` + + ```bash + laconic-so --stack fixturenet-laconic-loaded deploy exec cli "laconic cns authority bond set cerc-io $BOND_ID" + # {"success":true} + ``` + +- Start the server in `packages/backend` ```bash yarn start diff --git a/packages/backend/package.json b/packages/backend/package.json index e8bb181..94fef45 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -16,8 +16,10 @@ "express": "^4.18.2", "fs-extra": "^11.2.0", "graphql": "^16.8.1", + "luxon": "^3.4.4", "nanoid": "3", "nanoid-dictionary": "^5.0.0-beta.1", + "octokit": "^3.1.2", "reflect-metadata": "^0.2.1", "semver": "^7.6.0", "toml": "^3.0.0", diff --git a/packages/backend/src/entity/Deployment.ts b/packages/backend/src/entity/Deployment.ts index c766fbe..51beb2e 100644 --- a/packages/backend/src/entity/Deployment.ts +++ b/packages/backend/src/entity/Deployment.ts @@ -28,13 +28,13 @@ export enum DeploymentStatus { export interface ApplicationRecord { type: string; version:string - name: string - description: string - homepage: string - license: string - author: string - repository: string, - app_version: string + name?: string + description?: string + homepage?: string + license?: string + author?: string + repository?: string[], + app_version?: string repository_ref: string app_type: string } diff --git a/packages/backend/src/entity/Project.ts b/packages/backend/src/entity/Project.ts index aa76c5d..ffef8a7 100644 --- a/packages/backend/src/entity/Project.ts +++ b/packages/backend/src/entity/Project.ts @@ -20,14 +20,8 @@ export interface ApplicationDeploymentRequest { version: string name: string application: string - config: { - env: {[key:string]: string} - }, - meta: { - note: string - repository: string - repository_ref: string - } + config: string, + meta: string } @Entity() diff --git a/packages/backend/src/registry.ts b/packages/backend/src/registry.ts index a88bac7..b0b8570 100644 --- a/packages/backend/src/registry.ts +++ b/packages/backend/src/registry.ts @@ -1,17 +1,19 @@ import debug from 'debug'; +import assert from 'assert'; import { inc as semverInc } from 'semver'; +import { DateTime } from 'luxon'; import { Registry as LaconicRegistry } from '@cerc-io/laconic-sdk'; import { RegistryConfig } from './config'; import { ApplicationDeploymentRequest } from './entity/Project'; import { ApplicationRecord } from './entity/Deployment'; +import { PackageJSON } from './types'; const log = debug('snowball:registry'); const APP_RECORD_TYPE = 'ApplicationRecord'; const DEPLOYMENT_RECORD_TYPE = 'ApplicationDeploymentRequest'; -const AUTHORITY_NAME = 'snowball'; // TODO: Move registry code to laconic-sdk/watcher-ts export class Registry { @@ -23,16 +25,21 @@ export class Registry { this.registry = new LaconicRegistry(registryConfig.gqlEndpoint, registryConfig.restEndpoint, registryConfig.chainId); } - async createApplicationRecord (data: { recordName: string, appType: string }): Promise<{registryRecordId: string, registryRecordData: ApplicationRecord}> { - // TODO: Get record name from repo package.json name - const recordName = data.recordName; - + async createApplicationRecord ({ + packageJSON, + commitHash, + appType + }: { + packageJSON: PackageJSON + appType: string, + commitHash: string + }): Promise<{registryRecordId: string, registryRecordData: ApplicationRecord}> { // Use laconic-sdk to publish record // Reference: https://git.vdb.to/cerc-io/test-progressive-web-app/src/branch/main/scripts/publish-app-record.sh // Fetch previous records const records = await this.registry.queryRecords({ type: APP_RECORD_TYPE, - name: recordName + name: packageJSON.name }, true); // Get next version of record @@ -40,23 +47,21 @@ export class Registry { const [latestBondRecord] = bondRecords.sort((a: any, b: any) => new Date(b.createTime).getTime() - new Date(a.createTime).getTime()); const nextVersion = semverInc(latestBondRecord?.attributes.version ?? '0.0.0', 'patch'); + assert(nextVersion, 'Application record version not valid'); + // Create record of type ApplicationRecord and publish const applicationRecord = { type: APP_RECORD_TYPE, - version: nextVersion ?? '', - name: recordName, - - // TODO: Get data from repo package.json - description: '', - homepage: '', - license: '', - author: '', - repository: '', - app_version: '0.1.0', - - // TODO: Get latest commit hash from repo production branch / deployment - repository_ref: '10ac6678e8372a05ad5bb1c34c34', - app_type: data.appType + version: nextVersion, + repository_ref: commitHash, + app_type: appType, + ...(packageJSON.name && { name: packageJSON.name }), + ...(packageJSON.description && { description: packageJSON.description }), + ...(packageJSON.homepage && { homepage: packageJSON.homepage }), + ...(packageJSON.license && { license: packageJSON.license }), + ...(packageJSON.author && { author: typeof packageJSON.author === 'object' ? JSON.stringify(packageJSON.author) : packageJSON.author }), + ...(packageJSON.repository && { repository: [packageJSON.repository] }), + ...(packageJSON.version && { app_version: packageJSON.version }) }; const result = await this.registry.setRecord( @@ -71,8 +76,8 @@ export class Registry { log('Application record data:', applicationRecord); - // TODO: Discuss computation of crn - const crn = this.getCrn(data.recordName); + // TODO: Discuss computation of CRN + const crn = this.getCrn(packageJSON.name ?? ''); await this.registry.setName({ cid: result.data.id, crn }, this.registryConfig.privateKey, this.registryConfig.fee); await this.registry.setName({ cid: result.data.id, crn: `${crn}@${applicationRecord.app_version}` }, this.registryConfig.privateKey, this.registryConfig.fee); @@ -81,7 +86,14 @@ export class Registry { return { registryRecordId: result.data.id, registryRecordData: applicationRecord }; } - async createApplicationDeploymentRequest (data: { appName: string }): Promise<{registryRecordId: string, registryRecordData: ApplicationDeploymentRequest}> { + async createApplicationDeploymentRequest (data: { + appName: string, + commitHash: string, + repository: string + }): Promise<{ + registryRecordId: string, + registryRecordData: ApplicationDeploymentRequest + }> { const crn = this.getCrn(data.appName); const records = await this.registry.resolveNames([crn]); const applicationRecord = records[0]; @@ -101,16 +113,17 @@ export class Registry { // dns: '$CERC_REGISTRY_DEPLOYMENT_SHORT_HOSTNAME', // deployment: '$CERC_REGISTRY_DEPLOYMENT_CRN', - config: { + // https://git.vdb.to/cerc-io/laconic-registry-cli/commit/129019105dfb93bebcea02fde0ed64d0f8e5983b + config: JSON.stringify({ env: { CERC_WEBAPP_DEBUG: `${applicationRecord.attributes.app_version}` } - }, - meta: { - note: `Added by Snowball @ ${(new Date()).toISOString()}`, - repository: applicationRecord.attributes.repository, - repository_ref: applicationRecord.attributes.repository_ref - } + }), + meta: JSON.stringify({ + note: `Added by Snowball @ ${DateTime.utc().toFormat('EEE LLL dd HH:mm:ss \'UTC\' yyyy')}`, + repository: data.repository, + repository_ref: data.commitHash + }) }; const result = await this.registry.setRecord( @@ -128,7 +141,14 @@ export class Registry { return { registryRecordId: result.data.id, registryRecordData: applicationDeploymentRequest }; } - getCrn (appName: string): string { - return `crn://${AUTHORITY_NAME}/applications/${appName}`; + getCrn (packageJsonName: string): string { + const [arg1, arg2] = packageJsonName.split('/'); + + if (arg2) { + const authority = arg1.replace('@', ''); + return `crn://${authority}/applications/${arg2}`; + } + + return `crn://${arg1}/applications/${arg1}`; } } diff --git a/packages/backend/src/service.ts b/packages/backend/src/service.ts index f46c1a5..0cb5593 100644 --- a/packages/backend/src/service.ts +++ b/packages/backend/src/service.ts @@ -1,6 +1,7 @@ import assert from 'assert'; import debug from 'debug'; import { DeepPartial, FindOptionsWhere } from 'typeorm'; +import { Octokit } from 'octokit'; import { OAuthApp } from '@octokit/oauth-app'; @@ -18,12 +19,12 @@ const log = debug('snowball:service'); export class Service { private db: Database; - private app: OAuthApp; + private oauthApp: OAuthApp; private registry: Registry; constructor (db: Database, app: OAuthApp, registry: Registry) { this.db = db; - this.app = app; + this.oauthApp = app; this.registry = registry; } @@ -35,6 +36,13 @@ export class Service { }); } + async getOctokit (userId: string): Promise { + const user = await this.db.getUser({ where: { id: userId } }); + assert(user && user.gitHubToken, 'User needs to be authenticated with GitHub token'); + + return new Octokit({ auth: user.gitHubToken }); + } + async getOrganizationsByUserId (userId: string): Promise { const dbOrganizations = await this.db.getOrganizationsByUserId(userId); return dbOrganizations; @@ -200,7 +208,10 @@ export class Service { await this.db.updateDeploymentById(oldCurrentDeployment.id, { isCurrent: false, domain: null }); } + const octokit = await this.getOctokit(userId); + const newDeployement = await this.createDeployment(userId, + octokit, { project: oldDeployment.project, isCurrent: true, @@ -213,10 +224,28 @@ export class Service { return newDeployement; } - async createDeployment (userId: string, data: DeepPartial): Promise { + async createDeployment (userId: string, octokit: Octokit, data: DeepPartial): Promise { + assert(data.project?.repository, 'Project repository not found'); + const [owner, repo] = data.project.repository.split('/'); + + const { data: packageJSONData } = await octokit.rest.repos.getContent({ + owner, + repo, + path: 'package.json', + ref: data.commitHash + }); + + if (!packageJSONData) { + throw new Error('Package.json file not found'); + } + + assert(!Array.isArray(packageJSONData) && packageJSONData.type === 'file'); + const packageJSON = JSON.parse(atob(packageJSONData.content)); + const { registryRecordId, registryRecordData } = await this.registry.createApplicationRecord({ - recordName: data.project?.name ?? '', - appType: data.project?.template ?? '' + packageJSON, + appType: data.project!.template!, + commitHash: data.commitHash! }); const newDeployement = await this.db.addDeployement({ @@ -250,24 +279,43 @@ export class Service { const project = await this.db.addProject(userId, organization.id, data); - // TODO: Get repository details from github - await this.createDeployment(userId, + const octokit = await this.getOctokit(userId); + const [owner, repo] = project.repository.split('/'); + + const { data: [latestCommit] } = await octokit.rest.repos.listCommits({ + owner, + repo, + sha: project.prodBranch, + per_page: 1 + }); + + const { data: repoDetails } = await octokit.rest.repos.get({ owner, repo }); + + // Create deployment with prod branch and latest commit + const newDeployment = await this.createDeployment(userId, + octokit, { project, isCurrent: true, branch: project.prodBranch, environment: Environment.Production, - // TODO: Set latest commit hash - commitHash: '', - domain: null + domain: null, + commitHash: latestCommit.sha }); - const { registryRecordId, registryRecordData } = await this.registry.createApplicationDeploymentRequest({ appName: project.name }); + const { registryRecordId, registryRecordData } = await this.registry.createApplicationDeploymentRequest( + { + appName: newDeployment.registryRecordData.name!, + commitHash: latestCommit.sha, + repository: repoDetails.git_url + }); await this.db.updateProjectById(project.id, { registryRecordId, registryRecordData }); + // TODO: Setup repo webhook for push events + return project; } @@ -311,7 +359,10 @@ export class Service { await this.db.updateDeploymentById(deploymentId, { domain: null, isCurrent: false }); + const octokit = await this.getOctokit(userId); + const newDeployement = await this.createDeployment(userId, + octokit, { project: oldDeployment.project, // TODO: Put isCurrent field in project @@ -435,7 +486,7 @@ export class Service { } async authenticateGitHub (code:string, userId: string): Promise<{token: string}> { - const { authentication: { token } } = await this.app.createToken({ + const { authentication: { token } } = await this.oauthApp.createToken({ code }); diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts new file mode 100644 index 0000000..9459c01 --- /dev/null +++ b/packages/backend/src/types.ts @@ -0,0 +1,9 @@ +export interface PackageJSON { + name?: string; + version?: string; + author?: string; + description?: string; + homepage?: string; + license?: string; + repository?: string; +} diff --git a/packages/backend/test/fixtures/deployments.json b/packages/backend/test/fixtures/deployments.json index 63c5adf..db24060 100644 --- a/packages/backend/test/fixtures/deployments.json +++ b/packages/backend/test/fixtures/deployments.json @@ -10,7 +10,7 @@ "registryRecordId": "qbafyrehvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", "registryRecordData": {}, "branch": "main", - "commitHash": "testXyz", + "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "url": "testProject-ffhae3zq.snowball.xyz" }, { @@ -24,7 +24,7 @@ "registryRecordId": "wbafyreihvzya6ovp4yfpkqnddkui2iw7thbhwq74lbqs7bhobvmfhrowoi", "registryRecordData": {}, "branch": "test", - "commitHash": "testXyz", + "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "url": "testProject-vehagei8.snowball.xyz" }, { @@ -38,7 +38,7 @@ "registryRecordId": "ebafyreihvzya6ovp4yfpkqnddkui2iw7t6bhwq74lbqs7bhobvmfhrowoi", "registryRecordData": {}, "branch": "test", - "commitHash": "testXyz", + "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "url": "testProject-qmgekyte.snowball.xyz" }, { @@ -52,7 +52,7 @@ "registryRecordId": "rbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhw74lbqs7bhobvmfhrowoi", "registryRecordData": {}, "branch": "prod", - "commitHash": "testXyz", + "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "url": "testProject-f8wsyim6.snowball.xyz" }, { @@ -66,7 +66,7 @@ "registryRecordId": "tbafyreihvzya6ovp4yfpqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", "registryRecordData": {}, "branch": "main", - "commitHash": "testXyz", + "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "url": "testProject-2-eO8cckxk.snowball.xyz" }, { @@ -80,7 +80,7 @@ "registryRecordId": "ybafyreihvzya6ovp4yfpkqnddkui2iw7t6bhwq74lbqs7bhobvmfhrowoi", "registryRecordData": {}, "branch": "test", - "commitHash": "testXyz", + "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "url": "testProject-2-yaq0t5yw.snowball.xyz" }, { @@ -94,7 +94,7 @@ "registryRecordId": "ubafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvfhrowoi", "registryRecordData": {}, "branch": "test", - "commitHash": "testXyz", + "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "url": "testProject-2-hwwr6sbx.snowball.xyz" }, { @@ -108,7 +108,7 @@ "registryRecordId": "ibayreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", "registryRecordData": {}, "branch": "main", - "commitHash": "testXyz", + "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "url": "iglootools-ndxje48a.snowball.xyz" }, { @@ -122,7 +122,7 @@ "registryRecordId": "obafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi", "registryRecordData": {}, "branch": "test", - "commitHash": "testXyz", + "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "url": "iglootools-gtgpgvei.snowball.xyz" }, { @@ -136,7 +136,7 @@ "registryRecordId": "pbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowo", "registryRecordData": {}, "branch": "test", - "commitHash": "testXyz", + "commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00", "url": "iglootools-b4bpthjr.snowball.xyz" } ] diff --git a/packages/backend/test/fixtures/projects.json b/packages/backend/test/fixtures/projects.json index a390f48..f2def3f 100644 --- a/packages/backend/test/fixtures/projects.json +++ b/packages/backend/test/fixtures/projects.json @@ -3,10 +3,10 @@ "ownerIndex": 0, "organizationIndex": 0, "name": "testProject", - "repository": "test", + "repository": "snowball-tools/snowball-ts-framework-template", "prodBranch": "main", "description": "test", - "template": "test", + "template": "webapp", "framework": "test", "webhooks": [], "icon": "", @@ -18,10 +18,10 @@ "ownerIndex": 1, "organizationIndex": 0, "name": "testProject-2", - "repository": "test-2", + "repository": "snowball-tools/snowball-ts-framework-template", "prodBranch": "main", "description": "test-2", - "template": "test-2", + "template": "webapp", "framework": "test-2", "webhooks": [], "icon": "", @@ -33,10 +33,10 @@ "ownerIndex": 2, "organizationIndex": 0, "name": "iglootools", - "repository": "test-3", + "repository": "snowball-tools/snowball-ts-framework-template", "prodBranch": "main", "description": "test-3", - "template": "test-3", + "template": "webapp", "framework": "test-3", "webhooks": [], "icon": "", @@ -48,10 +48,10 @@ "ownerIndex": 1, "organizationIndex": 0, "name": "iglootools-2", - "repository": "test-4", + "repository": "snowball-tools/snowball-ts-framework-template", "prodBranch": "main", "description": "test-4", - "template": "test-4", + "template": "webapp", "framework": "test-4", "webhooks": [], "icon": "", @@ -63,10 +63,10 @@ "ownerIndex": 0, "organizationIndex": 1, "name": "snowball-2", - "repository": "test-5", + "repository": "snowball-tools/snowball-ts-framework-template", "prodBranch": "main", "description": "test-5", - "template": "test-5", + "template": "webapp", "framework": "test-5", "webhooks": [], "icon": "", diff --git a/packages/frontend/src/components/projects/ProjectCard.tsx b/packages/frontend/src/components/projects/ProjectCard.tsx index ce78a64..57978c0 100644 --- a/packages/frontend/src/components/projects/ProjectCard.tsx +++ b/packages/frontend/src/components/projects/ProjectCard.tsx @@ -7,6 +7,7 @@ import { MenuList, MenuItem, Typography, + Avatar, } from '@material-tailwind/react'; import { relativeTimeISO } from '../../utils/time'; @@ -20,7 +21,7 @@ const ProjectCard: React.FC = ({ project }) => { return (
-
{project.icon}
+
{project.name} @@ -42,10 +43,10 @@ const ProjectCard: React.FC = ({ project }) => {
- {project.latestCommit.message} + ^ {project.latestCommit.message} - {relativeTimeISO(project.latestCommit.createdAt)} on{' '} + {relativeTimeISO(project.latestCommit.createdAt)} on ^  {project.latestCommit.branch}
diff --git a/packages/frontend/src/components/projects/ProjectSearchBar.tsx b/packages/frontend/src/components/projects/ProjectSearchBar.tsx index 494c036..c6653bb 100644 --- a/packages/frontend/src/components/projects/ProjectSearchBar.tsx +++ b/packages/frontend/src/components/projects/ProjectSearchBar.tsx @@ -9,6 +9,7 @@ import { ListItemPrefix, Card, Typography, + Avatar, } from '@material-tailwind/react'; import SearchBar from '../SearchBar'; @@ -86,7 +87,7 @@ const ProjectSearchBar = ({ onChange }: ProjectsSearchProps) => { {...getItemProps({ item, index })} > - ^ +
diff --git a/packages/frontend/src/components/projects/create/ConnectAccount.tsx b/packages/frontend/src/components/projects/create/ConnectAccount.tsx index 305894c..11a5e5d 100644 --- a/packages/frontend/src/components/projects/create/ConnectAccount.tsx +++ b/packages/frontend/src/components/projects/create/ConnectAccount.tsx @@ -32,8 +32,9 @@ const ConnectAccount = ({ onAuth: onToken }: ConnectAccountInterface) => {

Connect to your git account

- Once connected, you can create projects by importing repositories - under the account + Once connected, you can import a repository from your +
+ account or start with one of our templates.

diff --git a/packages/frontend/src/components/projects/project/deployments/AssignDomainDialog.tsx b/packages/frontend/src/components/projects/project/deployments/AssignDomainDialog.tsx index 7c51b59..b1f5874 100644 --- a/packages/frontend/src/components/projects/project/deployments/AssignDomainDialog.tsx +++ b/packages/frontend/src/components/projects/project/deployments/AssignDomainDialog.tsx @@ -22,12 +22,12 @@ const AssignDomainDialog = ({ open, handleOpen }: AssignDomainProps) => { In order to assign a domain to your production deployments, configure it in the{' '} - {/* TODO: Navigate to settings tab panel after clicking on project settings */} - + project settings{' '} (recommended). If you want to assign to this specific deployment, however, you can do so using our command-line interface: + {/* https://github.com/rajinwonderland/react-code-blocks/issues/138 */} ^ {deployment.branch} - ^ {deployment.commitHash} {deployment.commit.message} + ^ {deployment.commitHash.substring(0, SHORT_COMMIT_HASH_LENGTH)}{' '} + {deployment.commit.message}
- {relativeTimeMs(deployment.createdAt)} ^ {deployment.createdBy.name} + ^ {relativeTimeMs(deployment.createdAt)} ^ {deployment.createdBy.name} diff --git a/packages/frontend/src/components/projects/project/deployments/DeploymentDialogBodyCard.tsx b/packages/frontend/src/components/projects/project/deployments/DeploymentDialogBodyCard.tsx index 1ae8aee..73ef40b 100644 --- a/packages/frontend/src/components/projects/project/deployments/DeploymentDialogBodyCard.tsx +++ b/packages/frontend/src/components/projects/project/deployments/DeploymentDialogBodyCard.tsx @@ -4,6 +4,7 @@ import { Typography, Chip, Card } from '@material-tailwind/react'; import { color } from '@material-tailwind/react/types/components/chip'; import { DeploymentDetails } from '../../../../types/project'; import { relativeTimeMs } from '../../../../utils/time'; +import { SHORT_COMMIT_HASH_LENGTH } from '../../../../constants'; interface DeploymentDialogBodyCardProps { deployment: DeploymentDetails; @@ -31,7 +32,8 @@ const DeploymentDialogBodyCard = ({ {deployment.url} - ^ {deployment.branch} ^ {deployment.commitHash}{' '} + ^ {deployment.branch} ^{' '} + {deployment.commitHash.substring(0, SHORT_COMMIT_HASH_LENGTH)}{' '} {deployment.commit.message} diff --git a/packages/frontend/src/constants.ts b/packages/frontend/src/constants.ts index 79dfe16..df71627 100644 --- a/packages/frontend/src/constants.ts +++ b/packages/frontend/src/constants.ts @@ -8,3 +8,5 @@ export const ORGANIZATION_ID = '2379cf1f-a232-4ad2-ae14-4d881131cc26'; export const GIT_TEMPLATE_LINK = 'https://git.vdb.to/cerc-io/test-progressive-web-app'; + +export const SHORT_COMMIT_HASH_LENGTH = 8; diff --git a/packages/frontend/src/pages/org-slug/projects/create/Import.tsx b/packages/frontend/src/pages/org-slug/projects/create/Import.tsx index 420c239..726135e 100644 --- a/packages/frontend/src/pages/org-slug/projects/create/Import.tsx +++ b/packages/frontend/src/pages/org-slug/projects/create/Import.tsx @@ -30,8 +30,9 @@ const Import = () => {
^
{repoName}
- - +
+ +
); }; diff --git a/packages/frontend/src/pages/org-slug/projects/create/Template.tsx b/packages/frontend/src/pages/org-slug/projects/create/Template.tsx index dda801f..e95b7c3 100644 --- a/packages/frontend/src/pages/org-slug/projects/create/Template.tsx +++ b/packages/frontend/src/pages/org-slug/projects/create/Template.tsx @@ -1,6 +1,8 @@ import React, { useMemo } from 'react'; import { Outlet, useLocation, useSearchParams } from 'react-router-dom'; +import { Avatar } from '@material-tailwind/react'; + import Stepper from '../../../../components/Stepper'; import templateDetails from '../../../../assets/templates.json'; import { GIT_TEMPLATE_LINK } from '../../../../constants'; @@ -29,12 +31,12 @@ const CreateWithTemplate = () => { return (
-
-
^
-
{template?.name}
+ diff --git a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx index 453259f..cd4f230 100644 --- a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx +++ b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'; import { Domain, DomainStatus } from 'gql-client'; import { useOutletContext } from 'react-router-dom'; -import { Typography, Button, Chip } from '@material-tailwind/react'; +import { Typography, Button, Chip, Avatar } from '@material-tailwind/react'; import ActivityCard from '../../../../components/projects/project/ActivityCard'; import { relativeTimeMs } from '../../../../utils/time'; @@ -96,7 +96,7 @@ const OverviewTabPanel = () => {
-
^
+
{project.name} @@ -137,7 +137,7 @@ const OverviewTabPanel = () => { <>

^ Source

-

{project.deployments[0]?.branch}

+

^ {project.deployments[0]?.branch}

^ Deployment