forked from cerc-io/snowballtools-base
Compare commits
38
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7fd7c010d | ||
|
|
a684743bd6 | ||
|
|
b12c95b2ff | ||
|
|
a4d9211ffe | ||
|
|
af31fac3ee | ||
|
|
54ae3f429d | ||
|
|
acfe78bf07 | ||
|
|
ce1833cb51 | ||
|
|
f2e59c11fd | ||
|
|
b261e7e436 | ||
|
|
934aa1a26b | ||
|
|
d975390a1b | ||
|
|
f77323364c | ||
|
|
c6a78f2116 | ||
|
|
cff9a5b2ea | ||
|
|
003b83ba21 | ||
|
|
82a1c151a8 | ||
|
|
2ada11f311 | ||
|
|
6e32d0678a | ||
|
|
198478f5fa | ||
|
|
552dfe783e | ||
|
|
e2bf5d052c | ||
|
|
33323b9bbf | ||
|
|
e2a3254563 | ||
|
|
8589bf4094 | ||
|
|
f8ebdfe7aa | ||
|
|
2166b2f800 | ||
|
|
cdd8d15e73 | ||
|
|
dc7b251988 | ||
|
|
bfb4a3f30b | ||
|
|
8f7fc888a9 | ||
|
|
0e9c3a07fd | ||
|
|
61e3e88a6c | ||
|
|
7b5ba1a5d0 | ||
|
|
b35f4033c5 | ||
|
|
306d3235b3 | ||
|
|
e148fd8d6b | ||
|
|
f84e2c0d9d |
+4
-1
@@ -6,4 +6,7 @@ yarn-error.log
|
||||
|
||||
packages/backend/environments/local.toml
|
||||
packages/backend/dev/
|
||||
packages/frontend/dist/
|
||||
packages/frontend/dist/
|
||||
|
||||
# ignore all .DS_Store files
|
||||
**/.DS_Store
|
||||
|
||||
@@ -1,220 +1,23 @@
|
||||
# snowballtools-base
|
||||
|
||||
## Setup
|
||||
This is a [yarn workspace](https://yarnpkg.com/features/workspaces) monorepo for the dashboard.
|
||||
|
||||
- Clone the `snowballtools-base` repo
|
||||
## Getting Started
|
||||
|
||||
```bash
|
||||
git clone git@github.com:snowball-tools/snowballtools-base.git
|
||||
cd snowballtools-base
|
||||
```
|
||||
### Install dependencies
|
||||
|
||||
- Install dependencies in root
|
||||
In the root of the project, run:
|
||||
|
||||
```bash
|
||||
yarn
|
||||
```
|
||||
```zsh
|
||||
yarn
|
||||
```
|
||||
|
||||
- Build packages
|
||||
### Build backend
|
||||
|
||||
```bash
|
||||
yarn build --ignore frontend
|
||||
```
|
||||
```zsh
|
||||
yarn build --ignore frontend
|
||||
```
|
||||
|
||||
Let us assume the following domains for backend and frontend
|
||||
- Backend server: `api.snowballtools.com`
|
||||
- Frontend app: `dashboard.snowballtools.com`
|
||||
### Environment variables, running the development server, and deployment
|
||||
|
||||
- Configuration Files
|
||||
|
||||
- For Backend:
|
||||
|
||||
```bash
|
||||
cp packages/backend/environments/local.toml.example packages/backend/environments/local.toml
|
||||
```
|
||||
|
||||
- Production
|
||||
|
||||
- Update the following in backend [config file](packages/backend/environments/local.toml)
|
||||
|
||||
```toml
|
||||
[server]
|
||||
...
|
||||
[server.session]
|
||||
# Secret should be changed to a different random string
|
||||
secret = "p4yfpkqnddkui2iw7t6hbhwq74lbqs7sidnc382"
|
||||
# Set URL of the frontend app
|
||||
appOriginUrl = "https://dashboard.snowballtools.com"
|
||||
# Set to true for session cookies to work behind proxy
|
||||
trustProxy = true
|
||||
# Set empty domain when using secure connection
|
||||
domain = ""
|
||||
```
|
||||
|
||||
- Set `gitHub.oAuth.clientId` and `gitHub.oAuth.clientSecret` in backend [config file](packages/backend/environments/local.toml)
|
||||
- [OAuth App Creation](https://github.com/organizations/<org>/settings/applications/new)
|
||||
- Homepage URL: `https://dashboard.snowballtools.com`
|
||||
- Authorization callback URL: `https://dashboard.snowballtools.com/organization/projects/create`
|
||||
- Generate a new client secret after app is created
|
||||
|
||||
- Set `gitHub.webhookUrl` in backend [config file](packages/backend/environments/local.toml)
|
||||
|
||||
```toml
|
||||
[gitHub]
|
||||
webhookUrl = "https://api.snowballtools.com"
|
||||
```
|
||||
|
||||
- Let us assume domain for Laconicd to be `api.laconic.com` and set the following in backend [config file](packages/backend/environments/local.toml)
|
||||
|
||||
```toml
|
||||
[registryConfig]
|
||||
fetchDeploymentRecordDelay = 5000
|
||||
# Use actual port for REST endpoint
|
||||
restEndpoint = "http://api.laconic.com:1317"
|
||||
# Use actual port for GQL endpoint
|
||||
gqlEndpoint = "http://api.laconic.com:9473/api"
|
||||
# Set private key of account to be used in Laconicd
|
||||
privateKey = "0wtu92cd4f1y791ezpjwgzzazni4dmd3q3mzqc3t6i6r9v06ji784tey6hwmnn69"
|
||||
# Set Bond ID to be used for publishing records
|
||||
bondId = "8xk8c2pb61kajwixpm223zvptr2x2ncajq0vd998p6aqhvqqep2reu6pik245epf"
|
||||
chainId = "laconic_9000-1"
|
||||
# Set authority that is existing in the chain
|
||||
authority = "laconic"
|
||||
[registryConfig.fee]
|
||||
amount = "200000"
|
||||
denom = "aphoton"
|
||||
gas = "750000"
|
||||
```
|
||||
|
||||
- Development
|
||||
|
||||
- Set `gitHub.oAuth.clientId` and `gitHub.oAuth.clientSecret` in backend [config file](packages/backend/environments/local.toml)
|
||||
- [OAuth App Creation](https://github.com/organizations/<org>/settings/applications/new)
|
||||
- Homepage URL: `http://localhost:3000`
|
||||
- Authorization callback URL: `http://localhost:3000/organization/projects/create`
|
||||
- Generate a new client secret after app is created
|
||||
|
||||
- Setup Laconicd
|
||||
- Run the laconicd stack following this [doc](https://git.vdb.to/cerc-io/stack-orchestrator/src/branch/main/docs/laconicd-with-console.md)
|
||||
- Get the private key and set `registryConfig.privateKey` in backend [config file](packages/backend/environments/local.toml)
|
||||
|
||||
```bash
|
||||
laconic-so deployment --dir laconic-loaded-deployment exec laconicd "laconicd keys export mykey --unarmored-hex --unsafe"
|
||||
# WARNING: The private key will be exported as an unarmored hexadecimal string. USE AT YOUR OWN RISK. Continue? [y/N]: y
|
||||
# 754cca7b4b729a99d156913aea95366411d072856666e95ba09ef6c664357d81
|
||||
```
|
||||
|
||||
- Set authority in `registryConfig.authority` in backend [config file](packages/backend/environments/local.toml)
|
||||
|
||||
- Run the script to create bond, reserve the authority and set authority bond
|
||||
|
||||
```bash
|
||||
yarn test:registry:init
|
||||
# snowball:initialize-registry bondId: 6af0ab81973b93d3511ae79841756fb5da3fd2f70ea1279e81fae7c9b19af6c4 +0ms
|
||||
```
|
||||
|
||||
- Get the bond id and set `registryConfig.bondId` in backend [config file](packages/backend/environments/local.toml)
|
||||
|
||||
- Setup ngrok for GitHub webhooks
|
||||
- [ngrok getting started](https://ngrok.com/docs/getting-started/)
|
||||
- Start ngrok and point to backend server endpoint
|
||||
|
||||
```bash
|
||||
ngrok http http://localhost:8000
|
||||
```
|
||||
|
||||
- Look for the forwarding URL in ngrok
|
||||
|
||||
```bash
|
||||
Forwarding https://19c1-61-95-158-116.ngrok-free.app -> http://localhost:8000
|
||||
```
|
||||
|
||||
- Set `gitHub.webhookUrl` in backend [config file](packages/backend/environments/local.toml)
|
||||
|
||||
```toml
|
||||
[gitHub]
|
||||
webhookUrl = "https://19c1-61-95-158-116.ngrok-free.app"
|
||||
```
|
||||
|
||||
- For Frontend:
|
||||
|
||||
```bash
|
||||
cp packages/frontend/.env.example packages/frontend/.env
|
||||
```
|
||||
|
||||
- Copy the GitHub OAuth app client ID from previous steps and set it in frontend [.env](packages/frontend/.env) file
|
||||
|
||||
```env
|
||||
VITE_GITHUB_CLIENT_ID = <CLIENT_ID>
|
||||
```
|
||||
|
||||
- Set `VITE_GITHUB_PWA_TEMPLATE_REPO` and `VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO` in [.env](packages/frontend/.env) file
|
||||
|
||||
```env
|
||||
VITE_GITHUB_PWA_TEMPLATE_REPO = 'cerc-io/test-progressive-web-app' # Set actual owner/name of the template repo that will be used for creating new repo
|
||||
VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO = 'cerc-io/image-upload-pwa-example' # Set actual owner/name of the template repo that will be used for creating new repo
|
||||
```
|
||||
|
||||
- Production
|
||||
|
||||
- Set the following values in [.env](packages/frontend/.env) file
|
||||
|
||||
```env
|
||||
VITE_SERVER_URL = 'https://api.snowballtools.com' # Backend server endpoint
|
||||
```
|
||||
|
||||
- Sign in to [wallet connect](https://cloud.walletconnect.com/sign-in) to create a project ID
|
||||
- Create a project and add information to use wallet connect SDK
|
||||
- Add project name and select project type as `App`
|
||||
- Set project home page URL to `https://dashboard.snowballtools.com`
|
||||
- On creation of project, use the `Project ID` and set it in `VITE_WALLET_CONNECT_ID` in [.env](packages/frontend/.env) file
|
||||
|
||||
```env
|
||||
VITE_WALLET_CONNECT_ID = <PROJECT_ID>
|
||||
```
|
||||
|
||||
- Build the React application
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
```
|
||||
|
||||
- Use a web server for hosting static built files
|
||||
|
||||
```bash
|
||||
python3 -m http.server -d build 3000
|
||||
```
|
||||
|
||||
- Development
|
||||
|
||||
- Copy the graphQL endpoint from terminal and add the endpoint in the [.env](packages/frontend/.env) file present in `packages/frontend`
|
||||
|
||||
```env
|
||||
VITE_SERVER_URL = 'http://localhost:8000'
|
||||
```
|
||||
|
||||
- Sign in to [wallet connect](https://cloud.walletconnect.com/sign-in) to create a project ID.
|
||||
- Create a project and add information to use wallet connect SDK
|
||||
- Add project name and select project type as `App`
|
||||
- Project home page URL is not required to be set
|
||||
- On creation of project, use the `Project ID` and set it in `VITE_WALLET_CONNECT_ID` in [.env](packages/frontend/.env) file
|
||||
|
||||
```env
|
||||
VITE_WALLET_CONNECT_ID = <Project_ID>
|
||||
```
|
||||
|
||||
- The React application will be running in `http://localhost:3000/`
|
||||
|
||||
## Development
|
||||
|
||||
- Start the backend server
|
||||
|
||||
```bash
|
||||
yarn start:backend
|
||||
```
|
||||
|
||||
- Start the frontend
|
||||
|
||||
```bash
|
||||
yarn start
|
||||
```
|
||||
Follow the instructions in the README.md files of the [backend](packages/backend/README.md) and [frontend](packages/frontend/README.md) packages.
|
||||
|
||||
@@ -1 +1,76 @@
|
||||
# Backend for Snowball Tools
|
||||
# backend
|
||||
|
||||
This backend is a [node.js](https://nodejs.org/) [express.js](https://expressjs.com/) [apollo server](https://www.apollographql.com/docs/apollo-server/) project in a [yarn workspace](https://yarnpkg.com/features/workspaces).
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Install dependencies
|
||||
|
||||
In the root of the project, run:
|
||||
|
||||
```zsh
|
||||
yarn
|
||||
```
|
||||
|
||||
### Build backend
|
||||
|
||||
```zsh
|
||||
yarn build --ignore frontend
|
||||
```
|
||||
|
||||
### Environment variables
|
||||
|
||||
#### Local
|
||||
|
||||
Copy the `envionments/local.toml.example` file to `envionments/local.toml`:
|
||||
|
||||
```zsh
|
||||
cp envionments/local.toml.example envionments/local.toml
|
||||
```
|
||||
|
||||
#### Staging environment variables
|
||||
|
||||
In the deployment repository, update staging [staging/configmaps/config/prod.toml](https://git.vdb.to/cerc-io/snowballtools-base-api-deployments/src/commit/318c2bc09f334dca79c3501838512749f9431bf1/deployments/staging/configmaps/config/prod.toml)
|
||||
|
||||
#### Production environment variables
|
||||
|
||||
In the deployment repository, update production [production/configmaps/config/prod.toml](https://git.vdb.to/cerc-io/snowballtools-base-api-deployments/src/commit/318c2bc09f334dca79c3501838512749f9431bf1/deployments/production/configmaps/config/prod.toml)
|
||||
|
||||
### Run development server
|
||||
|
||||
```zsh
|
||||
yarn start
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
Clone the deployer repository:
|
||||
|
||||
```zsh
|
||||
git clone git@git.vdb.to:cerc-io/snowballtools-base-api-deployments.git
|
||||
```
|
||||
|
||||
### Staging
|
||||
|
||||
```zsh
|
||||
echo trigger >> .gitea/workflows/triggers/staging-deploy
|
||||
git commit -a -m "Deploy v0.0.8" # replace with version number
|
||||
git push
|
||||
```
|
||||
|
||||
### Production
|
||||
|
||||
```zsh
|
||||
echo trigger >> .gitea/workflows/triggers/production-deploy
|
||||
git commit -a -m "Deploy v0.0.8" # replace with version number
|
||||
git push
|
||||
```
|
||||
|
||||
### Deployment status
|
||||
|
||||
Dumb for now
|
||||
|
||||
- [Staging](https://snowballtools-base-api.staging.apps.snowballtools.com/staging/version)
|
||||
- [Production](https://snowballtools-base-api.apps.snowballtools.com/staging/version)
|
||||
|
||||
Update version number manually in [routes/staging.ts](/packages/backend/src/routes/staging.ts)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"cors": "^2.8.5",
|
||||
"debug": "^4.3.1",
|
||||
"express": "^4.18.2",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"express-session": "^1.18.0",
|
||||
"fs-extra": "^11.2.0",
|
||||
"graphql": "^16.8.1",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'express-async-errors';
|
||||
import 'reflect-metadata';
|
||||
import debug from 'debug';
|
||||
import fs from 'fs';
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Permission } from './entity/ProjectMember';
|
||||
import { Domain } from './entity/Domain';
|
||||
import { Project } from './entity/Project';
|
||||
import { EnvironmentVariable } from './entity/EnvironmentVariable';
|
||||
import { AddProjectFromTemplateInput } from './types';
|
||||
|
||||
const log = debug('snowball:resolver');
|
||||
|
||||
@@ -17,7 +18,7 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
return context.user;
|
||||
},
|
||||
|
||||
organizations: async (_:any, __: any, context: any) => {
|
||||
organizations: async (_: any, __: any, context: any) => {
|
||||
return service.getOrganizationsByUserId(context.user);
|
||||
},
|
||||
|
||||
@@ -25,8 +26,15 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
return service.getProjectById(projectId);
|
||||
},
|
||||
|
||||
projectsInOrganization: async (_: any, { organizationSlug }: {organizationSlug: string }, context: any) => {
|
||||
return service.getProjectsInOrganization(context.user, organizationSlug);
|
||||
projectsInOrganization: async (
|
||||
_: any,
|
||||
{ organizationSlug }: { organizationSlug: string },
|
||||
context: any,
|
||||
) => {
|
||||
return service.getProjectsInOrganization(
|
||||
context.user,
|
||||
organizationSlug,
|
||||
);
|
||||
},
|
||||
|
||||
deployments: async (_: any, { projectId }: { projectId: string }) => {
|
||||
@@ -35,7 +43,7 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
|
||||
environmentVariables: async (
|
||||
_: any,
|
||||
{ projectId }: { projectId: string }
|
||||
{ projectId }: { projectId: string },
|
||||
) => {
|
||||
return service.getEnvironmentVariablesByProjectId(projectId);
|
||||
},
|
||||
@@ -44,7 +52,11 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
return service.getProjectMembersByProjectId(projectId);
|
||||
},
|
||||
|
||||
searchProjects: async (_: any, { searchText }: { searchText: string }, context: any) => {
|
||||
searchProjects: async (
|
||||
_: any,
|
||||
{ searchText }: { searchText: string },
|
||||
context: any,
|
||||
) => {
|
||||
return service.searchProjects(context.user, searchText);
|
||||
},
|
||||
|
||||
@@ -52,11 +64,11 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
_: any,
|
||||
{
|
||||
projectId,
|
||||
filter
|
||||
}: { projectId: string; filter?: FindOptionsWhere<Domain> }
|
||||
filter,
|
||||
}: { projectId: string; filter?: FindOptionsWhere<Domain> },
|
||||
) => {
|
||||
return service.getDomainsByProjectId(projectId, filter);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
// TODO: Return error in GQL response
|
||||
@@ -64,10 +76,13 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
removeProjectMember: async (
|
||||
_: any,
|
||||
{ projectMemberId }: { projectMemberId: string },
|
||||
context: any
|
||||
context: any,
|
||||
) => {
|
||||
try {
|
||||
return await service.removeProjectMember(context.user, projectMemberId);
|
||||
return await service.removeProjectMember(
|
||||
context.user,
|
||||
projectMemberId,
|
||||
);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
@@ -78,13 +93,13 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
_: any,
|
||||
{
|
||||
projectMemberId,
|
||||
data
|
||||
data,
|
||||
}: {
|
||||
projectMemberId: string;
|
||||
data: {
|
||||
permissions: Permission[];
|
||||
};
|
||||
}
|
||||
},
|
||||
) => {
|
||||
try {
|
||||
return await service.updateProjectMember(projectMemberId, data);
|
||||
@@ -98,14 +113,14 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
_: any,
|
||||
{
|
||||
projectId,
|
||||
data
|
||||
data,
|
||||
}: {
|
||||
projectId: string;
|
||||
data: {
|
||||
email: string;
|
||||
permissions: Permission[];
|
||||
};
|
||||
}
|
||||
},
|
||||
) => {
|
||||
try {
|
||||
return Boolean(await service.addProjectMember(projectId, data));
|
||||
@@ -119,15 +134,15 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
_: any,
|
||||
{
|
||||
projectId,
|
||||
data
|
||||
data,
|
||||
}: {
|
||||
projectId: string;
|
||||
data: { environments: string[]; key: string; value: string }[];
|
||||
}
|
||||
},
|
||||
) => {
|
||||
try {
|
||||
return Boolean(
|
||||
await service.addEnvironmentVariables(projectId, data)
|
||||
await service.addEnvironmentVariables(projectId, data),
|
||||
);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
@@ -139,16 +154,16 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
_: any,
|
||||
{
|
||||
environmentVariableId,
|
||||
data
|
||||
data,
|
||||
}: {
|
||||
environmentVariableId: string;
|
||||
data: DeepPartial<EnvironmentVariable>;
|
||||
}
|
||||
},
|
||||
) => {
|
||||
try {
|
||||
return await service.updateEnvironmentVariable(
|
||||
environmentVariableId,
|
||||
data
|
||||
data,
|
||||
);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
@@ -158,7 +173,7 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
|
||||
removeEnvironmentVariable: async (
|
||||
_: any,
|
||||
{ environmentVariableId }: { environmentVariableId: string }
|
||||
{ environmentVariableId }: { environmentVariableId: string },
|
||||
) => {
|
||||
try {
|
||||
return await service.removeEnvironmentVariable(environmentVariableId);
|
||||
@@ -171,23 +186,45 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
updateDeploymentToProd: async (
|
||||
_: any,
|
||||
{ deploymentId }: { deploymentId: string },
|
||||
context: any
|
||||
context: any,
|
||||
) => {
|
||||
try {
|
||||
return Boolean(await service.updateDeploymentToProd(context.user, deploymentId));
|
||||
return Boolean(
|
||||
await service.updateDeploymentToProd(context.user, deploymentId),
|
||||
);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
addProjectFromTemplate: async (
|
||||
_: any,
|
||||
{
|
||||
organizationSlug,
|
||||
data,
|
||||
}: { organizationSlug: string; data: AddProjectFromTemplateInput },
|
||||
context: any,
|
||||
) => {
|
||||
try {
|
||||
return await service.addProjectFromTemplate(
|
||||
context.user,
|
||||
organizationSlug,
|
||||
data,
|
||||
);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
addProject: async (
|
||||
_: any,
|
||||
{
|
||||
organizationSlug,
|
||||
data
|
||||
data,
|
||||
}: { organizationSlug: string; data: DeepPartial<Project> },
|
||||
context: any
|
||||
context: any,
|
||||
) => {
|
||||
try {
|
||||
return await service.addProject(context.user, organizationSlug, data);
|
||||
@@ -199,7 +236,7 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
|
||||
updateProject: async (
|
||||
_: any,
|
||||
{ projectId, data }: { projectId: string; data: DeepPartial<Project> }
|
||||
{ projectId, data }: { projectId: string; data: DeepPartial<Project> },
|
||||
) => {
|
||||
try {
|
||||
return await service.updateProject(projectId, data);
|
||||
@@ -212,10 +249,12 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
redeployToProd: async (
|
||||
_: any,
|
||||
{ deploymentId }: { deploymentId: string },
|
||||
context: any
|
||||
context: any,
|
||||
) => {
|
||||
try {
|
||||
return Boolean(await service.redeployToProd(context.user, deploymentId));
|
||||
return Boolean(
|
||||
await service.redeployToProd(context.user, deploymentId),
|
||||
);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
@@ -244,8 +283,8 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
_: any,
|
||||
{
|
||||
projectId,
|
||||
deploymentId
|
||||
}: { deploymentId: string; projectId: string }
|
||||
deploymentId,
|
||||
}: { deploymentId: string; projectId: string },
|
||||
) => {
|
||||
try {
|
||||
return await service.rollbackDeployment(projectId, deploymentId);
|
||||
@@ -257,9 +296,7 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
|
||||
deleteDeployment: async (
|
||||
_: any,
|
||||
{
|
||||
deploymentId
|
||||
}: { deploymentId: string; }
|
||||
{ deploymentId }: { deploymentId: string },
|
||||
) => {
|
||||
try {
|
||||
return await service.deleteDeployment(deploymentId);
|
||||
@@ -271,7 +308,7 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
|
||||
addDomain: async (
|
||||
_: any,
|
||||
{ projectId, data }: { projectId: string; data: { name: string } }
|
||||
{ projectId, data }: { projectId: string; data: { name: string } },
|
||||
) => {
|
||||
try {
|
||||
return Boolean(await service.addDomain(projectId, data));
|
||||
@@ -283,7 +320,7 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
|
||||
updateDomain: async (
|
||||
_: any,
|
||||
{ domainId, data }: { domainId: string; data: DeepPartial<Domain> }
|
||||
{ domainId, data }: { domainId: string; data: DeepPartial<Domain> },
|
||||
) => {
|
||||
try {
|
||||
return await service.updateDomain(domainId, data);
|
||||
@@ -296,7 +333,7 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
authenticateGitHub: async (
|
||||
_: any,
|
||||
{ code }: { code: string },
|
||||
context: any
|
||||
context: any,
|
||||
) => {
|
||||
try {
|
||||
return await service.authenticateGitHub(code, context.user);
|
||||
@@ -308,12 +345,14 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
|
||||
unauthenticateGitHub: async (_: any, __: object, context: any) => {
|
||||
try {
|
||||
return service.unauthenticateGitHub(context.user, { gitHubToken: null });
|
||||
return service.unauthenticateGitHub(context.user, {
|
||||
gitHubToken: null,
|
||||
});
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,6 +5,19 @@ import { authenticateUser, createUser } from '../turnkey-backend';
|
||||
|
||||
const router = Router();
|
||||
|
||||
//
|
||||
// Access Code
|
||||
//
|
||||
router.post('/accesscode', async (req, res) => {
|
||||
console.log('Access Code', req.body);
|
||||
const { accesscode } = req.body;
|
||||
if (accesscode === '44444') {
|
||||
return res.send({ isValid: true });
|
||||
} else {
|
||||
return res.sendStatus(204);
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Turnkey
|
||||
//
|
||||
@@ -19,6 +32,7 @@ router.get('/registration/:email', async (req, res) => {
|
||||
});
|
||||
|
||||
router.post('/register', async (req, res) => {
|
||||
console.log('Register', req.body);
|
||||
const { email, challenge, attestation } = req.body;
|
||||
const user = await createUser(req.app.get('service'), {
|
||||
challenge,
|
||||
@@ -31,6 +45,7 @@ router.post('/register', async (req, res) => {
|
||||
});
|
||||
|
||||
router.post('/authenticate', async (req, res) => {
|
||||
console.log('Authenticate', req.body);
|
||||
const { signedWhoamiRequest } = req.body;
|
||||
const user = await authenticateUser(
|
||||
req.app.get('service'),
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Router } from 'express';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get('/version', async (req, res) => {
|
||||
return res.send({ version: '0.0.8' });
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -130,6 +130,14 @@ input AddEnvironmentVariableInput {
|
||||
value: String!
|
||||
}
|
||||
|
||||
input AddProjectFromTemplateInput {
|
||||
templateOwner: String!
|
||||
templateRepo: String!
|
||||
owner: String!
|
||||
name: String!
|
||||
isPrivate: Boolean!
|
||||
}
|
||||
|
||||
input AddProjectInput {
|
||||
name: String!
|
||||
repository: String!
|
||||
@@ -204,6 +212,10 @@ type Mutation {
|
||||
): Boolean!
|
||||
removeEnvironmentVariable(environmentVariableId: String!): Boolean!
|
||||
updateDeploymentToProd(deploymentId: String!): Boolean!
|
||||
addProjectFromTemplate(
|
||||
organizationSlug: String!
|
||||
data: AddProjectFromTemplateInput
|
||||
): Project!
|
||||
addProject(organizationSlug: String!, data: AddProjectInput): Project!
|
||||
updateProject(projectId: String!, data: UpdateProjectInput): Boolean!
|
||||
redeployToProd(deploymentId: String!): Boolean!
|
||||
|
||||
@@ -17,6 +17,7 @@ import { ServerConfig } from './config';
|
||||
import { DEFAULT_GQL_PATH } from './constants';
|
||||
import githubRouter from './routes/github';
|
||||
import authRouter from './routes/auth';
|
||||
import stagingRouter from './routes/staging';
|
||||
import { Service } from './service';
|
||||
|
||||
const log = debug('snowball:server');
|
||||
@@ -109,6 +110,12 @@ export const createAndStartServer = async (
|
||||
app.set('service', service);
|
||||
app.use('/auth', authRouter);
|
||||
app.use('/api/github', githubRouter);
|
||||
app.use('/staging', stagingRouter);
|
||||
|
||||
app.use((err: any, req: any, res: any, next: any) => {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: err.message });
|
||||
});
|
||||
|
||||
httpServer.listen(port, host, () => {
|
||||
log(`Server is listening on ${host}:${port}${server.graphqlPath}`);
|
||||
|
||||
+341
-235
File diff suppressed because it is too large
Load Diff
@@ -41,7 +41,7 @@ export interface AppDeploymentRecordAttributes {
|
||||
export interface AppDeploymentRemovalRecordAttributes {
|
||||
deployment: string;
|
||||
request: string;
|
||||
type: "ApplicationDeploymentRemovalRecord";
|
||||
type: 'ApplicationDeploymentRemovalRecord';
|
||||
version: string;
|
||||
}
|
||||
|
||||
@@ -61,3 +61,11 @@ export interface AppDeploymentRecord extends RegistryRecord {
|
||||
export interface AppDeploymentRemovalRecord extends RegistryRecord {
|
||||
attributes: AppDeploymentRemovalRecordAttributes;
|
||||
}
|
||||
|
||||
export interface AddProjectFromTemplateInput {
|
||||
templateOwner: string;
|
||||
templateRepo: string;
|
||||
owner: string;
|
||||
name: string;
|
||||
isPrivate: boolean;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# deployer
|
||||
|
||||
- Install dependencies
|
||||
|
||||
```bash
|
||||
yarn
|
||||
```
|
||||
|
||||
```bash
|
||||
brew install jq # if you do not have jq installed already
|
||||
```
|
||||
@@ -12,13 +14,13 @@
|
||||
|
||||
- To deploy frontend app to `dashboard.staging.apps.snowballtools.com`
|
||||
|
||||
```
|
||||
```bash
|
||||
./deploy-frontend.staging.sh
|
||||
```
|
||||
|
||||
- To deploy frontend app to `dashboard.apps.snowballtools.com`
|
||||
|
||||
```
|
||||
```bash
|
||||
./deploy-frontend.sh
|
||||
```
|
||||
|
||||
@@ -27,6 +29,7 @@
|
||||
## Notes
|
||||
|
||||
- Any config env can be updated in [records/application-deployment-request.yml](records/application-deployment-request.yml)
|
||||
|
||||
```yml
|
||||
record:
|
||||
...
|
||||
@@ -35,6 +38,7 @@
|
||||
LACONIC_HOSTED_CONFIG_app_server_url: https://snowballtools-base-api-001.apps.snowballtools.com
|
||||
...
|
||||
```
|
||||
|
||||
- On changing `LACONIC_HOSTED_CONFIG_app_github_clientid`, the GitHub client ID and secret need to be changed in backend config too
|
||||
|
||||
## Troubleshoot
|
||||
@@ -44,6 +48,7 @@
|
||||
|
||||
- If deployment fails due to low bond balance
|
||||
- Check balances
|
||||
|
||||
```bash
|
||||
# Account balance
|
||||
yarn laconic cns account get
|
||||
@@ -51,7 +56,9 @@
|
||||
# Bond balance
|
||||
yarn laconic cns bond get --id 99c0e9aec0ac1b8187faa579be3b54f93fafb6060ac1fd29170b860df605be32
|
||||
```
|
||||
|
||||
- Command to refill bond
|
||||
|
||||
```bash
|
||||
yarn laconic cns bond refill --id 99c0e9aec0ac1b8187faa579be3b54f93fafb6060ac1fd29170b860df605be32 --type aphoton --quantity 10000000
|
||||
```
|
||||
|
||||
@@ -3,7 +3,7 @@ services:
|
||||
restEndpoint: 'http://console.laconic.com:1317'
|
||||
gqlEndpoint: 'http://console.laconic.com:9473/api'
|
||||
userKey: 87d00f66a73e2ca428adeb49ba9164d0ad9a87edc60e33d46ad3031b9c5701fe
|
||||
bondId: 098c906850b87412f02200e41f449bc79e055eab77acfef32c0b22443bb46661
|
||||
bondId: 89c75c7bc5759861d10285aff6f9e7227d6855e446b77ad5d8324822dfec7deb
|
||||
chainId: laconic_9000-1
|
||||
gas: 550000
|
||||
gas: 1200000
|
||||
fees: 200000aphoton
|
||||
|
||||
@@ -26,7 +26,7 @@ if [ -z "$NEW_APPLICATION_VERSION" ] || [ "1" == "$NEW_APPLICATION_VERSION" ]; t
|
||||
fi
|
||||
|
||||
# Generate application-deployment-request.yml
|
||||
cat > ./records/application-deployment-request.yml <<EOF
|
||||
cat >./records/application-deployment-request.yml <<EOF
|
||||
record:
|
||||
type: ApplicationDeploymentRequest
|
||||
version: '1.0.0'
|
||||
@@ -37,9 +37,9 @@ record:
|
||||
env:
|
||||
LACONIC_HOSTED_CONFIG_server_url: https://snowballtools-base-api-001.apps.snowballtools.com
|
||||
LACONIC_HOSTED_CONFIG_github_clientid: b7c63b235ca1dd5639ab
|
||||
LACONIC_HOSTED_CONFIG_github_templaterepo: snowball-tools-platform/test-progressive-web-app
|
||||
LACONIC_HOSTED_CONFIG_github_pwa_templaterepo: snowball-tools-platform/test-progressive-web-app
|
||||
LACONIC_HOSTED_CONFIG_github_image_upload_templaterepo: snowball-tools-platform/image-upload-pwa-example
|
||||
LACONIC_HOSTED_CONFIG_github_templaterepo: snowball-tools/test-progressive-web-app
|
||||
LACONIC_HOSTED_CONFIG_github_pwa_templaterepo: snowball-tools/test-progressive-web-app
|
||||
LACONIC_HOSTED_CONFIG_github_image_upload_templaterepo: snowball-tools/image-upload-pwa-example
|
||||
LACONIC_HOSTED_CONFIG_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
|
||||
meta:
|
||||
note: Added by Snowball @ $CURRENT_DATE_TIME
|
||||
@@ -48,7 +48,7 @@ record:
|
||||
EOF
|
||||
|
||||
# Generate application-record.yml with incremented version
|
||||
cat > ./records/application-record.yml <<EOF
|
||||
cat >./records/application-record.yml <<EOF
|
||||
record:
|
||||
type: ApplicationRecord
|
||||
version: $NEW_APPLICATION_VERSION
|
||||
@@ -64,7 +64,13 @@ echo "Files generated successfully."
|
||||
RECORD_FILE=records/application-record.yml
|
||||
|
||||
# Publish ApplicationRecord
|
||||
RECORD_ID=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE | jq -r '.id')
|
||||
publish_response=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE)
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to publish record"
|
||||
exit $rc
|
||||
fi
|
||||
RECORD_ID=$(echo $publish_response | jq -r '.id')
|
||||
echo "ApplicationRecord published"
|
||||
echo $RECORD_ID
|
||||
|
||||
@@ -73,15 +79,36 @@ REGISTRY_APP_CRN="crn://snowballtools/applications/snowballtools-base-frontend"
|
||||
|
||||
sleep 2
|
||||
yarn --silent laconic -c $CONFIG_FILE cns name set "$REGISTRY_APP_CRN@${PACKAGE_VERSION}" "$RECORD_ID"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to set name: $REGISTRY_APP_CRN@${PACKAGE_VERSION}"
|
||||
exit $rc
|
||||
fi
|
||||
sleep 2
|
||||
yarn --silent laconic -c $CONFIG_FILE cns name set "$REGISTRY_APP_CRN@${LATEST_HASH}" "$RECORD_ID"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to set hash"
|
||||
exit $rc
|
||||
fi
|
||||
sleep 2
|
||||
# Set name if latest release
|
||||
yarn --silent laconic -c $CONFIG_FILE cns name set "$REGISTRY_APP_CRN" "$RECORD_ID"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to set release"
|
||||
exit $rc
|
||||
fi
|
||||
echo "$REGISTRY_APP_CRN set for ApplicationRecord"
|
||||
|
||||
# Check if record found for REGISTRY_APP_CRN
|
||||
APP_RECORD=$(yarn --silent laconic -c $CONFIG_FILE cns name resolve "$REGISTRY_APP_CRN" | jq '.[0]')
|
||||
query_response=$(yarn --silent laconic -c $CONFIG_FILE cns name resolve "$REGISTRY_APP_CRN")
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to query name"
|
||||
exit $rc
|
||||
fi
|
||||
APP_RECORD=$(echo $query_response | jq '.[0]')
|
||||
if [ -z "$APP_RECORD" ] || [ "null" == "$APP_RECORD" ]; then
|
||||
echo "No record found for $REGISTRY_APP_CRN."
|
||||
exit 1
|
||||
@@ -90,6 +117,11 @@ fi
|
||||
RECORD_FILE=records/application-deployment-request.yml
|
||||
|
||||
sleep 2
|
||||
DEPLOYMENT_REQUEST_ID=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE | jq -r '.id')
|
||||
deployment_response=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE)
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to query deployment request"
|
||||
exit $rc
|
||||
fi
|
||||
DEPLOYMENT_REQUEST_ID=$(echo $deployment_response | jq -r '.id')
|
||||
echo "ApplicationDeploymentRequest published"
|
||||
echo $DEPLOYMENT_REQUEST_ID
|
||||
|
||||
@@ -26,7 +26,7 @@ if [ -z "$NEW_APPLICATION_VERSION" ] || [ "1" == "$NEW_APPLICATION_VERSION" ]; t
|
||||
fi
|
||||
|
||||
# Generate application-deployment-request.yml
|
||||
cat > ./staging-records/application-deployment-request.yml <<EOF
|
||||
cat >./staging-records/application-deployment-request.yml <<EOF
|
||||
record:
|
||||
type: ApplicationDeploymentRequest
|
||||
version: '1.0.0'
|
||||
@@ -36,16 +36,16 @@ record:
|
||||
config:
|
||||
env:
|
||||
LACONIC_HOSTED_CONFIG_server_url: https://snowballtools-base-api.staging.apps.snowballtools.com
|
||||
LACONIC_HOSTED_CONFIG_github_clientid: 905c09553f527d2cdff5
|
||||
LACONIC_HOSTED_CONFIG_github_clientid: Ov23liOaoahRTYd4nSCV
|
||||
LACONIC_HOSTED_CONFIG_github_templaterepo: snowball-tools/test-progressive-web-app
|
||||
LACONIC_HOSTED_CONFIG_github_pwa_templaterepo: snowball-tools/image-upload-pwa-example
|
||||
LACONIC_HOSTED_CONFIG_github_image_upload_templaterepo: snowball-tools-platform/image-upload-pwa-example
|
||||
LACONIC_HOSTED_CONFIG_github_pwa_templaterepo: snowball-tools/test-progressive-web-app
|
||||
LACONIC_HOSTED_CONFIG_github_image_upload_templaterepo: snowball-tools/image-upload-pwa-example
|
||||
LACONIC_HOSTED_CONFIG_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
|
||||
LACONIC_HOSTED_CONFIG_lit_relay_api_key: 15DDD969-E75F-404D-AAD9-58A37C4FD354_snowball
|
||||
LACONIC_HOSTED_CONFIG_aplchemy_api_key: THvPart_gqI5x02RNYSBntlmwA66I_qc
|
||||
LACONIC_HOSTED_CONFIG_bugsnag_api_key: 8c480cd5386079f9dd44f9581264a073
|
||||
LACONIC_HOSTED_CONFIG_passkey_wallet_rpid: localhost
|
||||
LACONIC_HOSTED_CONFIG_turnkey_api_base_url: https://api.turnkey.com/
|
||||
LACONIC_HOSTED_CONFIG_passkey_wallet_rpid: dashboard.staging.apps.snowballtools.com
|
||||
LACONIC_HOSTED_CONFIG_turnkey_api_base_url: https://api.turnkey.com
|
||||
LACONIC_HOSTED_CONFIG_turnkey_organization_id: 5049ae99-5bca-40b3-8317-504384d4e591
|
||||
meta:
|
||||
note: Added by Snowball @ $CURRENT_DATE_TIME
|
||||
@@ -54,7 +54,7 @@ record:
|
||||
EOF
|
||||
|
||||
# Generate application-record.yml with incremented version
|
||||
cat > ./staging-records/application-record.yml <<EOF
|
||||
cat >./staging-records/application-record.yml <<EOF
|
||||
record:
|
||||
type: ApplicationRecord
|
||||
version: $NEW_APPLICATION_VERSION
|
||||
@@ -70,7 +70,13 @@ echo "Files generated successfully."
|
||||
RECORD_FILE=staging-records/application-record.yml
|
||||
|
||||
# Publish ApplicationRecord
|
||||
RECORD_ID=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE | jq -r '.id')
|
||||
publish_response=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE)
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to publish record"
|
||||
exit $rc
|
||||
fi
|
||||
RECORD_ID=$(echo $publish_response | jq -r '.id')
|
||||
echo "ApplicationRecord published"
|
||||
echo $RECORD_ID
|
||||
|
||||
@@ -79,15 +85,36 @@ REGISTRY_APP_CRN="crn://staging-snowballtools/applications/staging-snowballtools
|
||||
|
||||
sleep 2
|
||||
yarn --silent laconic -c $CONFIG_FILE cns name set "$REGISTRY_APP_CRN@${PACKAGE_VERSION}" "$RECORD_ID"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to set name: $REGISTRY_APP_CRN@${PACKAGE_VERSION}"
|
||||
exit $rc
|
||||
fi
|
||||
sleep 2
|
||||
yarn --silent laconic -c $CONFIG_FILE cns name set "$REGISTRY_APP_CRN@${LATEST_HASH}" "$RECORD_ID"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to set hash"
|
||||
exit $rc
|
||||
fi
|
||||
sleep 2
|
||||
# Set name if latest release
|
||||
yarn --silent laconic -c $CONFIG_FILE cns name set "$REGISTRY_APP_CRN" "$RECORD_ID"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to set release"
|
||||
exit $rc
|
||||
fi
|
||||
echo "$REGISTRY_APP_CRN set for ApplicationRecord"
|
||||
|
||||
# Check if record found for REGISTRY_APP_CRN
|
||||
APP_RECORD=$(yarn --silent laconic -c $CONFIG_FILE cns name resolve "$REGISTRY_APP_CRN" | jq '.[0]')
|
||||
query_response=$(yarn --silent laconic -c $CONFIG_FILE cns name resolve "$REGISTRY_APP_CRN")
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to query name"
|
||||
exit $rc
|
||||
fi
|
||||
APP_RECORD=$(echo $query_response | jq '.[0]')
|
||||
if [ -z "$APP_RECORD" ] || [ "null" == "$APP_RECORD" ]; then
|
||||
echo "No record found for $REGISTRY_APP_CRN."
|
||||
exit 1
|
||||
@@ -96,6 +123,11 @@ fi
|
||||
RECORD_FILE=staging-records/application-deployment-request.yml
|
||||
|
||||
sleep 2
|
||||
DEPLOYMENT_REQUEST_ID=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE | jq -r '.id')
|
||||
deployment_response=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE)
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to query deployment request"
|
||||
exit $rc
|
||||
fi
|
||||
DEPLOYMENT_REQUEST_ID=$(echo $deployment_response | jq -r '.id')
|
||||
echo "ApplicationDeploymentRequest published"
|
||||
echo $DEPLOYMENT_REQUEST_ID
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
record:
|
||||
type: ApplicationDeploymentRequest
|
||||
version: '1.0.0'
|
||||
version: "1.0.0"
|
||||
name: snowballtools-base-frontend@0.1.8
|
||||
application: crn://snowballtools/applications/snowballtools-base-frontend@0.1.8
|
||||
dns: dashboard
|
||||
@@ -8,9 +8,9 @@ record:
|
||||
env:
|
||||
LACONIC_HOSTED_CONFIG_app_server_url: https://snowballtools-base-api-001.apps.snowballtools.com
|
||||
LACONIC_HOSTED_CONFIG_app_github_clientid: b7c63b235ca1dd5639ab
|
||||
LACONIC_HOSTED_CONFIG_app_github_templaterepo: snowball-tools-platform/test-progressive-web-app
|
||||
LACONIC_HOSTED_CONFIG_app_github_pwa_templaterepo: snowball-tools-platform/test-progressive-web-app
|
||||
LACONIC_HOSTED_CONFIG_app_github_image_upload_templaterepo: snowball-tools-platform/image-upload-pwa-example
|
||||
LACONIC_HOSTED_CONFIG_app_github_templaterepo: snowball-tools/test-progressive-web-app
|
||||
LACONIC_HOSTED_CONFIG_app_github_pwa_templaterepo: snowball-tools/test-progressive-web-app
|
||||
LACONIC_HOSTED_CONFIG_app_github_image_upload_templaterepo: snowball-tools/image-upload-pwa-example
|
||||
LACONIC_HOSTED_CONFIG_app_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
|
||||
meta:
|
||||
note: Added by Snowball @ Thu Apr 4 14:49:41 UTC 2024
|
||||
|
||||
@@ -7,18 +7,18 @@ record:
|
||||
config:
|
||||
env:
|
||||
LACONIC_HOSTED_CONFIG_server_url: https://snowballtools-base-api.staging.apps.snowballtools.com
|
||||
LACONIC_HOSTED_CONFIG_github_clientid: 905c09553f527d2cdff5
|
||||
LACONIC_HOSTED_CONFIG_github_clientid: Ov23liOaoahRTYd4nSCV
|
||||
LACONIC_HOSTED_CONFIG_github_templaterepo: snowball-tools/test-progressive-web-app
|
||||
LACONIC_HOSTED_CONFIG_github_pwa_templaterepo: snowball-tools/image-upload-pwa-example
|
||||
LACONIC_HOSTED_CONFIG_github_image_upload_templaterepo: snowball-tools-platform/image-upload-pwa-example
|
||||
LACONIC_HOSTED_CONFIG_github_pwa_templaterepo: snowball-tools/test-progressive-web-app
|
||||
LACONIC_HOSTED_CONFIG_github_image_upload_templaterepo: snowball-tools/image-upload-pwa-example
|
||||
LACONIC_HOSTED_CONFIG_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
|
||||
LACONIC_HOSTED_CONFIG_lit_relay_api_key: 15DDD969-E75F-404D-AAD9-58A37C4FD354_snowball
|
||||
LACONIC_HOSTED_CONFIG_aplchemy_api_key: THvPart_gqI5x02RNYSBntlmwA66I_qc
|
||||
LACONIC_HOSTED_CONFIG_bugsnag_api_key: 8c480cd5386079f9dd44f9581264a073
|
||||
LACONIC_HOSTED_CONFIG_passkey_wallet_rpid: localhost
|
||||
LACONIC_HOSTED_CONFIG_turnkey_api_base_url: https://api.turnkey.com/
|
||||
LACONIC_HOSTED_CONFIG_passkey_wallet_rpid: dashboard.staging.apps.snowballtools.com
|
||||
LACONIC_HOSTED_CONFIG_turnkey_api_base_url: https://api.turnkey.com
|
||||
LACONIC_HOSTED_CONFIG_turnkey_organization_id: 5049ae99-5bca-40b3-8317-504384d4e591
|
||||
meta:
|
||||
note: Added by Snowball @ Tuesday 21 May 2024 06:17:23 AM UTC
|
||||
note: Added by Snowball @ Sat Jun 22 02:49:45 UTC 2024
|
||||
repository: "https://git.vdb.to/cerc-io/snowballtools-base"
|
||||
repository_ref: 8488cfab8353321ed05c4234bf1b914c9ad3aa99
|
||||
repository_ref: 61e3e88a6c9d57e95441059369ee5a46f5c07601
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
record:
|
||||
type: ApplicationRecord
|
||||
version: 0.0.2
|
||||
repository_ref: 8488cfab8353321ed05c4234bf1b914c9ad3aa99
|
||||
version: 0.0.1
|
||||
repository_ref: 61e3e88a6c9d57e95441059369ee5a46f5c07601
|
||||
repository: ["https://git.vdb.to/cerc-io/snowballtools-base"]
|
||||
app_type: webapp
|
||||
name: staging-snowballtools-base-frontend
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Check if the live web app deployer is in a working state
|
||||
|
||||
- Web app repo used: https://github.com/snowball-tools-platform/test-progressive-web-app (main branch)
|
||||
- Web app repo used: <https://github.com/snowball-tools/test-progressive-web-app> (main branch)
|
||||
- Config used: [../config.yml](../config.yml)
|
||||
- The script [test-webapp-deployment-undeployment.sh](./test-webapp-deployment-undeployment.sh) performs the following:
|
||||
- Create / update [`ApplicationRecord`](./records/application-record.yml) and [`ApplicationDeploymentRequest`](./records/application-deployment-request.yml) records with latest meta data from the repo
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
record:
|
||||
type: ApplicationDeploymentRequest
|
||||
version: '1.0.0'
|
||||
version: "1.0.0"
|
||||
name: deployment-test-app@0.1.24
|
||||
application: crn://snowballtools/applications/deployment-test-app@0.1.24
|
||||
dns: deployment-ci-test
|
||||
@@ -11,5 +11,5 @@ record:
|
||||
CERC_WEBAPP_DEBUG: 0
|
||||
meta:
|
||||
note: Deployment test @ Thu 11 Apr 2024 07:29:19 AM UTC
|
||||
repository: "https://github.com/snowball-tools-platform/test-progressive-web-app"
|
||||
repository: "https://github.com/snowball-tools/test-progressive-web-app"
|
||||
repository_ref: 05819619487a0d2dbc5453b6d1ccff3044c0dd26
|
||||
|
||||
@@ -2,7 +2,7 @@ record:
|
||||
type: ApplicationRecord
|
||||
version: 0.0.1
|
||||
repository_ref: 05819619487a0d2dbc5453b6d1ccff3044c0dd26
|
||||
repository: ["https://github.com/snowball-tools-platform/test-progressive-web-app"]
|
||||
repository: ["https://github.com/snowball-tools/test-progressive-web-app"]
|
||||
app_type: webapp
|
||||
name: deployment-test-app
|
||||
app_version: 0.1.24
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Repository URL
|
||||
REPO_URL="https://github.com/snowball-tools-platform/test-progressive-web-app"
|
||||
REPO_URL="https://github.com/snowball-tools/test-progressive-web-app"
|
||||
|
||||
# Get the latest commit hash from the repository
|
||||
LATEST_HASH=$(git ls-remote $REPO_URL HEAD | awk '{print $1}')
|
||||
@@ -32,7 +32,7 @@ fi
|
||||
# Generate application-record.yml with incremented version
|
||||
RECORD_FILE=packages/deployer/test/records/application-record.yml
|
||||
|
||||
cat > $RECORD_FILE <<EOF
|
||||
cat >$RECORD_FILE <<EOF
|
||||
record:
|
||||
type: ApplicationRecord
|
||||
version: $NEW_APPLICATION_VERSION
|
||||
@@ -46,7 +46,7 @@ EOF
|
||||
# Generate application-deployment-request.yml
|
||||
REQUEST_RECORD_FILE=packages/deployer/test/records/application-deployment-request.yml
|
||||
|
||||
cat > $REQUEST_RECORD_FILE <<EOF
|
||||
cat >$REQUEST_RECORD_FILE <<EOF
|
||||
record:
|
||||
type: ApplicationDeploymentRequest
|
||||
version: '1.0.0'
|
||||
@@ -115,7 +115,7 @@ while true; do
|
||||
else
|
||||
echo "ApplicationDeploymentRecord not found, retrying in $RETRY_INTERVAL sec..."
|
||||
sleep $RETRY_INTERVAL
|
||||
retry_count=$((retry_count+1))
|
||||
retry_count=$((retry_count + 1))
|
||||
fi
|
||||
else
|
||||
echo "ApplicationDeploymentRecord found"
|
||||
@@ -154,7 +154,7 @@ while true; do
|
||||
else
|
||||
echo "Deployment URL $fetched_url is not active, received code $url_response, retrying in $retry_interval sec..."
|
||||
sleep $retry_interval
|
||||
retry_count=$((retry_count+1))
|
||||
retry_count=$((retry_count + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
@@ -162,7 +162,7 @@ done
|
||||
# Generate application-deployment-removal-request.yml
|
||||
REMOVAL_REQUEST_RECORD_FILE=packages/deployer/test/records/application-deployment-removal-request.yml
|
||||
|
||||
cat > $REMOVAL_REQUEST_RECORD_FILE <<EOF
|
||||
cat >$REMOVAL_REQUEST_RECORD_FILE <<EOF
|
||||
record:
|
||||
deployment: $DEPLOYMENT_RECORD_ID
|
||||
type: ApplicationDeploymentRemovalRequest
|
||||
@@ -190,7 +190,7 @@ while true; do
|
||||
else
|
||||
echo "ApplicationDeploymentRemovalRecord not found, retrying in $RETRY_INTERVAL sec..."
|
||||
sleep $RETRY_INTERVAL
|
||||
retry_count=$((retry_count+1))
|
||||
retry_count=$((retry_count + 1))
|
||||
fi
|
||||
else
|
||||
echo "ApplicationDeploymentRemovalRecord found"
|
||||
@@ -217,7 +217,7 @@ while true; do
|
||||
else
|
||||
echo "Deployment URL $fetched_url is still active, received code $url_response, retrying in $retry_interval sec..."
|
||||
sleep $retry_interval
|
||||
retry_count=$((retry_count+1))
|
||||
retry_count=$((retry_count + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -14,4 +14,4 @@ VITE_BUGSNAG_API_KEY=
|
||||
|
||||
VITE_PASSKEY_WALLET_RPID=
|
||||
VITE_TURNKEY_API_BASE_URL=
|
||||
VITE_TURNKEY_ORGANIZATION_ID=
|
||||
VITE_TURNKEY_ORGANIZATION_ID=
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
dist/
|
||||
@@ -9,6 +9,7 @@ import { join, dirname } from 'path';
|
||||
function getAbsolutePath(value: string): any {
|
||||
return dirname(require.resolve(join(value, 'package.json')));
|
||||
}
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
|
||||
addons: [
|
||||
@@ -26,6 +27,7 @@ const config: StorybookConfig = {
|
||||
docs: {
|
||||
autodocs: 'tag',
|
||||
},
|
||||
staticDirs: ['../public'],
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
+56
-23
@@ -1,30 +1,63 @@
|
||||
# React + TypeScript + Vite
|
||||
# frontend
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
This is a [vite](https://vitejs.dev/) [react](https://reactjs.org/) [nextjs](https://nextjs.org/) project in a [yarn workspace](https://yarnpkg.com/features/workspaces).
|
||||
|
||||
Currently, two official plugins are available:
|
||||
## Getting Started
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
### Install dependencies
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
In the root of the project, run:
|
||||
|
||||
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||
|
||||
- Configure the top-level `parserOptions` property like this:
|
||||
|
||||
```js
|
||||
export default {
|
||||
// other rules...
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
project: ['./tsconfig.json', './tsconfig.node.json'],
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
};
|
||||
```zsh
|
||||
yarn
|
||||
```
|
||||
|
||||
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
|
||||
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
|
||||
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
|
||||
### Build backend
|
||||
|
||||
```zsh
|
||||
yarn build --ignore frontend
|
||||
```
|
||||
|
||||
### Environment variables
|
||||
|
||||
#### Local
|
||||
|
||||
Copy the `.env.example` file to `.env`:
|
||||
|
||||
```zsh
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
#### Staging environment variables
|
||||
|
||||
Change in [deployer/deploy-frontend.staging.sh](/packages/deployer/deploy-frontend.staging.sh)
|
||||
|
||||
#### Production environment variables
|
||||
|
||||
Change in [deployer/deploy-frontend.sh](/packages/deployer/deploy-frontend.sh)
|
||||
|
||||
### Run development server
|
||||
|
||||
```zsh
|
||||
yarn dev
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
From the root of the project, run:
|
||||
|
||||
### Staging
|
||||
|
||||
```zsh
|
||||
cd packages/deployer && ./deploy-frontend.staging.sh
|
||||
```
|
||||
|
||||
### Production
|
||||
|
||||
```zsh
|
||||
cd packages/deployer && ./deploy-frontend.sh
|
||||
```
|
||||
|
||||
### Deployment status
|
||||
|
||||
Check the status of the deployment [here](https://webapp-deployer.apps.snowballtools.com)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useEffect } from 'react';
|
||||
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
||||
|
||||
import Projects from './pages/org-slug';
|
||||
@@ -10,8 +11,8 @@ import ProjectSearchLayout from './layouts/ProjectSearch';
|
||||
import Index from './pages';
|
||||
import AuthPage from './pages/AuthPage';
|
||||
import { DashboardLayout } from './pages/org-slug/layout';
|
||||
import { useEffect } from 'react';
|
||||
import Web3Provider from 'context/Web3Provider';
|
||||
import { baseUrl } from 'utils/constants';
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
@@ -59,7 +60,7 @@ function App() {
|
||||
// Hacky way of checking session
|
||||
// TODO: Handle redirect backs
|
||||
useEffect(() => {
|
||||
fetch(`${import.meta.env.VITE_SERVER_URL}/auth/session`, {
|
||||
fetch(`${baseUrl}/auth/session`, {
|
||||
credentials: 'include',
|
||||
}).then((res) => {
|
||||
if (res.status !== 200) {
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import {
|
||||
VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO,
|
||||
VITE_GITHUB_PWA_TEMPLATE_REPO,
|
||||
} from 'utils/constants';
|
||||
|
||||
export default [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Progressive Web App (PWA)',
|
||||
icon: 'pwa',
|
||||
repoFullName: `${import.meta.env.VITE_GITHUB_PWA_TEMPLATE_REPO}`,
|
||||
repoFullName: `${VITE_GITHUB_PWA_TEMPLATE_REPO}`,
|
||||
isComingSoon: false,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Image Upload PWA',
|
||||
icon: 'pwa',
|
||||
repoFullName: `${import.meta.env.VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO}`,
|
||||
repoFullName: `${VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO}`,
|
||||
isComingSoon: false,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Input, InputProps } from './shared/Input';
|
||||
const SearchBar: React.ForwardRefRenderFunction<
|
||||
HTMLInputElement,
|
||||
InputProps & RefAttributes<HTMLInputElement>
|
||||
> = ({ value, onChange, placeholder = 'Search', ...props }) => {
|
||||
> = ({ value, onChange, placeholder = 'Search', ...props }, ref) => {
|
||||
return (
|
||||
<div className="relative flex w-full">
|
||||
<Input
|
||||
@@ -18,6 +18,7 @@ const SearchBar: React.ForwardRefRenderFunction<
|
||||
appearance="borderless"
|
||||
className="w-full lg:w-[459px]"
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
+1
-1
@@ -96,9 +96,9 @@ export const ProjectSearchBarDialog = ({
|
||||
</p>
|
||||
</div>
|
||||
<ProjectSearchBarItem
|
||||
{...getItemProps({ item, index })}
|
||||
key={item.id}
|
||||
item={item}
|
||||
{...getItemProps({ item, index })}
|
||||
/>
|
||||
</>
|
||||
))
|
||||
|
||||
@@ -14,11 +14,10 @@ import { useToast } from '../../shared/Toast';
|
||||
import { IconWithFrame } from '../../shared/IconWithFrame';
|
||||
import { Heading } from '../../shared/Heading';
|
||||
import { MockConnectGitCard } from './MockConnectGitCard';
|
||||
import { VITE_GITHUB_CLIENT_ID } from 'utils/constants';
|
||||
|
||||
const SCOPES = 'repo user';
|
||||
const GITHUB_OAUTH_URL = `https://github.com/login/oauth/authorize?client_id=${
|
||||
import.meta.env.VITE_GITHUB_CLIENT_ID
|
||||
}&scope=${encodeURIComponent(SCOPES)}`;
|
||||
const GITHUB_OAUTH_URL = `https://github.com/login/oauth/authorize?client_id=${VITE_GITHUB_CLIENT_ID}&scope=${encodeURIComponent(SCOPES)}`;
|
||||
|
||||
interface ConnectAccountInterface {
|
||||
onAuth: (token: string) => void;
|
||||
|
||||
+27
-37
@@ -1,13 +1,8 @@
|
||||
import { CopyBlock, atomOneLight } from 'react-code-blocks';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogHeader,
|
||||
DialogBody,
|
||||
DialogFooter,
|
||||
} from '@snowballtools/material-tailwind-react-fork';
|
||||
import { Modal } from 'components/shared/Modal';
|
||||
import { Button } from 'components/shared/Button';
|
||||
|
||||
interface AssignDomainProps {
|
||||
open: boolean;
|
||||
@@ -16,36 +11,31 @@ interface AssignDomainProps {
|
||||
|
||||
const AssignDomainDialog = ({ open, handleOpen }: AssignDomainProps) => {
|
||||
return (
|
||||
<Dialog open={open} handler={handleOpen}>
|
||||
<DialogHeader>Assign Domain</DialogHeader>
|
||||
<DialogBody>
|
||||
In order to assign a domain to your production deployments, configure it
|
||||
in the{' '}
|
||||
{/* TODO: Fix selection of project settings tab on navigation to domains */}
|
||||
<Link to="../settings/domains" className="text-light-blue-800 inline">
|
||||
project settings{' '}
|
||||
</Link>
|
||||
(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 */}
|
||||
<CopyBlock
|
||||
text="snowball alias <deployment> <domain>"
|
||||
language=""
|
||||
showLineNumbers={false}
|
||||
theme={atomOneLight}
|
||||
/>
|
||||
</DialogBody>
|
||||
<DialogFooter className="flex justify-start">
|
||||
<Button
|
||||
className="rounded-3xl"
|
||||
variant="gradient"
|
||||
color="blue"
|
||||
onClick={handleOpen}
|
||||
>
|
||||
<span>Okay</span>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
<Modal open={open} onOpenChange={handleOpen}>
|
||||
<Modal.Content>
|
||||
<Modal.Header>Assign Domain</Modal.Header>
|
||||
<Modal.Body>
|
||||
In order to assign a domain to your production deployments, configure
|
||||
it in the{' '}
|
||||
{/* TODO: Fix selection of project settings tab on navigation to domains */}
|
||||
<Link to="../settings/domains" className="text-light-blue-800 inline">
|
||||
project settings{' '}
|
||||
</Link>
|
||||
(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 */}
|
||||
<CopyBlock
|
||||
text="snowball alias <deployment> <domain>"
|
||||
language=""
|
||||
showLineNumbers={false}
|
||||
theme={atomOneLight}
|
||||
/>
|
||||
</Modal.Body>
|
||||
<Modal.Footer className="flex justify-start">
|
||||
<Button onClick={handleOpen}>Okay</Button>
|
||||
</Modal.Footer>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { useState } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useState, ComponentPropsWithRef } from 'react';
|
||||
|
||||
import {
|
||||
Menu,
|
||||
MenuHandler,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
} from '@snowballtools/material-tailwind-react-fork';
|
||||
|
||||
import { Deployment, Domain, Environment, Project } from 'gql-client';
|
||||
import { Button } from 'components/shared/Button';
|
||||
import {
|
||||
@@ -11,17 +18,11 @@ import {
|
||||
UndoIcon,
|
||||
CrossCircleIcon,
|
||||
} from 'components/shared/CustomIcon';
|
||||
import {
|
||||
Menu,
|
||||
MenuHandler,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
} from '@snowballtools/material-tailwind-react-fork';
|
||||
import { ComponentPropsWithRef } from 'react';
|
||||
import AssignDomainDialog from './AssignDomainDialog';
|
||||
import { useGQLClient } from 'context/GQLClientContext';
|
||||
import { cn } from 'utils/classnames';
|
||||
import { ChangeStateToProductionDialog } from 'components/projects/Dialog/ChangeStateToProductionDialog';
|
||||
import { useToast } from 'components/shared/Toast';
|
||||
|
||||
interface DeploymentMenuProps extends ComponentPropsWithRef<'div'> {
|
||||
deployment: Deployment;
|
||||
@@ -41,6 +42,7 @@ export const DeploymentMenu = ({
|
||||
...props
|
||||
}: DeploymentMenuProps) => {
|
||||
const client = useGQLClient();
|
||||
const { toast, dismiss } = useToast();
|
||||
|
||||
const [changeToProduction, setChangeToProduction] = useState(false);
|
||||
const [redeployToProduction, setRedeployToProduction] = useState(false);
|
||||
@@ -51,9 +53,19 @@ export const DeploymentMenu = ({
|
||||
const isUpdated = await client.updateDeploymentToProd(deployment.id);
|
||||
if (isUpdated) {
|
||||
await onUpdate();
|
||||
toast.success('Deployment changed to production');
|
||||
toast({
|
||||
id: 'deployment_changed_to_production',
|
||||
title: 'Deployment changed to production',
|
||||
variant: 'success',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
} else {
|
||||
toast.error('Unable to change deployment to production');
|
||||
toast({
|
||||
id: 'deployment_not_changed_to_production',
|
||||
title: 'Error changing deployment to production',
|
||||
variant: 'error',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -61,9 +73,19 @@ export const DeploymentMenu = ({
|
||||
const isRedeployed = await client.redeployToProd(deployment.id);
|
||||
if (isRedeployed) {
|
||||
await onUpdate();
|
||||
toast.success('Redeployed to production');
|
||||
toast({
|
||||
id: 'redeployed_to_production',
|
||||
title: 'Redeployed to production',
|
||||
variant: 'success',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
} else {
|
||||
toast.error('Unable to redeploy to production');
|
||||
toast({
|
||||
id: 'redeployed_to_production_failed',
|
||||
title: 'Error redeploying to production',
|
||||
variant: 'error',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -74,9 +96,19 @@ export const DeploymentMenu = ({
|
||||
);
|
||||
if (isRollbacked) {
|
||||
await onUpdate();
|
||||
toast.success('Deployment rolled back');
|
||||
toast({
|
||||
id: 'deployment_rolled_back',
|
||||
title: 'Deployment rolled back',
|
||||
variant: 'success',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
} else {
|
||||
toast.error('Unable to rollback deployment');
|
||||
toast({
|
||||
id: 'deployment_rollback_failed',
|
||||
title: 'Error rolling back deployment',
|
||||
variant: 'error',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -84,9 +116,19 @@ export const DeploymentMenu = ({
|
||||
const isDeleted = await client.deleteDeployment(deployment.id);
|
||||
if (isDeleted) {
|
||||
await onUpdate();
|
||||
toast.success('Deleted deployment');
|
||||
toast({
|
||||
id: 'deployment_deleted',
|
||||
title: 'Deployment deleted',
|
||||
variant: 'success',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
} else {
|
||||
toast.error('Unable to delete deployment');
|
||||
toast({
|
||||
id: 'deployment_not_deleted',
|
||||
title: 'Error deleting deployment',
|
||||
variant: 'error',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { AddProjectMemberInput, Permission } from 'gql-client';
|
||||
|
||||
import { Typography } from '@snowballtools/material-tailwind-react-fork';
|
||||
|
||||
import { Button } from 'components/shared/Button';
|
||||
import { Modal } from 'components/shared/Modal';
|
||||
import { Input } from 'components/shared/Input';
|
||||
import { Checkbox } from 'components/shared/Checkbox';
|
||||
import { Select, SelectOption } from 'components/shared/Select';
|
||||
import { AddProjectMemberInput, Permission } from 'gql-client';
|
||||
|
||||
interface AddMemberDialogProp {
|
||||
open: boolean;
|
||||
@@ -17,18 +17,30 @@ interface AddMemberDialogProp {
|
||||
|
||||
interface formData {
|
||||
emailAddress: string;
|
||||
permissions: {
|
||||
view: boolean;
|
||||
edit: boolean;
|
||||
};
|
||||
canEdit: boolean;
|
||||
}
|
||||
|
||||
const permissionViewOptions: SelectOption = {
|
||||
value: Permission.View,
|
||||
label: Permission.View,
|
||||
};
|
||||
const permissionEditOptions: SelectOption = {
|
||||
value: Permission.Edit,
|
||||
label: Permission.Edit,
|
||||
};
|
||||
const permissionsDropdownOptions: SelectOption[] = [
|
||||
permissionViewOptions,
|
||||
permissionEditOptions,
|
||||
];
|
||||
|
||||
const AddMemberDialog = ({
|
||||
open,
|
||||
handleOpen,
|
||||
handleAddMember,
|
||||
}: AddMemberDialogProp) => {
|
||||
const {
|
||||
watch,
|
||||
setValue,
|
||||
handleSubmit,
|
||||
register,
|
||||
reset,
|
||||
@@ -36,10 +48,7 @@ const AddMemberDialog = ({
|
||||
} = useForm({
|
||||
defaultValues: {
|
||||
emailAddress: '',
|
||||
permissions: {
|
||||
view: true,
|
||||
edit: false,
|
||||
},
|
||||
canEdit: false,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -47,11 +56,7 @@ const AddMemberDialog = ({
|
||||
reset();
|
||||
handleOpen();
|
||||
|
||||
const permissions = Object.entries(data.permissions)
|
||||
.filter(([, value]) => value)
|
||||
.map(
|
||||
([key]) => key.charAt(0).toUpperCase() + key.slice(1),
|
||||
) as Permission[];
|
||||
const permissions = [data.canEdit ? Permission.Edit : Permission.View];
|
||||
|
||||
await handleAddMember({ email: data.emailAddress, permissions });
|
||||
}, []);
|
||||
@@ -72,19 +77,19 @@ const AddMemberDialog = ({
|
||||
required: 'email field cannot be empty',
|
||||
})}
|
||||
/>
|
||||
<Typography variant="small">Permissions</Typography>
|
||||
<Typography variant="small">
|
||||
You can change this later if required.
|
||||
</Typography>
|
||||
<Checkbox
|
||||
label={Permission.View}
|
||||
{...register(`permissions.view`)}
|
||||
color="blue"
|
||||
/>
|
||||
<Checkbox
|
||||
label={Permission.Edit}
|
||||
{...register(`permissions.edit`)}
|
||||
color="blue"
|
||||
<Select
|
||||
label="Permissions"
|
||||
description="You can change this later if required."
|
||||
options={permissionsDropdownOptions}
|
||||
value={
|
||||
watch('canEdit') ? permissionEditOptions : permissionViewOptions
|
||||
}
|
||||
onChange={(value) =>
|
||||
setValue(
|
||||
'canEdit',
|
||||
(value as SelectOption)!.value === Permission.Edit,
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
useMemo,
|
||||
ComponentPropsWithoutRef,
|
||||
} from 'react';
|
||||
import { FieldValues, UseFormRegister } from 'react-hook-form';
|
||||
|
||||
import { WarningIcon } from 'components/shared/CustomIcon';
|
||||
import { cloneIcon } from 'utils/cloneIcon';
|
||||
@@ -12,7 +11,7 @@ import { cn } from 'utils/classnames';
|
||||
|
||||
import { InputTheme, inputTheme } from './Input.theme';
|
||||
|
||||
export interface InputProps<T extends FieldValues = FieldValues>
|
||||
export interface InputProps
|
||||
extends InputTheme,
|
||||
Omit<ComponentPropsWithoutRef<'input'>, 'size'> {
|
||||
label?: string;
|
||||
@@ -20,9 +19,6 @@ export interface InputProps<T extends FieldValues = FieldValues>
|
||||
leftIcon?: ReactNode;
|
||||
rightIcon?: ReactNode;
|
||||
helperText?: string;
|
||||
|
||||
// react-hook-form optional register
|
||||
register?: ReturnType<UseFormRegister<T>>;
|
||||
}
|
||||
|
||||
const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
@@ -34,7 +30,6 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
leftIcon,
|
||||
rightIcon,
|
||||
helperText,
|
||||
register,
|
||||
size,
|
||||
state,
|
||||
appearance,
|
||||
@@ -107,12 +102,11 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
<div className={containerCls({ class: className })}>
|
||||
{leftIcon && renderLeftIcon}
|
||||
<input
|
||||
{...(register ? register : {})}
|
||||
className={cn(inputCls(), {
|
||||
'pl-10': leftIcon,
|
||||
})}
|
||||
{...props}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
{rightIcon && renderRightIcon}
|
||||
</div>
|
||||
|
||||
@@ -20,6 +20,7 @@ import { cn } from 'utils/classnames';
|
||||
import { useMediaQuery } from 'usehooks-ts';
|
||||
import { SIDEBAR_MENU } from './constants';
|
||||
import { UserSelect } from 'components/shared/UserSelect';
|
||||
import { baseUrl } from 'utils/constants';
|
||||
|
||||
interface SidebarProps {
|
||||
mobileOpen?: boolean;
|
||||
@@ -83,7 +84,7 @@ export const Sidebar = ({ mobileOpen }: SidebarProps) => {
|
||||
}, [orgSlug]);
|
||||
|
||||
const handleLogOut = useCallback(async () => {
|
||||
await fetch(`${import.meta.env.VITE_SERVER_URL}/auth/logout`, {
|
||||
await fetch(`${baseUrl}/auth/logout`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
@@ -103,10 +103,12 @@ export const UserSelect = ({ options, value }: UserSelectProps) => {
|
||||
<div className={theme.container()}>
|
||||
{/* Input */}
|
||||
<div
|
||||
{...getToggleButtonProps({
|
||||
ref: inputWrapperRef,
|
||||
suppressRefError: true,
|
||||
})}
|
||||
{...getToggleButtonProps(
|
||||
{
|
||||
ref: inputWrapperRef,
|
||||
},
|
||||
{ suppressRefError: true },
|
||||
)}
|
||||
onClick={() => !dropdownOpen && openMenu()}
|
||||
className="cursor-pointer relative py-2 pl-2 pr-4 flex min-w-[200px] w-full items-center justify-between rounded-xl bg-surface-card shadow-sm"
|
||||
>
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { Input } from '../Input';
|
||||
|
||||
export interface VerifyCodeInputProps {
|
||||
code: string;
|
||||
setCode: (code: string) => void;
|
||||
submitCode: () => void;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export const VerifyCodeInput = ({
|
||||
code,
|
||||
setCode,
|
||||
submitCode,
|
||||
loading,
|
||||
}: VerifyCodeInputProps) => {
|
||||
const inputRefs = useRef<(HTMLInputElement | null)[]>([]);
|
||||
|
||||
const handlePaste = (
|
||||
e: React.ClipboardEvent<HTMLInputElement>,
|
||||
i: number,
|
||||
) => {
|
||||
e.preventDefault();
|
||||
const pasteData = e.clipboardData.getData('text').replace(/\D/g, ''); // Only digits
|
||||
if (pasteData.length > 0) {
|
||||
let newCodeArray = code.split('');
|
||||
for (let j = 0; j < pasteData.length && i + j < 6; j++) {
|
||||
newCodeArray[i + j] = pasteData[j];
|
||||
}
|
||||
const newCode = newCodeArray.join('');
|
||||
setCode(newCode);
|
||||
const nextIndex = Math.min(i + pasteData.length, 5);
|
||||
const nextInput = inputRefs.current[nextIndex];
|
||||
if (nextInput) nextInput.focus();
|
||||
if (!newCode.includes(' ')) {
|
||||
submitCode();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (
|
||||
e: React.KeyboardEvent<HTMLInputElement>,
|
||||
i: number,
|
||||
) => {
|
||||
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
|
||||
|
||||
if (e.key === 'Backspace') {
|
||||
e.preventDefault();
|
||||
const isEmpty = code[i] === ' ';
|
||||
const newCode = !isEmpty
|
||||
? code.slice(0, i) + ' ' + code.slice(i + 1, 6)
|
||||
: code.slice(0, i - 1) + ' ' + code.slice(i, 6);
|
||||
|
||||
setCode(newCode.slice(0, 6));
|
||||
|
||||
if (i === 0 || !isEmpty) return;
|
||||
const prev = inputRefs.current[i - 1];
|
||||
if (prev) prev.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e.key.match(/[0-9]/)) return;
|
||||
|
||||
e.preventDefault(); // Prevent the default event to avoid duplicate input
|
||||
|
||||
const newCode = code.slice(0, i) + e.key + code.slice(i + 1, 6);
|
||||
setCode(newCode);
|
||||
|
||||
if (i === 5) {
|
||||
submitCode();
|
||||
return;
|
||||
}
|
||||
|
||||
const next = inputRefs.current[i + 1];
|
||||
if (next) next.focus();
|
||||
};
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>, i: number) => {
|
||||
const value = e.target.value.slice(-1);
|
||||
if (!value.match(/[0-9]/)) return;
|
||||
|
||||
const newCode = code.slice(0, i) + value + code.slice(i + 1, 6);
|
||||
setCode(newCode);
|
||||
|
||||
if (i < 5) {
|
||||
const next = inputRefs.current[i + 1];
|
||||
if (next) next.focus();
|
||||
}
|
||||
|
||||
if (!newCode.includes(' ')) {
|
||||
submitCode();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (inputRefs.current[0]) {
|
||||
inputRefs.current[0].focus();
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex gap-2">
|
||||
{code.split('').map((char, i) => (
|
||||
<Input
|
||||
key={i}
|
||||
value={char === ' ' ? '' : char}
|
||||
ref={(el) => (inputRefs.current[i] = el)}
|
||||
onChange={(e) => handleChange(e, i)}
|
||||
onPaste={(e) => handlePaste(e, i)}
|
||||
onKeyDown={(e) => handleKeyDown(e, i)}
|
||||
disabled={!!loading}
|
||||
style={{ textAlign: 'center' }} // Add this line to center text
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export { VerifyCodeInput } from './VerifyCodeInput';
|
||||
@@ -1,9 +1,11 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
|
||||
import { VITE_WALLET_CONNECT_ID } from 'utils/constants';
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
if (!import.meta.env.VITE_WALLET_CONNECT_ID) {
|
||||
if (!VITE_WALLET_CONNECT_ID) {
|
||||
throw new Error('Error: REACT_APP_WALLET_CONNECT_ID env config is not set');
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,17 @@ import { GQLClientProvider } from './context/GQLClientContext';
|
||||
import { SERVER_GQL_PATH } from './constants';
|
||||
import { Toaster } from 'components/shared/Toast';
|
||||
import { LogErrorBoundary } from 'utils/log-error';
|
||||
import { baseUrl } from 'utils/constants';
|
||||
|
||||
// @ts-ignore
|
||||
console.log(`v-${__VERSION__}`);
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement,
|
||||
);
|
||||
|
||||
assert(import.meta.env.VITE_SERVER_URL, 'VITE_SERVER_URL is not set in env');
|
||||
const gqlEndpoint = `${import.meta.env.VITE_SERVER_URL}/${SERVER_GQL_PATH}`;
|
||||
assert(baseUrl, 'VITE_SERVER_URL is not set in env');
|
||||
const gqlEndpoint = `${baseUrl}/${SERVER_GQL_PATH}`;
|
||||
|
||||
const gqlClient = new GQLClient({ gqlEndpoint });
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { Button } from 'components/shared/Button';
|
||||
import {
|
||||
ArrowRightCircleFilledIcon,
|
||||
LoaderIcon,
|
||||
} from 'components/shared/CustomIcon';
|
||||
import { WavyBorder } from 'components/shared/WavyBorder';
|
||||
import { VerifyCodeInput } from 'components/shared/VerifyCodeInput';
|
||||
import { verifyAccessCode } from 'utils/accessCode';
|
||||
|
||||
type AccessMethod = 'accesscode' | 'passkey';
|
||||
|
||||
type Err = { type: AccessMethod; message: string };
|
||||
|
||||
type AccessCodeProps = {
|
||||
onCorrectAccessCode: () => void;
|
||||
};
|
||||
|
||||
export const AccessCode: React.FC<AccessCodeProps> = ({
|
||||
onCorrectAccessCode,
|
||||
}) => {
|
||||
const [accessCode, setAccessCode] = useState(' ');
|
||||
const [error, setError] = useState<Err | null>();
|
||||
const [accessMethod, setAccessMethod] = useState<AccessMethod | false>(false);
|
||||
|
||||
async function validateAccessCode() {
|
||||
setAccessMethod('accesscode');
|
||||
try {
|
||||
const isValidAccessCode = await verifyAccessCode(accessCode);
|
||||
|
||||
// add a pause for ux
|
||||
await new Promise((resolve) => setTimeout(resolve, 250));
|
||||
if (isValidAccessCode) {
|
||||
localStorage.setItem('accessCode', accessCode);
|
||||
onCorrectAccessCode();
|
||||
} else {
|
||||
setError({
|
||||
type: 'accesscode',
|
||||
message: 'Invalid access code',
|
||||
});
|
||||
}
|
||||
} catch (err: any) {
|
||||
setError({ type: 'accesscode', message: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
const loading = accessMethod;
|
||||
const isValidAccessCodeLength = accessCode.trim().length === 5;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="self-stretch p-3 xs:p-6 flex-col justify-center items-center gap-5 flex">
|
||||
<div className="self-stretch text-center text-sky-950 text-2xl font-medium font-display leading-tight">
|
||||
Access Code
|
||||
</div>
|
||||
</div>
|
||||
<WavyBorder className="self-stretch" variant="stroke" />
|
||||
<div className="self-stretch p-4 xs:p-6 flex-col justify-center items-center gap-8 flex">
|
||||
<div className="self-stretch flex-col gap-8 flex">
|
||||
<div className="flex-col justify-start items-start gap-2 inline-flex">
|
||||
<VerifyCodeInput
|
||||
loading={!!loading}
|
||||
code={accessCode}
|
||||
setCode={setAccessCode}
|
||||
submitCode={validateAccessCode}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
rightIcon={
|
||||
loading && loading === 'accesscode' ? (
|
||||
<LoaderIcon className="animate-spin" />
|
||||
) : (
|
||||
<ArrowRightCircleFilledIcon height="16" />
|
||||
)
|
||||
}
|
||||
onClick={validateAccessCode}
|
||||
variant={'secondary'}
|
||||
disabled={!accessCode || !isValidAccessCodeLength || !!loading}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
{error && error.type === 'accesscode' && (
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="justify-center items-center gap-2 inline-flex">
|
||||
<div className="text-red-500 text-sm">
|
||||
Error: {error.message}.{' '}
|
||||
<a href="/signup" className="underline">
|
||||
Try again?
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { AccessCode } from './AccessCode';
|
||||
import { SignUp } from './SignUp';
|
||||
|
||||
type AccessSignUpProps = {
|
||||
onDone: () => void;
|
||||
};
|
||||
|
||||
export const AccessSignUp: React.FC<AccessSignUpProps> = ({ onDone }) => {
|
||||
const [isValidAccessCode, setIsValidAccessCode] = useState<boolean>(
|
||||
!!localStorage.getItem('accessCode'),
|
||||
);
|
||||
|
||||
return isValidAccessCode ? (
|
||||
<SignUp onDone={onDone} />
|
||||
) : (
|
||||
<AccessCode onCorrectAccessCode={() => setIsValidAccessCode(true)} />
|
||||
);
|
||||
};
|
||||
@@ -47,7 +47,9 @@ export const Login = ({ onDone }: Props) => {
|
||||
console.log('Handling google redirect back');
|
||||
try {
|
||||
await google.handleOAuthRedirectBack();
|
||||
// @ts-ignore
|
||||
wallet = await google.getEthersWallet();
|
||||
// @ts-ignore
|
||||
const result = await signInWithEthereum(1, 'login', wallet);
|
||||
if (result.error) {
|
||||
setError(result.error);
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
turnkeySignin,
|
||||
turnkeySignup,
|
||||
} from 'utils/turnkey-frontend';
|
||||
import { verifyAccessCode } from 'utils/accessCode';
|
||||
|
||||
type Provider = 'google' | 'github' | 'apple' | 'email';
|
||||
|
||||
@@ -45,7 +46,9 @@ export const SignUp = ({ onDone }: Props) => {
|
||||
setProvider('google');
|
||||
try {
|
||||
await google.handleOAuthRedirectBack();
|
||||
// @ts-ignore
|
||||
wallet = await google.getEthersWallet();
|
||||
// @ts-ignore
|
||||
const result = await signInWithEthereum(1, 'signup', wallet);
|
||||
if (result.error) {
|
||||
setError({ type: 'provider', message: result.error });
|
||||
@@ -109,6 +112,29 @@ export const SignUp = ({ onDone }: Props) => {
|
||||
const loading = provider;
|
||||
const emailValid = /.@./.test(email);
|
||||
|
||||
useEffect(() => {
|
||||
const validateAccessCode = async () => {
|
||||
const accessCode = localStorage.getItem('accessCode');
|
||||
if (!accessCode) {
|
||||
redirectToSignup();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await verifyAccessCode(accessCode);
|
||||
} catch (err: any) {
|
||||
redirectToSignup();
|
||||
}
|
||||
};
|
||||
|
||||
const redirectToSignup = () => {
|
||||
localStorage.removeItem('accessCode');
|
||||
window.location.href = '/signup';
|
||||
};
|
||||
|
||||
validateAccessCode();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="self-stretch p-3 xs:p-6 flex-col justify-center items-center gap-5 flex">
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { snowball } from 'utils/use-snowball';
|
||||
import { Login } from './Login';
|
||||
import { SignUp } from './SignUp';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Done } from './Done';
|
||||
import { AccessSignUp } from './AccessSignUp';
|
||||
|
||||
type Screen = 'login' | 'signup' | 'success';
|
||||
|
||||
const DASHBOARD_URL = '/';
|
||||
|
||||
export const SnowballAuth = () => {
|
||||
export const SnowballAuth: React.FC = () => {
|
||||
const path = window.location.pathname;
|
||||
const [screen, setScreen] = useState<Screen>(
|
||||
path === '/login' ? 'login' : 'signup',
|
||||
@@ -30,7 +31,7 @@ export const SnowballAuth = () => {
|
||||
|
||||
if (screen === 'signup') {
|
||||
return (
|
||||
<SignUp
|
||||
<AccessSignUp
|
||||
onDone={() => {
|
||||
setScreen('success');
|
||||
}}
|
||||
|
||||
@@ -11,7 +11,10 @@ import { Template } from '../../../../../types/types';
|
||||
import { Heading } from 'components/shared/Heading';
|
||||
import { Input } from 'components/shared/Input';
|
||||
import { Select, SelectOption } from 'components/shared/Select';
|
||||
import { ArrowRightCircleFilledIcon } from 'components/shared/CustomIcon';
|
||||
import {
|
||||
ArrowRightCircleFilledIcon,
|
||||
LoadingIcon,
|
||||
} from 'components/shared/CustomIcon';
|
||||
import { Checkbox } from 'components/shared/Checkbox';
|
||||
import { Button } from 'components/shared/Button';
|
||||
import { useToast } from 'components/shared/Toast';
|
||||
@@ -50,36 +53,22 @@ const CreateRepo = () => {
|
||||
assert(template.repoFullName, 'Template URL not provided');
|
||||
const [owner, repo] = template.repoFullName.split('/');
|
||||
|
||||
// TODO: Handle this functionality in backend
|
||||
const gitRepo = await octokit?.rest.repos.createUsingTemplate({
|
||||
template_owner: owner,
|
||||
template_repo: repo,
|
||||
owner: data.account,
|
||||
name: data.repoName,
|
||||
include_all_branches: false,
|
||||
private: data.isPrivate,
|
||||
});
|
||||
setIsLoading(true);
|
||||
|
||||
if (!gitRepo) {
|
||||
return;
|
||||
}
|
||||
const { addProjectFromTemplate } = await client.addProjectFromTemplate(
|
||||
orgSlug!,
|
||||
{
|
||||
templateOwner: owner,
|
||||
templateRepo: repo,
|
||||
owner: data.account,
|
||||
name: data.repoName,
|
||||
isPrivate: false,
|
||||
},
|
||||
);
|
||||
|
||||
// Refetch to always get correct default branch
|
||||
const templateRepo = await octokit.rest.repos.get({
|
||||
owner: template.repoFullName.split('/')[0],
|
||||
repo: template.repoFullName.split('/')[1],
|
||||
});
|
||||
const prodBranch = templateRepo.data.default_branch ?? 'main';
|
||||
|
||||
const { addProject } = await client.addProject(orgSlug!, {
|
||||
name: `${gitRepo.data.owner!.login}-${gitRepo.data.name}`,
|
||||
prodBranch,
|
||||
repository: gitRepo.data.full_name,
|
||||
// TODO: Set selected template
|
||||
template: 'webapp',
|
||||
});
|
||||
|
||||
navigate(`deploy?projectId=${addProject.id}&templateId=${template.id}`);
|
||||
navigate(
|
||||
`deploy?projectId=${addProjectFromTemplate.id}&templateId=${template.id}`,
|
||||
);
|
||||
} catch (err) {
|
||||
setIsLoading(false);
|
||||
|
||||
@@ -206,7 +195,13 @@ const CreateRepo = () => {
|
||||
{...buttonSize}
|
||||
type="submit"
|
||||
disabled={!Boolean(template.repoFullName) || isLoading}
|
||||
rightIcon={<ArrowRightCircleFilledIcon />}
|
||||
rightIcon={
|
||||
isLoading ? (
|
||||
<LoadingIcon className="animate-spin" />
|
||||
) : (
|
||||
<ArrowRightCircleFilledIcon />
|
||||
)
|
||||
}
|
||||
>
|
||||
Deploy
|
||||
</Button>
|
||||
|
||||
@@ -16,7 +16,7 @@ const FIRST_MEMBER_CARD = 0;
|
||||
|
||||
const CollaboratorsTabPanel = () => {
|
||||
const client = useGQLClient();
|
||||
const { toast } = useToast();
|
||||
const { toast, dismiss } = useToast();
|
||||
const { project } = useOutletContext<OutletContextType>();
|
||||
|
||||
const [addmemberDialogOpen, setAddMemberDialogOpen] = useState(false);
|
||||
@@ -39,14 +39,14 @@ const CollaboratorsTabPanel = () => {
|
||||
id: 'member_added',
|
||||
title: 'Member added to project',
|
||||
variant: 'success',
|
||||
onDismiss() {},
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
id: 'member_not_added',
|
||||
title: 'Invitation not sent',
|
||||
variant: 'error',
|
||||
onDismiss() {},
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -63,14 +63,14 @@ const CollaboratorsTabPanel = () => {
|
||||
id: 'member_removed',
|
||||
title: 'Member removed from project',
|
||||
variant: 'success',
|
||||
onDismiss() {},
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
id: 'member_not_removed',
|
||||
title: 'Not able to remove member',
|
||||
variant: 'error',
|
||||
onDismiss() {},
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -86,14 +86,14 @@ const CollaboratorsTabPanel = () => {
|
||||
id: 'member_permission_updated',
|
||||
title: 'Project member permission updated',
|
||||
variant: 'success',
|
||||
onDismiss() {},
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
id: 'member_permission_not_updated',
|
||||
title: 'Project member permission not updated',
|
||||
variant: 'error',
|
||||
onDismiss() {},
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -6,9 +6,13 @@ const meta: Meta<typeof ChevronDownSmallIcon> = {
|
||||
title: 'Icons/ChevronDownSmallIcon',
|
||||
component: ChevronDownSmallIcon,
|
||||
tags: ['autodocs'],
|
||||
args: {
|
||||
size: 'string | number' as unknown as any,
|
||||
name: 'string',
|
||||
argTypes: {
|
||||
size: {
|
||||
control: 'text',
|
||||
},
|
||||
name: {
|
||||
control: 'text',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -6,9 +6,13 @@ const meta: Meta<typeof ChevronRight> = {
|
||||
title: 'Icons/ChevronRight',
|
||||
component: ChevronRight,
|
||||
tags: ['autodocs'],
|
||||
args: {
|
||||
size: 'string | number' as unknown as any,
|
||||
name: 'string',
|
||||
argTypes: {
|
||||
size: {
|
||||
control: 'text',
|
||||
},
|
||||
name: {
|
||||
control: 'text',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -6,9 +6,13 @@ const meta: Meta<typeof ChevronUpDown> = {
|
||||
title: 'Icons/ChevronUpDown',
|
||||
component: ChevronUpDown,
|
||||
tags: ['autodocs'],
|
||||
args: {
|
||||
size: 'string | number' as unknown as any,
|
||||
name: 'string',
|
||||
argTypes: {
|
||||
size: {
|
||||
control: 'text',
|
||||
},
|
||||
name: {
|
||||
control: 'text',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -3,12 +3,16 @@ import { Meta, StoryObj } from '@storybook/react';
|
||||
import { ChevronUpSmallIcon } from 'components/shared/CustomIcon';
|
||||
|
||||
const meta: Meta<typeof ChevronUpSmallIcon> = {
|
||||
title: 'Components/ChevronUpSmallIcon',
|
||||
title: 'Icons/ChevronUpSmallIcon',
|
||||
component: ChevronUpSmallIcon,
|
||||
tags: ['autodocs'],
|
||||
args: {
|
||||
size: 'string | number' as unknown as any,
|
||||
name: 'string',
|
||||
argTypes: {
|
||||
size: {
|
||||
control: 'text',
|
||||
},
|
||||
name: {
|
||||
control: 'text',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Meta, StoryObj } from '@storybook/react';
|
||||
import { CollaboratorsIcon } from 'components/shared/CustomIcon';
|
||||
|
||||
const meta: Meta<typeof CollaboratorsIcon> = {
|
||||
title: 'Components/CollaboratorsIcon',
|
||||
title: 'Icons/CollaboratorsIcon',
|
||||
component: CollaboratorsIcon,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { baseUrl } from './constants';
|
||||
|
||||
export async function verifyAccessCode(
|
||||
accesscode: string,
|
||||
): Promise<boolean | null> {
|
||||
const res = await fetch(`${baseUrl}/auth/accesscode`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
accesscode,
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
});
|
||||
// If API returns a non-empty 200, this is a valid access code.
|
||||
if (res.status == 200) {
|
||||
const isValid = (await res.json()).isValid as boolean;
|
||||
console.log('isValid', isValid);
|
||||
return isValid;
|
||||
} else if (res.status === 204) {
|
||||
return null;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Unexpected response from access code endpoint: ${res.status}: ${await res.text()}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export const baseUrl = import.meta.env.VITE_SERVER_URL;
|
||||
export const PASSKEY_WALLET_RPID = import.meta.env.VITE_PASSKEY_WALLET_RPID!;
|
||||
export const TURNKEY_BASE_URL = import.meta.env.VITE_TURNKEY_API_BASE_URL!;
|
||||
export const VITE_GITHUB_PWA_TEMPLATE_REPO = import.meta.env
|
||||
.VITE_GITHUB_PWA_TEMPLATE_REPO;
|
||||
export const VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO = import.meta.env
|
||||
.VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO;
|
||||
export const VITE_GITHUB_CLIENT_ID = import.meta.env.VITE_GITHUB_CLIENT_ID;
|
||||
export const VITE_WALLET_CONNECT_ID = import.meta.env.VITE_WALLET_CONNECT_ID;
|
||||
export const VITE_BUGSNAG_API_KEY = import.meta.env.VITE_BUGSNAG_API_KEY;
|
||||
export const VITE_LIT_RELAY_API_KEY = import.meta.env.VITE_LIT_RELAY_API_KEY;
|
||||
@@ -1,21 +1,21 @@
|
||||
import React from 'react';
|
||||
import Bugsnag from '@bugsnag/js';
|
||||
import BugsnagPluginReact from '@bugsnag/plugin-react';
|
||||
import BugsnagPerformance from '@bugsnag/browser-performance';
|
||||
import React from 'react';
|
||||
|
||||
const bugsnagApiKey = import.meta.env.VITE_BUGSNAG_API_KEY;
|
||||
import { VITE_BUGSNAG_API_KEY } from './constants';
|
||||
|
||||
if (bugsnagApiKey) {
|
||||
if (VITE_BUGSNAG_API_KEY) {
|
||||
Bugsnag.start({
|
||||
apiKey: bugsnagApiKey,
|
||||
apiKey: VITE_BUGSNAG_API_KEY,
|
||||
plugins: [new BugsnagPluginReact()],
|
||||
});
|
||||
BugsnagPerformance.start({ apiKey: bugsnagApiKey });
|
||||
BugsnagPerformance.start({ apiKey: VITE_BUGSNAG_API_KEY });
|
||||
}
|
||||
|
||||
export const errorLoggingEnabled = !!bugsnagApiKey;
|
||||
export const errorLoggingEnabled = !!VITE_BUGSNAG_API_KEY;
|
||||
|
||||
export const LogErrorBoundary = bugsnagApiKey
|
||||
export const LogErrorBoundary = VITE_BUGSNAG_API_KEY
|
||||
? Bugsnag.getPlugin('react')!.createErrorBoundary(React)
|
||||
: ({ children }: any) => children;
|
||||
|
||||
@@ -28,7 +28,7 @@ export function logError(error: Error) {
|
||||
}
|
||||
console.error(...errors);
|
||||
|
||||
if (import.meta.env.VITE_BUGSNAG_API_KEY) {
|
||||
if (VITE_BUGSNAG_API_KEY) {
|
||||
Bugsnag.notify(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import { SiweMessage } from 'siwe';
|
||||
import { PKPEthersWallet } from '@lit-protocol/pkp-ethers';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { baseUrl } from './constants';
|
||||
|
||||
const domain = window.location.host;
|
||||
const origin = window.location.origin;
|
||||
|
||||
@@ -17,7 +19,7 @@ export async function signInWithEthereum(
|
||||
);
|
||||
const signature = await wallet.signMessage(message);
|
||||
|
||||
const res = await fetch(`${import.meta.env.VITE_SERVER_URL}/auth/validate`, {
|
||||
const res = await fetch(`${baseUrl}/auth/validate`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { TurnkeyClient, getWebAuthnAttestation } from '@turnkey/http';
|
||||
import { WebauthnStamper } from '@turnkey/webauthn-stamper';
|
||||
|
||||
const baseUrl = import.meta.env.VITE_SERVER_URL;
|
||||
|
||||
const PASSKEY_WALLET_RPID = import.meta.env.VITE_PASSKEY_WALLET_RPID!;
|
||||
const TURNKEY_BASE_URL = import.meta.env.VITE_TURNKEY_API_BASE_URL!;
|
||||
import { baseUrl, PASSKEY_WALLET_RPID, TURNKEY_BASE_URL } from './constants';
|
||||
|
||||
// All algorithms can be found here: https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
||||
// We only support ES256, which is listed here
|
||||
|
||||
@@ -5,16 +5,17 @@ import {
|
||||
LitGoogleAuth,
|
||||
LitPasskeyAuth,
|
||||
} from '@snowballtools/auth-lit';
|
||||
import { VITE_LIT_RELAY_API_KEY } from './constants';
|
||||
|
||||
export const snowball = Snowball.withAuth({
|
||||
google: LitGoogleAuth.configure({
|
||||
litRelayApiKey: import.meta.env.VITE_LIT_RELAY_API_KEY!,
|
||||
litRelayApiKey: VITE_LIT_RELAY_API_KEY!,
|
||||
}),
|
||||
// apple: LitAppleAuth.configure({
|
||||
// litRelayApiKey: import.meta.env.VITE_LIT_RELAY_API_KEY!,
|
||||
// litRelayApiKey: VITE_LIT_RELAY_API_KEY!,
|
||||
// }),
|
||||
passkey: LitPasskeyAuth.configure({
|
||||
litRelayApiKey: import.meta.env.VITE_LIT_RELAY_API_KEY!,
|
||||
litRelayApiKey: VITE_LIT_RELAY_API_KEY!,
|
||||
}),
|
||||
}).create({
|
||||
initialChain: SnowballChain.sepolia,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { defineConfig, PluginOption } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
@@ -16,5 +18,8 @@ export default defineConfig({
|
||||
},
|
||||
define: {
|
||||
'process.env': {},
|
||||
__VERSION__: JSON.stringify(
|
||||
(await promisify(exec)('git rev-parse --short HEAD')).stdout.trim(),
|
||||
),
|
||||
},
|
||||
});
|
||||
|
||||
Vendored
+12
-1
@@ -185,6 +185,9 @@ type RemoveEnvironmentVariableResponse = {
|
||||
type UpdateDeploymentToProdResponse = {
|
||||
updateDeploymentToProd: boolean;
|
||||
};
|
||||
type AddProjectFromTemplateResponse = {
|
||||
addProjectFromTemplate: Project;
|
||||
};
|
||||
type AddProjectResponse = {
|
||||
addProject: Project;
|
||||
};
|
||||
@@ -200,6 +203,13 @@ type DeleteProjectResponse = {
|
||||
type DeleteDomainResponse = {
|
||||
deleteDomain: boolean;
|
||||
};
|
||||
type AddProjectFromTemplateInput = {
|
||||
templateOwner: string;
|
||||
templateRepo: string;
|
||||
owner: string;
|
||||
name: string;
|
||||
isPrivate: boolean;
|
||||
};
|
||||
type AddProjectInput = {
|
||||
name: string;
|
||||
repository: string;
|
||||
@@ -267,6 +277,7 @@ declare class GQLClient {
|
||||
updateEnvironmentVariable(environmentVariableId: string, data: UpdateEnvironmentVariableInput): Promise<UpdateEnvironmentVariableResponse>;
|
||||
removeEnvironmentVariable(environmentVariableId: string): Promise<RemoveEnvironmentVariableResponse>;
|
||||
updateDeploymentToProd(deploymentId: string): Promise<UpdateDeploymentToProdResponse>;
|
||||
addProjectFromTemplate(organizationSlug: string, data: AddProjectFromTemplateInput): Promise<AddProjectFromTemplateResponse>;
|
||||
addProject(organizationSlug: string, data: AddProjectInput): Promise<AddProjectResponse>;
|
||||
updateProject(projectId: string, data: UpdateProjectInput): Promise<UpdateProjectResponse>;
|
||||
updateDomain(domainId: string, data: UpdateDomainInput): Promise<UpdateDomainResponse>;
|
||||
@@ -281,4 +292,4 @@ declare class GQLClient {
|
||||
unauthenticateGithub(): Promise<UnauthenticateGitHubResponse>;
|
||||
}
|
||||
|
||||
export { type AddDomainInput, type AddDomainResponse, type AddEnvironmentVariableInput, type AddEnvironmentVariablesResponse, type AddProjectInput, type AddProjectMemberInput, type AddProjectMemberResponse, type AddProjectResponse, type AuthenticateGitHubResponse, type DeleteDeploymentResponse, type DeleteDomainResponse, type DeleteProjectResponse, type Deployment, DeploymentStatus, type Domain, DomainStatus, Environment, type EnvironmentVariable, type FilterDomainInput, GQLClient, type GetDeploymentsResponse, type GetDomainsResponse, type GetEnvironmentVariablesResponse, type GetOrganizationsResponse, type GetProjectMembersResponse, type GetProjectResponse, type GetProjectsInOrganizationResponse, type GetUserResponse, type GraphQLConfig, type Organization, type OrganizationMember, type OrganizationProject, Permission, type Project, type ProjectMember, type RedeployToProdResponse, type RemoveEnvironmentVariableResponse, type RemoveProjectMemberResponse, Role, type RollbackDeploymentResponse, type SearchProjectsResponse, type UnauthenticateGitHubResponse, type UpdateDeploymentToProdResponse, type UpdateDomainInput, type UpdateDomainResponse, type UpdateEnvironmentVariableInput, type UpdateEnvironmentVariableResponse, type UpdateProjectInput, type UpdateProjectMemberInput, type UpdateProjectMemberResponse, type UpdateProjectResponse, type User };
|
||||
export { type AddDomainInput, type AddDomainResponse, type AddEnvironmentVariableInput, type AddEnvironmentVariablesResponse, type AddProjectFromTemplateInput, type AddProjectFromTemplateResponse, type AddProjectInput, type AddProjectMemberInput, type AddProjectMemberResponse, type AddProjectResponse, type AuthenticateGitHubResponse, type DeleteDeploymentResponse, type DeleteDomainResponse, type DeleteProjectResponse, type Deployment, DeploymentStatus, type Domain, DomainStatus, Environment, type EnvironmentVariable, type FilterDomainInput, GQLClient, type GetDeploymentsResponse, type GetDomainsResponse, type GetEnvironmentVariablesResponse, type GetOrganizationsResponse, type GetProjectMembersResponse, type GetProjectResponse, type GetProjectsInOrganizationResponse, type GetUserResponse, type GraphQLConfig, type Organization, type OrganizationMember, type OrganizationProject, Permission, type Project, type ProjectMember, type RedeployToProdResponse, type RemoveEnvironmentVariableResponse, type RemoveProjectMemberResponse, Role, type RollbackDeploymentResponse, type SearchProjectsResponse, type UnauthenticateGitHubResponse, type UpdateDeploymentToProdResponse, type UpdateDomainInput, type UpdateDomainResponse, type UpdateEnvironmentVariableInput, type UpdateEnvironmentVariableResponse, type UpdateProjectInput, type UpdateProjectMemberInput, type UpdateProjectMemberResponse, type UpdateProjectResponse, type User };
|
||||
|
||||
Vendored
+12
-1
@@ -185,6 +185,9 @@ type RemoveEnvironmentVariableResponse = {
|
||||
type UpdateDeploymentToProdResponse = {
|
||||
updateDeploymentToProd: boolean;
|
||||
};
|
||||
type AddProjectFromTemplateResponse = {
|
||||
addProjectFromTemplate: Project;
|
||||
};
|
||||
type AddProjectResponse = {
|
||||
addProject: Project;
|
||||
};
|
||||
@@ -200,6 +203,13 @@ type DeleteProjectResponse = {
|
||||
type DeleteDomainResponse = {
|
||||
deleteDomain: boolean;
|
||||
};
|
||||
type AddProjectFromTemplateInput = {
|
||||
templateOwner: string;
|
||||
templateRepo: string;
|
||||
owner: string;
|
||||
name: string;
|
||||
isPrivate: boolean;
|
||||
};
|
||||
type AddProjectInput = {
|
||||
name: string;
|
||||
repository: string;
|
||||
@@ -267,6 +277,7 @@ declare class GQLClient {
|
||||
updateEnvironmentVariable(environmentVariableId: string, data: UpdateEnvironmentVariableInput): Promise<UpdateEnvironmentVariableResponse>;
|
||||
removeEnvironmentVariable(environmentVariableId: string): Promise<RemoveEnvironmentVariableResponse>;
|
||||
updateDeploymentToProd(deploymentId: string): Promise<UpdateDeploymentToProdResponse>;
|
||||
addProjectFromTemplate(organizationSlug: string, data: AddProjectFromTemplateInput): Promise<AddProjectFromTemplateResponse>;
|
||||
addProject(organizationSlug: string, data: AddProjectInput): Promise<AddProjectResponse>;
|
||||
updateProject(projectId: string, data: UpdateProjectInput): Promise<UpdateProjectResponse>;
|
||||
updateDomain(domainId: string, data: UpdateDomainInput): Promise<UpdateDomainResponse>;
|
||||
@@ -281,4 +292,4 @@ declare class GQLClient {
|
||||
unauthenticateGithub(): Promise<UnauthenticateGitHubResponse>;
|
||||
}
|
||||
|
||||
export { type AddDomainInput, type AddDomainResponse, type AddEnvironmentVariableInput, type AddEnvironmentVariablesResponse, type AddProjectInput, type AddProjectMemberInput, type AddProjectMemberResponse, type AddProjectResponse, type AuthenticateGitHubResponse, type DeleteDeploymentResponse, type DeleteDomainResponse, type DeleteProjectResponse, type Deployment, DeploymentStatus, type Domain, DomainStatus, Environment, type EnvironmentVariable, type FilterDomainInput, GQLClient, type GetDeploymentsResponse, type GetDomainsResponse, type GetEnvironmentVariablesResponse, type GetOrganizationsResponse, type GetProjectMembersResponse, type GetProjectResponse, type GetProjectsInOrganizationResponse, type GetUserResponse, type GraphQLConfig, type Organization, type OrganizationMember, type OrganizationProject, Permission, type Project, type ProjectMember, type RedeployToProdResponse, type RemoveEnvironmentVariableResponse, type RemoveProjectMemberResponse, Role, type RollbackDeploymentResponse, type SearchProjectsResponse, type UnauthenticateGitHubResponse, type UpdateDeploymentToProdResponse, type UpdateDomainInput, type UpdateDomainResponse, type UpdateEnvironmentVariableInput, type UpdateEnvironmentVariableResponse, type UpdateProjectInput, type UpdateProjectMemberInput, type UpdateProjectMemberResponse, type UpdateProjectResponse, type User };
|
||||
export { type AddDomainInput, type AddDomainResponse, type AddEnvironmentVariableInput, type AddEnvironmentVariablesResponse, type AddProjectFromTemplateInput, type AddProjectFromTemplateResponse, type AddProjectInput, type AddProjectMemberInput, type AddProjectMemberResponse, type AddProjectResponse, type AuthenticateGitHubResponse, type DeleteDeploymentResponse, type DeleteDomainResponse, type DeleteProjectResponse, type Deployment, DeploymentStatus, type Domain, DomainStatus, Environment, type EnvironmentVariable, type FilterDomainInput, GQLClient, type GetDeploymentsResponse, type GetDomainsResponse, type GetEnvironmentVariablesResponse, type GetOrganizationsResponse, type GetProjectMembersResponse, type GetProjectResponse, type GetProjectsInOrganizationResponse, type GetUserResponse, type GraphQLConfig, type Organization, type OrganizationMember, type OrganizationProject, Permission, type Project, type ProjectMember, type RedeployToProdResponse, type RemoveEnvironmentVariableResponse, type RemoveProjectMemberResponse, Role, type RollbackDeploymentResponse, type SearchProjectsResponse, type UnauthenticateGitHubResponse, type UpdateDeploymentToProdResponse, type UpdateDomainInput, type UpdateDomainResponse, type UpdateEnvironmentVariableInput, type UpdateEnvironmentVariableResponse, type UpdateProjectInput, type UpdateProjectMemberInput, type UpdateProjectMemberResponse, type UpdateProjectResponse, type User };
|
||||
|
||||
Vendored
+87
-56
@@ -267,93 +267,112 @@ query ($projectId: String!, $filter: FilterDomainsInput) {
|
||||
// src/mutations.ts
|
||||
var import_client2 = require("@apollo/client");
|
||||
var removeProjectMember = import_client2.gql`
|
||||
mutation ($projectMemberId: String!) {
|
||||
removeProjectMember(projectMemberId: $projectMemberId)
|
||||
}
|
||||
mutation ($projectMemberId: String!) {
|
||||
removeProjectMember(projectMemberId: $projectMemberId)
|
||||
}
|
||||
`;
|
||||
var updateProjectMember = import_client2.gql`
|
||||
mutation ($projectMemberId: String!, $data: UpdateProjectMemberInput) {
|
||||
updateProjectMember(projectMemberId: $projectMemberId, data: $data)
|
||||
}
|
||||
mutation ($projectMemberId: String!, $data: UpdateProjectMemberInput) {
|
||||
updateProjectMember(projectMemberId: $projectMemberId, data: $data)
|
||||
}
|
||||
`;
|
||||
var addProjectMember = import_client2.gql`
|
||||
mutation ($projectId: String!, $data: AddProjectMemberInput) {
|
||||
addProjectMember(projectId: $projectId, data: $data)
|
||||
}
|
||||
mutation ($projectId: String!, $data: AddProjectMemberInput) {
|
||||
addProjectMember(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
var addEnvironmentVariables = import_client2.gql`
|
||||
mutation ($projectId: String!, $data: [AddEnvironmentVariableInput!]) {
|
||||
addEnvironmentVariables(projectId: $projectId, data: $data)
|
||||
}
|
||||
mutation ($projectId: String!, $data: [AddEnvironmentVariableInput!]) {
|
||||
addEnvironmentVariables(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
var updateEnvironmentVariable = import_client2.gql`
|
||||
mutation ($environmentVariableId: String!, $data: UpdateEnvironmentVariableInput!) {
|
||||
updateEnvironmentVariable(environmentVariableId: $environmentVariableId, data: $data)
|
||||
}
|
||||
mutation (
|
||||
$environmentVariableId: String!
|
||||
$data: UpdateEnvironmentVariableInput!
|
||||
) {
|
||||
updateEnvironmentVariable(
|
||||
environmentVariableId: $environmentVariableId
|
||||
data: $data
|
||||
)
|
||||
}
|
||||
`;
|
||||
var removeEnvironmentVariable = import_client2.gql`
|
||||
mutation ($environmentVariableId: String!) {
|
||||
removeEnvironmentVariable(environmentVariableId: $environmentVariableId)
|
||||
}
|
||||
mutation ($environmentVariableId: String!) {
|
||||
removeEnvironmentVariable(environmentVariableId: $environmentVariableId)
|
||||
}
|
||||
`;
|
||||
var updateDeploymentToProd = import_client2.gql`
|
||||
mutation ($deploymentId: String!) {
|
||||
updateDeploymentToProd(deploymentId: $deploymentId)
|
||||
}
|
||||
mutation ($deploymentId: String!) {
|
||||
updateDeploymentToProd(deploymentId: $deploymentId)
|
||||
}
|
||||
`;
|
||||
var addProjectFromTemplate = import_client2.gql`
|
||||
mutation ($organizationSlug: String!, $data: AddProjectFromTemplateInput) {
|
||||
addProjectFromTemplate(organizationSlug: $organizationSlug, data: $data) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`;
|
||||
var addProject = import_client2.gql`
|
||||
mutation ($organizationSlug: String!, $data: AddProjectInput) {
|
||||
addProject(organizationSlug: $organizationSlug, data: $data) {
|
||||
id
|
||||
mutation ($organizationSlug: String!, $data: AddProjectInput) {
|
||||
addProject(organizationSlug: $organizationSlug, data: $data) {
|
||||
id
|
||||
}
|
||||
}
|
||||
}`;
|
||||
`;
|
||||
var updateProjectMutation = import_client2.gql`
|
||||
mutation ($projectId: String!, $data: UpdateProjectInput) {
|
||||
updateProject(projectId: $projectId, data: $data)
|
||||
}`;
|
||||
mutation ($projectId: String!, $data: UpdateProjectInput) {
|
||||
updateProject(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
var updateDomainMutation = import_client2.gql`
|
||||
mutation ($domainId: String!, $data: UpdateDomainInput!) {
|
||||
updateDomain(domainId: $domainId, data: $data)
|
||||
}`;
|
||||
mutation ($domainId: String!, $data: UpdateDomainInput!) {
|
||||
updateDomain(domainId: $domainId, data: $data)
|
||||
}
|
||||
`;
|
||||
var redeployToProd = import_client2.gql`
|
||||
mutation ($deploymentId: String!) {
|
||||
redeployToProd(deploymentId: $deploymentId)
|
||||
}
|
||||
mutation ($deploymentId: String!) {
|
||||
redeployToProd(deploymentId: $deploymentId)
|
||||
}
|
||||
`;
|
||||
var deleteProject = import_client2.gql`
|
||||
mutation ($projectId: String!) {
|
||||
deleteProject(projectId: $projectId)
|
||||
}
|
||||
mutation ($projectId: String!) {
|
||||
deleteProject(projectId: $projectId)
|
||||
}
|
||||
`;
|
||||
var deleteDomain = import_client2.gql`
|
||||
mutation ($domainId: String!) {
|
||||
deleteDomain(domainId: $domainId)
|
||||
}`;
|
||||
mutation ($domainId: String!) {
|
||||
deleteDomain(domainId: $domainId)
|
||||
}
|
||||
`;
|
||||
var rollbackDeployment = import_client2.gql`
|
||||
mutation ($projectId: String! ,$deploymentId: String!) {
|
||||
rollbackDeployment(projectId: $projectId, deploymentId: $deploymentId)
|
||||
}
|
||||
mutation ($projectId: String!, $deploymentId: String!) {
|
||||
rollbackDeployment(projectId: $projectId, deploymentId: $deploymentId)
|
||||
}
|
||||
`;
|
||||
var deleteDeployment = import_client2.gql`
|
||||
mutation ($deploymentId: String!) {
|
||||
deleteDeployment(deploymentId: $deploymentId)
|
||||
}
|
||||
mutation ($deploymentId: String!) {
|
||||
deleteDeployment(deploymentId: $deploymentId)
|
||||
}
|
||||
`;
|
||||
var addDomain = import_client2.gql`
|
||||
mutation ($projectId: String!, $data: AddDomainInput!) {
|
||||
addDomain(projectId: $projectId, data: $data)
|
||||
}
|
||||
mutation ($projectId: String!, $data: AddDomainInput!) {
|
||||
addDomain(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
var authenticateGitHub = import_client2.gql`
|
||||
mutation ($code: String!) {
|
||||
authenticateGitHub(code: $code) {
|
||||
token
|
||||
mutation ($code: String!) {
|
||||
authenticateGitHub(code: $code) {
|
||||
token
|
||||
}
|
||||
}
|
||||
}`;
|
||||
`;
|
||||
var unauthenticateGitHub = import_client2.gql`
|
||||
mutation {
|
||||
unauthenticateGitHub
|
||||
}`;
|
||||
mutation {
|
||||
unauthenticateGitHub
|
||||
}
|
||||
`;
|
||||
|
||||
// src/client.ts
|
||||
var defaultOptions = {
|
||||
@@ -538,6 +557,18 @@ var GQLClient = class {
|
||||
return data;
|
||||
});
|
||||
}
|
||||
addProjectFromTemplate(organizationSlug, data) {
|
||||
return __async(this, null, function* () {
|
||||
const result = yield this.client.mutate({
|
||||
mutation: addProjectFromTemplate,
|
||||
variables: {
|
||||
organizationSlug,
|
||||
data
|
||||
}
|
||||
});
|
||||
return result.data;
|
||||
});
|
||||
}
|
||||
addProject(organizationSlug, data) {
|
||||
return __async(this, null, function* () {
|
||||
const result = yield this.client.mutate({
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+91
-57
@@ -20,7 +20,10 @@ var __async = (__this, __arguments, generator) => {
|
||||
};
|
||||
|
||||
// src/client.ts
|
||||
import { ApolloClient, InMemoryCache } from "@apollo/client";
|
||||
import {
|
||||
ApolloClient,
|
||||
InMemoryCache
|
||||
} from "@apollo/client";
|
||||
|
||||
// src/queries.ts
|
||||
import { gql } from "@apollo/client";
|
||||
@@ -237,93 +240,112 @@ query ($projectId: String!, $filter: FilterDomainsInput) {
|
||||
// src/mutations.ts
|
||||
import { gql as gql2 } from "@apollo/client";
|
||||
var removeProjectMember = gql2`
|
||||
mutation ($projectMemberId: String!) {
|
||||
removeProjectMember(projectMemberId: $projectMemberId)
|
||||
}
|
||||
mutation ($projectMemberId: String!) {
|
||||
removeProjectMember(projectMemberId: $projectMemberId)
|
||||
}
|
||||
`;
|
||||
var updateProjectMember = gql2`
|
||||
mutation ($projectMemberId: String!, $data: UpdateProjectMemberInput) {
|
||||
updateProjectMember(projectMemberId: $projectMemberId, data: $data)
|
||||
}
|
||||
mutation ($projectMemberId: String!, $data: UpdateProjectMemberInput) {
|
||||
updateProjectMember(projectMemberId: $projectMemberId, data: $data)
|
||||
}
|
||||
`;
|
||||
var addProjectMember = gql2`
|
||||
mutation ($projectId: String!, $data: AddProjectMemberInput) {
|
||||
addProjectMember(projectId: $projectId, data: $data)
|
||||
}
|
||||
mutation ($projectId: String!, $data: AddProjectMemberInput) {
|
||||
addProjectMember(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
var addEnvironmentVariables = gql2`
|
||||
mutation ($projectId: String!, $data: [AddEnvironmentVariableInput!]) {
|
||||
addEnvironmentVariables(projectId: $projectId, data: $data)
|
||||
}
|
||||
mutation ($projectId: String!, $data: [AddEnvironmentVariableInput!]) {
|
||||
addEnvironmentVariables(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
var updateEnvironmentVariable = gql2`
|
||||
mutation ($environmentVariableId: String!, $data: UpdateEnvironmentVariableInput!) {
|
||||
updateEnvironmentVariable(environmentVariableId: $environmentVariableId, data: $data)
|
||||
}
|
||||
mutation (
|
||||
$environmentVariableId: String!
|
||||
$data: UpdateEnvironmentVariableInput!
|
||||
) {
|
||||
updateEnvironmentVariable(
|
||||
environmentVariableId: $environmentVariableId
|
||||
data: $data
|
||||
)
|
||||
}
|
||||
`;
|
||||
var removeEnvironmentVariable = gql2`
|
||||
mutation ($environmentVariableId: String!) {
|
||||
removeEnvironmentVariable(environmentVariableId: $environmentVariableId)
|
||||
}
|
||||
mutation ($environmentVariableId: String!) {
|
||||
removeEnvironmentVariable(environmentVariableId: $environmentVariableId)
|
||||
}
|
||||
`;
|
||||
var updateDeploymentToProd = gql2`
|
||||
mutation ($deploymentId: String!) {
|
||||
updateDeploymentToProd(deploymentId: $deploymentId)
|
||||
}
|
||||
mutation ($deploymentId: String!) {
|
||||
updateDeploymentToProd(deploymentId: $deploymentId)
|
||||
}
|
||||
`;
|
||||
var addProjectFromTemplate = gql2`
|
||||
mutation ($organizationSlug: String!, $data: AddProjectFromTemplateInput) {
|
||||
addProjectFromTemplate(organizationSlug: $organizationSlug, data: $data) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`;
|
||||
var addProject = gql2`
|
||||
mutation ($organizationSlug: String!, $data: AddProjectInput) {
|
||||
addProject(organizationSlug: $organizationSlug, data: $data) {
|
||||
id
|
||||
mutation ($organizationSlug: String!, $data: AddProjectInput) {
|
||||
addProject(organizationSlug: $organizationSlug, data: $data) {
|
||||
id
|
||||
}
|
||||
}
|
||||
}`;
|
||||
`;
|
||||
var updateProjectMutation = gql2`
|
||||
mutation ($projectId: String!, $data: UpdateProjectInput) {
|
||||
updateProject(projectId: $projectId, data: $data)
|
||||
}`;
|
||||
mutation ($projectId: String!, $data: UpdateProjectInput) {
|
||||
updateProject(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
var updateDomainMutation = gql2`
|
||||
mutation ($domainId: String!, $data: UpdateDomainInput!) {
|
||||
updateDomain(domainId: $domainId, data: $data)
|
||||
}`;
|
||||
mutation ($domainId: String!, $data: UpdateDomainInput!) {
|
||||
updateDomain(domainId: $domainId, data: $data)
|
||||
}
|
||||
`;
|
||||
var redeployToProd = gql2`
|
||||
mutation ($deploymentId: String!) {
|
||||
redeployToProd(deploymentId: $deploymentId)
|
||||
}
|
||||
mutation ($deploymentId: String!) {
|
||||
redeployToProd(deploymentId: $deploymentId)
|
||||
}
|
||||
`;
|
||||
var deleteProject = gql2`
|
||||
mutation ($projectId: String!) {
|
||||
deleteProject(projectId: $projectId)
|
||||
}
|
||||
mutation ($projectId: String!) {
|
||||
deleteProject(projectId: $projectId)
|
||||
}
|
||||
`;
|
||||
var deleteDomain = gql2`
|
||||
mutation ($domainId: String!) {
|
||||
deleteDomain(domainId: $domainId)
|
||||
}`;
|
||||
mutation ($domainId: String!) {
|
||||
deleteDomain(domainId: $domainId)
|
||||
}
|
||||
`;
|
||||
var rollbackDeployment = gql2`
|
||||
mutation ($projectId: String! ,$deploymentId: String!) {
|
||||
rollbackDeployment(projectId: $projectId, deploymentId: $deploymentId)
|
||||
}
|
||||
mutation ($projectId: String!, $deploymentId: String!) {
|
||||
rollbackDeployment(projectId: $projectId, deploymentId: $deploymentId)
|
||||
}
|
||||
`;
|
||||
var deleteDeployment = gql2`
|
||||
mutation ($deploymentId: String!) {
|
||||
deleteDeployment(deploymentId: $deploymentId)
|
||||
}
|
||||
mutation ($deploymentId: String!) {
|
||||
deleteDeployment(deploymentId: $deploymentId)
|
||||
}
|
||||
`;
|
||||
var addDomain = gql2`
|
||||
mutation ($projectId: String!, $data: AddDomainInput!) {
|
||||
addDomain(projectId: $projectId, data: $data)
|
||||
}
|
||||
mutation ($projectId: String!, $data: AddDomainInput!) {
|
||||
addDomain(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
var authenticateGitHub = gql2`
|
||||
mutation ($code: String!) {
|
||||
authenticateGitHub(code: $code) {
|
||||
token
|
||||
mutation ($code: String!) {
|
||||
authenticateGitHub(code: $code) {
|
||||
token
|
||||
}
|
||||
}
|
||||
}`;
|
||||
`;
|
||||
var unauthenticateGitHub = gql2`
|
||||
mutation {
|
||||
unauthenticateGitHub
|
||||
}`;
|
||||
mutation {
|
||||
unauthenticateGitHub
|
||||
}
|
||||
`;
|
||||
|
||||
// src/client.ts
|
||||
var defaultOptions = {
|
||||
@@ -508,6 +530,18 @@ var GQLClient = class {
|
||||
return data;
|
||||
});
|
||||
}
|
||||
addProjectFromTemplate(organizationSlug, data) {
|
||||
return __async(this, null, function* () {
|
||||
const result = yield this.client.mutate({
|
||||
mutation: addProjectFromTemplate,
|
||||
variables: {
|
||||
organizationSlug,
|
||||
data
|
||||
}
|
||||
});
|
||||
return result.data;
|
||||
});
|
||||
}
|
||||
addProject(organizationSlug, data) {
|
||||
return __async(this, null, function* () {
|
||||
const result = yield this.client.mutate({
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,8 +1,13 @@
|
||||
import { ApolloClient, DefaultOptions, InMemoryCache, NormalizedCacheObject } from '@apollo/client';
|
||||
import {
|
||||
ApolloClient,
|
||||
DefaultOptions,
|
||||
InMemoryCache,
|
||||
NormalizedCacheObject,
|
||||
} from "@apollo/client";
|
||||
|
||||
import * as queries from './queries';
|
||||
import * as types from './types';
|
||||
import * as mutations from './mutations';
|
||||
import * as queries from "./queries";
|
||||
import * as types from "./types";
|
||||
import * as mutations from "./mutations";
|
||||
|
||||
export interface GraphQLConfig {
|
||||
gqlEndpoint: string;
|
||||
@@ -11,320 +16,387 @@ export interface GraphQLConfig {
|
||||
// TODO: check options
|
||||
const defaultOptions: DefaultOptions = {
|
||||
watchQuery: {
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'ignore'
|
||||
fetchPolicy: "no-cache",
|
||||
errorPolicy: "ignore",
|
||||
},
|
||||
query: {
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'all'
|
||||
}
|
||||
fetchPolicy: "no-cache",
|
||||
errorPolicy: "all",
|
||||
},
|
||||
};
|
||||
|
||||
export class GQLClient {
|
||||
private client: ApolloClient<NormalizedCacheObject>;
|
||||
|
||||
constructor (config: GraphQLConfig) {
|
||||
constructor(config: GraphQLConfig) {
|
||||
this.client = new ApolloClient({
|
||||
uri: config.gqlEndpoint,
|
||||
cache: new InMemoryCache(),
|
||||
defaultOptions,
|
||||
credentials: 'include'
|
||||
credentials: "include",
|
||||
});
|
||||
}
|
||||
|
||||
async getUser () : Promise<types.GetUserResponse> {
|
||||
async getUser(): Promise<types.GetUserResponse> {
|
||||
const { data } = await this.client.query({
|
||||
query: queries.getUser
|
||||
query: queries.getUser,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getProject (projectId: string) : Promise<types.GetProjectResponse> {
|
||||
async getProject(projectId: string): Promise<types.GetProjectResponse> {
|
||||
const { data } = await this.client.query({
|
||||
query: queries.getProject,
|
||||
variables: {
|
||||
projectId
|
||||
}
|
||||
projectId,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getProjectsInOrganization (organizationSlug: string) : Promise<types.GetProjectsInOrganizationResponse> {
|
||||
async getProjectsInOrganization(
|
||||
organizationSlug: string
|
||||
): Promise<types.GetProjectsInOrganizationResponse> {
|
||||
const { data } = await this.client.query({
|
||||
query: queries.getProjectsInOrganization,
|
||||
variables: {
|
||||
organizationSlug
|
||||
}
|
||||
organizationSlug,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getOrganizations () : Promise<types.GetOrganizationsResponse> {
|
||||
async getOrganizations(): Promise<types.GetOrganizationsResponse> {
|
||||
const { data } = await this.client.query({
|
||||
query: queries.getOrganizations
|
||||
query: queries.getOrganizations,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getDeployments (projectId: string) : Promise<types.GetDeploymentsResponse> {
|
||||
async getDeployments(
|
||||
projectId: string
|
||||
): Promise<types.GetDeploymentsResponse> {
|
||||
const { data } = await this.client.query({
|
||||
query: queries.getDeployments,
|
||||
variables: {
|
||||
projectId
|
||||
}
|
||||
projectId,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getEnvironmentVariables (projectId: string) : Promise<types.GetEnvironmentVariablesResponse> {
|
||||
async getEnvironmentVariables(
|
||||
projectId: string
|
||||
): Promise<types.GetEnvironmentVariablesResponse> {
|
||||
const { data } = await this.client.query({
|
||||
query: queries.getEnvironmentVariables,
|
||||
variables: {
|
||||
projectId
|
||||
}
|
||||
projectId,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getProjectMembers (projectId: string) : Promise<types.GetProjectMembersResponse> {
|
||||
async getProjectMembers(
|
||||
projectId: string
|
||||
): Promise<types.GetProjectMembersResponse> {
|
||||
const result = await this.client.query({
|
||||
query: queries.getProjectMembers,
|
||||
variables: {
|
||||
projectId
|
||||
}
|
||||
projectId,
|
||||
},
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async addProjectMember (projectId: string, data: types.AddProjectMemberInput) : Promise<types.AddProjectMemberResponse> {
|
||||
async addProjectMember(
|
||||
projectId: string,
|
||||
data: types.AddProjectMemberInput
|
||||
): Promise<types.AddProjectMemberResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: mutations.addProjectMember,
|
||||
variables: {
|
||||
projectId,
|
||||
data
|
||||
}
|
||||
data,
|
||||
},
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async updateProjectMember (projectMemberId: string, data: types.UpdateProjectMemberInput): Promise<types.UpdateProjectMemberResponse> {
|
||||
async updateProjectMember(
|
||||
projectMemberId: string,
|
||||
data: types.UpdateProjectMemberInput
|
||||
): Promise<types.UpdateProjectMemberResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: mutations.updateProjectMember,
|
||||
variables: {
|
||||
projectMemberId,
|
||||
data
|
||||
}
|
||||
data,
|
||||
},
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async removeProjectMember (projectMemberId: string): Promise<types.RemoveProjectMemberResponse> {
|
||||
async removeProjectMember(
|
||||
projectMemberId: string
|
||||
): Promise<types.RemoveProjectMemberResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: mutations.removeProjectMember,
|
||||
variables: {
|
||||
projectMemberId
|
||||
}
|
||||
projectMemberId,
|
||||
},
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async searchProjects (searchText: string) : Promise<types.SearchProjectsResponse> {
|
||||
async searchProjects(
|
||||
searchText: string
|
||||
): Promise<types.SearchProjectsResponse> {
|
||||
const { data } = await this.client.query({
|
||||
query: queries.searchProjects,
|
||||
variables: {
|
||||
searchText
|
||||
}
|
||||
searchText,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async addEnvironmentVariables (projectId: string, data: types.AddEnvironmentVariableInput[]): Promise<types.AddEnvironmentVariablesResponse> {
|
||||
async addEnvironmentVariables(
|
||||
projectId: string,
|
||||
data: types.AddEnvironmentVariableInput[]
|
||||
): Promise<types.AddEnvironmentVariablesResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: mutations.addEnvironmentVariables,
|
||||
variables: {
|
||||
projectId,
|
||||
data
|
||||
}
|
||||
data,
|
||||
},
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async updateEnvironmentVariable (environmentVariableId: string, data: types.UpdateEnvironmentVariableInput): Promise<types.UpdateEnvironmentVariableResponse> {
|
||||
async updateEnvironmentVariable(
|
||||
environmentVariableId: string,
|
||||
data: types.UpdateEnvironmentVariableInput
|
||||
): Promise<types.UpdateEnvironmentVariableResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: mutations.updateEnvironmentVariable,
|
||||
variables: {
|
||||
environmentVariableId,
|
||||
data
|
||||
}
|
||||
data,
|
||||
},
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async removeEnvironmentVariable (environmentVariableId: string): Promise<types.RemoveEnvironmentVariableResponse> {
|
||||
async removeEnvironmentVariable(
|
||||
environmentVariableId: string
|
||||
): Promise<types.RemoveEnvironmentVariableResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
mutation: mutations.removeEnvironmentVariable,
|
||||
variables: {
|
||||
environmentVariableId
|
||||
}
|
||||
environmentVariableId,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async updateDeploymentToProd (deploymentId: string): Promise<types.UpdateDeploymentToProdResponse> {
|
||||
async updateDeploymentToProd(
|
||||
deploymentId: string
|
||||
): Promise<types.UpdateDeploymentToProdResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
mutation: mutations.updateDeploymentToProd,
|
||||
variables: {
|
||||
deploymentId
|
||||
}
|
||||
deploymentId,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async addProject (organizationSlug: string, data: types.AddProjectInput): Promise<types.AddProjectResponse> {
|
||||
async addProjectFromTemplate(
|
||||
organizationSlug: string,
|
||||
data: types.AddProjectFromTemplateInput
|
||||
): Promise<types.AddProjectFromTemplateResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: mutations.addProjectFromTemplate,
|
||||
variables: {
|
||||
organizationSlug,
|
||||
data,
|
||||
},
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async addProject(
|
||||
organizationSlug: string,
|
||||
data: types.AddProjectInput
|
||||
): Promise<types.AddProjectResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: mutations.addProject,
|
||||
variables: {
|
||||
organizationSlug,
|
||||
data
|
||||
}
|
||||
data,
|
||||
},
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async updateProject (projectId: string, data: types.UpdateProjectInput): Promise<types.UpdateProjectResponse> {
|
||||
async updateProject(
|
||||
projectId: string,
|
||||
data: types.UpdateProjectInput
|
||||
): Promise<types.UpdateProjectResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: mutations.updateProjectMutation,
|
||||
variables: {
|
||||
projectId,
|
||||
data
|
||||
}
|
||||
data,
|
||||
},
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async updateDomain (domainId: string, data: types.UpdateDomainInput): Promise<types.UpdateDomainResponse> {
|
||||
async updateDomain(
|
||||
domainId: string,
|
||||
data: types.UpdateDomainInput
|
||||
): Promise<types.UpdateDomainResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: mutations.updateDomainMutation,
|
||||
variables: {
|
||||
domainId,
|
||||
data
|
||||
}
|
||||
data,
|
||||
},
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async redeployToProd (deploymentId: string): Promise<types.RedeployToProdResponse> {
|
||||
async redeployToProd(
|
||||
deploymentId: string
|
||||
): Promise<types.RedeployToProdResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
mutation: mutations.redeployToProd,
|
||||
variables: {
|
||||
deploymentId
|
||||
}
|
||||
deploymentId,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async deleteProject (projectId: string): Promise<types.DeleteProjectResponse> {
|
||||
async deleteProject(projectId: string): Promise<types.DeleteProjectResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
mutation: mutations.deleteProject,
|
||||
variables: {
|
||||
projectId
|
||||
}
|
||||
projectId,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async deleteDomain (domainId: string): Promise<types.DeleteDomainResponse> {
|
||||
async deleteDomain(domainId: string): Promise<types.DeleteDomainResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
mutation: mutations.deleteDomain,
|
||||
variables: {
|
||||
domainId
|
||||
}
|
||||
domainId,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async rollbackDeployment (projectId: string, deploymentId: string): Promise<types.RollbackDeploymentResponse> {
|
||||
async rollbackDeployment(
|
||||
projectId: string,
|
||||
deploymentId: string
|
||||
): Promise<types.RollbackDeploymentResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
mutation: mutations.rollbackDeployment,
|
||||
variables: {
|
||||
projectId,
|
||||
deploymentId
|
||||
}
|
||||
deploymentId,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async deleteDeployment (deploymentId: string): Promise<types.DeleteDeploymentResponse> {
|
||||
async deleteDeployment(
|
||||
deploymentId: string
|
||||
): Promise<types.DeleteDeploymentResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
mutation: mutations.deleteDeployment,
|
||||
variables: {
|
||||
deploymentId
|
||||
}
|
||||
deploymentId,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async addDomain (projectId: string, data: types.AddDomainInput): Promise<types.AddDomainResponse> {
|
||||
async addDomain(
|
||||
projectId: string,
|
||||
data: types.AddDomainInput
|
||||
): Promise<types.AddDomainResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: mutations.addDomain,
|
||||
variables: {
|
||||
projectId,
|
||||
data
|
||||
}
|
||||
data,
|
||||
},
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async getDomains (projectId: string, filter?: types.FilterDomainInput): Promise<types.GetDomainsResponse> {
|
||||
async getDomains(
|
||||
projectId: string,
|
||||
filter?: types.FilterDomainInput
|
||||
): Promise<types.GetDomainsResponse> {
|
||||
const { data } = await this.client.query({
|
||||
query: queries.getDomains,
|
||||
variables: {
|
||||
projectId,
|
||||
filter
|
||||
}
|
||||
filter,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async authenticateGitHub (code: string): Promise<types.AuthenticateGitHubResponse> {
|
||||
async authenticateGitHub(
|
||||
code: string
|
||||
): Promise<types.AuthenticateGitHubResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
mutation: mutations.authenticateGitHub,
|
||||
variables: {
|
||||
code
|
||||
}
|
||||
code,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async unauthenticateGithub (): Promise<types.UnauthenticateGitHubResponse> {
|
||||
async unauthenticateGithub(): Promise<types.UnauthenticateGitHubResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
mutation: mutations.unauthenticateGitHub
|
||||
mutation: mutations.unauthenticateGitHub,
|
||||
});
|
||||
|
||||
return data;
|
||||
|
||||
@@ -1,107 +1,127 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { gql } from "@apollo/client";
|
||||
|
||||
export const removeProjectMember = gql`
|
||||
mutation ($projectMemberId: String!) {
|
||||
removeProjectMember(projectMemberId: $projectMemberId)
|
||||
}
|
||||
mutation ($projectMemberId: String!) {
|
||||
removeProjectMember(projectMemberId: $projectMemberId)
|
||||
}
|
||||
`;
|
||||
|
||||
export const updateProjectMember = gql`
|
||||
mutation ($projectMemberId: String!, $data: UpdateProjectMemberInput) {
|
||||
updateProjectMember(projectMemberId: $projectMemberId, data: $data)
|
||||
}
|
||||
mutation ($projectMemberId: String!, $data: UpdateProjectMemberInput) {
|
||||
updateProjectMember(projectMemberId: $projectMemberId, data: $data)
|
||||
}
|
||||
`;
|
||||
|
||||
export const addProjectMember = gql`
|
||||
mutation ($projectId: String!, $data: AddProjectMemberInput) {
|
||||
addProjectMember(projectId: $projectId, data: $data)
|
||||
}
|
||||
mutation ($projectId: String!, $data: AddProjectMemberInput) {
|
||||
addProjectMember(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
|
||||
export const addEnvironmentVariables = gql`
|
||||
mutation ($projectId: String!, $data: [AddEnvironmentVariableInput!]) {
|
||||
addEnvironmentVariables(projectId: $projectId, data: $data)
|
||||
}
|
||||
mutation ($projectId: String!, $data: [AddEnvironmentVariableInput!]) {
|
||||
addEnvironmentVariables(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
|
||||
export const updateEnvironmentVariable = gql`
|
||||
mutation ($environmentVariableId: String!, $data: UpdateEnvironmentVariableInput!) {
|
||||
updateEnvironmentVariable(environmentVariableId: $environmentVariableId, data: $data)
|
||||
}
|
||||
mutation (
|
||||
$environmentVariableId: String!
|
||||
$data: UpdateEnvironmentVariableInput!
|
||||
) {
|
||||
updateEnvironmentVariable(
|
||||
environmentVariableId: $environmentVariableId
|
||||
data: $data
|
||||
)
|
||||
}
|
||||
`;
|
||||
|
||||
export const removeEnvironmentVariable = gql`
|
||||
mutation ($environmentVariableId: String!) {
|
||||
removeEnvironmentVariable(environmentVariableId: $environmentVariableId)
|
||||
}
|
||||
mutation ($environmentVariableId: String!) {
|
||||
removeEnvironmentVariable(environmentVariableId: $environmentVariableId)
|
||||
}
|
||||
`;
|
||||
|
||||
export const updateDeploymentToProd = gql`
|
||||
mutation ($deploymentId: String!) {
|
||||
updateDeploymentToProd(deploymentId: $deploymentId)
|
||||
}
|
||||
mutation ($deploymentId: String!) {
|
||||
updateDeploymentToProd(deploymentId: $deploymentId)
|
||||
}
|
||||
`;
|
||||
|
||||
export const addProjectFromTemplate = gql`
|
||||
mutation ($organizationSlug: String!, $data: AddProjectFromTemplateInput) {
|
||||
addProjectFromTemplate(organizationSlug: $organizationSlug, data: $data) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const addProject = gql`
|
||||
mutation ($organizationSlug: String!, $data: AddProjectInput) {
|
||||
addProject(organizationSlug: $organizationSlug, data: $data) {
|
||||
id
|
||||
mutation ($organizationSlug: String!, $data: AddProjectInput) {
|
||||
addProject(organizationSlug: $organizationSlug, data: $data) {
|
||||
id
|
||||
}
|
||||
}
|
||||
}`;
|
||||
`;
|
||||
|
||||
export const updateProjectMutation = gql`
|
||||
mutation ($projectId: String!, $data: UpdateProjectInput) {
|
||||
updateProject(projectId: $projectId, data: $data)
|
||||
}`;
|
||||
mutation ($projectId: String!, $data: UpdateProjectInput) {
|
||||
updateProject(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
|
||||
export const updateDomainMutation = gql`
|
||||
mutation ($domainId: String!, $data: UpdateDomainInput!) {
|
||||
updateDomain(domainId: $domainId, data: $data)
|
||||
}`;
|
||||
mutation ($domainId: String!, $data: UpdateDomainInput!) {
|
||||
updateDomain(domainId: $domainId, data: $data)
|
||||
}
|
||||
`;
|
||||
|
||||
export const redeployToProd = gql`
|
||||
mutation ($deploymentId: String!) {
|
||||
redeployToProd(deploymentId: $deploymentId)
|
||||
}
|
||||
mutation ($deploymentId: String!) {
|
||||
redeployToProd(deploymentId: $deploymentId)
|
||||
}
|
||||
`;
|
||||
|
||||
export const deleteProject = gql`
|
||||
mutation ($projectId: String!) {
|
||||
deleteProject(projectId: $projectId)
|
||||
}
|
||||
mutation ($projectId: String!) {
|
||||
deleteProject(projectId: $projectId)
|
||||
}
|
||||
`;
|
||||
|
||||
export const deleteDomain = gql`
|
||||
mutation ($domainId: String!) {
|
||||
deleteDomain(domainId: $domainId)
|
||||
}`;
|
||||
mutation ($domainId: String!) {
|
||||
deleteDomain(domainId: $domainId)
|
||||
}
|
||||
`;
|
||||
|
||||
export const rollbackDeployment = gql`
|
||||
mutation ($projectId: String! ,$deploymentId: String!) {
|
||||
rollbackDeployment(projectId: $projectId, deploymentId: $deploymentId)
|
||||
}
|
||||
mutation ($projectId: String!, $deploymentId: String!) {
|
||||
rollbackDeployment(projectId: $projectId, deploymentId: $deploymentId)
|
||||
}
|
||||
`;
|
||||
|
||||
export const deleteDeployment = gql`
|
||||
mutation ($deploymentId: String!) {
|
||||
deleteDeployment(deploymentId: $deploymentId)
|
||||
}
|
||||
mutation ($deploymentId: String!) {
|
||||
deleteDeployment(deploymentId: $deploymentId)
|
||||
}
|
||||
`;
|
||||
|
||||
export const addDomain = gql`
|
||||
mutation ($projectId: String!, $data: AddDomainInput!) {
|
||||
addDomain(projectId: $projectId, data: $data)
|
||||
}
|
||||
mutation ($projectId: String!, $data: AddDomainInput!) {
|
||||
addDomain(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
|
||||
export const authenticateGitHub = gql`
|
||||
mutation ($code: String!) {
|
||||
authenticateGitHub(code: $code) {
|
||||
token
|
||||
mutation ($code: String!) {
|
||||
authenticateGitHub(code: $code) {
|
||||
token
|
||||
}
|
||||
}
|
||||
}`;
|
||||
`;
|
||||
|
||||
export const unauthenticateGitHub = gql`
|
||||
mutation {
|
||||
unauthenticateGitHub
|
||||
}`;
|
||||
mutation {
|
||||
unauthenticateGitHub
|
||||
}
|
||||
`;
|
||||
|
||||
+180
-167
@@ -1,298 +1,311 @@
|
||||
import { addProjectFromTemplate } from "./mutations";
|
||||
// Note: equivalent to types present in GQL schema
|
||||
|
||||
export enum Role {
|
||||
Owner = 'Owner',
|
||||
Maintainer = 'Maintainer',
|
||||
Reader = 'Reader',
|
||||
Owner = "Owner",
|
||||
Maintainer = "Maintainer",
|
||||
Reader = "Reader",
|
||||
}
|
||||
|
||||
export enum Permission {
|
||||
View = 'View',
|
||||
Edit = 'Edit',
|
||||
View = "View",
|
||||
Edit = "Edit",
|
||||
}
|
||||
|
||||
export enum Environment {
|
||||
Production = 'Production',
|
||||
Preview = 'Preview',
|
||||
Development = 'Development',
|
||||
Production = "Production",
|
||||
Preview = "Preview",
|
||||
Development = "Development",
|
||||
}
|
||||
|
||||
export enum DeploymentStatus {
|
||||
Building = 'Building',
|
||||
Ready = 'Ready',
|
||||
Error = 'Error',
|
||||
Deleting = 'Deleting'
|
||||
Building = "Building",
|
||||
Ready = "Ready",
|
||||
Error = "Error",
|
||||
Deleting = "Deleting",
|
||||
}
|
||||
|
||||
export enum DomainStatus {
|
||||
Live = 'Live',
|
||||
Pending = 'Pending',
|
||||
Live = "Live",
|
||||
Pending = "Pending",
|
||||
}
|
||||
|
||||
export type EnvironmentVariable = {
|
||||
id: string
|
||||
environment: Environment
|
||||
key: string
|
||||
value: string
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
id: string;
|
||||
environment: Environment;
|
||||
key: string;
|
||||
value: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type Domain = {
|
||||
id: string
|
||||
branch: string
|
||||
name: string
|
||||
status: DomainStatus
|
||||
redirectTo: Domain | null
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
id: string;
|
||||
branch: string;
|
||||
name: string;
|
||||
status: DomainStatus;
|
||||
redirectTo: Domain | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type User = {
|
||||
id: string
|
||||
name: string | null
|
||||
email: string
|
||||
isVerified: boolean
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
gitHubToken: string | null
|
||||
}
|
||||
id: string;
|
||||
name: string | null;
|
||||
email: string;
|
||||
isVerified: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
gitHubToken: string | null;
|
||||
};
|
||||
|
||||
export type Deployment = {
|
||||
id: string
|
||||
domain: Domain
|
||||
branch: string
|
||||
commitHash: string
|
||||
commitMessage: string
|
||||
url?: string
|
||||
environment: Environment
|
||||
isCurrent: boolean
|
||||
status: DeploymentStatus
|
||||
createdBy: User
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
id: string;
|
||||
domain: Domain;
|
||||
branch: string;
|
||||
commitHash: string;
|
||||
commitMessage: string;
|
||||
url?: string;
|
||||
environment: Environment;
|
||||
isCurrent: boolean;
|
||||
status: DeploymentStatus;
|
||||
createdBy: User;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type OrganizationMember = {
|
||||
id: string
|
||||
member: User
|
||||
role: Role
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
id: string;
|
||||
member: User;
|
||||
role: Role;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type ProjectMember = {
|
||||
id: string
|
||||
member: User
|
||||
permissions: Permission[]
|
||||
isPending: boolean
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
id: string;
|
||||
member: User;
|
||||
permissions: Permission[];
|
||||
isPending: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type OrganizationProject = {
|
||||
id: string
|
||||
owner: User
|
||||
deployments: Deployment[]
|
||||
name: string
|
||||
repository: string
|
||||
prodBranch: string
|
||||
description: string
|
||||
template: string
|
||||
framework: string
|
||||
webhooks: string[]
|
||||
members: ProjectMember[]
|
||||
environmentVariables: EnvironmentVariable[]
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
id: string;
|
||||
owner: User;
|
||||
deployments: Deployment[];
|
||||
name: string;
|
||||
repository: string;
|
||||
prodBranch: string;
|
||||
description: string;
|
||||
template: string;
|
||||
framework: string;
|
||||
webhooks: string[];
|
||||
members: ProjectMember[];
|
||||
environmentVariables: EnvironmentVariable[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type Organization = {
|
||||
id: string
|
||||
name: string
|
||||
slug: string
|
||||
projects: OrganizationProject[]
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
members: OrganizationMember[]
|
||||
}
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
projects: OrganizationProject[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
members: OrganizationMember[];
|
||||
};
|
||||
|
||||
export type Project = {
|
||||
id: string
|
||||
owner: User
|
||||
deployments: Deployment[]
|
||||
name: string
|
||||
repository: string
|
||||
prodBranch: string
|
||||
description: string
|
||||
template: string
|
||||
framework: string
|
||||
webhooks: string[]
|
||||
members: ProjectMember[]
|
||||
environmentVariables: EnvironmentVariable[]
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
organization: Organization
|
||||
icon: string
|
||||
subDomain: string
|
||||
}
|
||||
id: string;
|
||||
owner: User;
|
||||
deployments: Deployment[];
|
||||
name: string;
|
||||
repository: string;
|
||||
prodBranch: string;
|
||||
description: string;
|
||||
template: string;
|
||||
framework: string;
|
||||
webhooks: string[];
|
||||
members: ProjectMember[];
|
||||
environmentVariables: EnvironmentVariable[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
organization: Organization;
|
||||
icon: string;
|
||||
subDomain: string;
|
||||
};
|
||||
|
||||
export type GetProjectMembersResponse = {
|
||||
projectMembers: ProjectMember[]
|
||||
}
|
||||
projectMembers: ProjectMember[];
|
||||
};
|
||||
|
||||
export type AddProjectMemberResponse = {
|
||||
addProjectMember: boolean
|
||||
}
|
||||
addProjectMember: boolean;
|
||||
};
|
||||
|
||||
export type RemoveProjectMemberResponse = {
|
||||
removeProjectMember: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export type UpdateProjectMemberResponse = {
|
||||
updateProjectMember: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export type GetDeploymentsResponse = {
|
||||
deployments: Deployment[]
|
||||
}
|
||||
deployments: Deployment[];
|
||||
};
|
||||
|
||||
export type GetEnvironmentVariablesResponse = {
|
||||
environmentVariables: EnvironmentVariable[]
|
||||
}
|
||||
environmentVariables: EnvironmentVariable[];
|
||||
};
|
||||
|
||||
export type GetOrganizationsResponse = {
|
||||
organizations: Organization[]
|
||||
}
|
||||
organizations: Organization[];
|
||||
};
|
||||
|
||||
export type GetUserResponse = {
|
||||
user: User
|
||||
}
|
||||
user: User;
|
||||
};
|
||||
|
||||
export type GetProjectResponse = {
|
||||
project: Project | null
|
||||
}
|
||||
project: Project | null;
|
||||
};
|
||||
|
||||
export type GetProjectsInOrganizationResponse = {
|
||||
projectsInOrganization: Project[]
|
||||
}
|
||||
projectsInOrganization: Project[];
|
||||
};
|
||||
|
||||
export type GetDomainsResponse = {
|
||||
domains: Domain[]
|
||||
}
|
||||
domains: Domain[];
|
||||
};
|
||||
|
||||
export type SearchProjectsResponse = {
|
||||
searchProjects: Project[]
|
||||
}
|
||||
searchProjects: Project[];
|
||||
};
|
||||
|
||||
export type AddEnvironmentVariablesResponse = {
|
||||
addEnvironmentVariables: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export type AddEnvironmentVariableInput = {
|
||||
environments: string[];
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
};
|
||||
|
||||
export type UpdateEnvironmentVariableInput = {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
};
|
||||
|
||||
export type UpdateProjectMemberInput = {
|
||||
permissions: Permission[];
|
||||
}
|
||||
};
|
||||
|
||||
export type AddProjectMemberInput = {
|
||||
email: string;
|
||||
permissions: Permission[]
|
||||
}
|
||||
permissions: Permission[];
|
||||
};
|
||||
|
||||
export type UpdateEnvironmentVariableResponse = {
|
||||
updateEnvironmentVariable: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export type RemoveEnvironmentVariableResponse = {
|
||||
removeEnvironmentVariable: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export type UpdateDeploymentToProdResponse = {
|
||||
updateDeploymentToProd: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export type AddProjectFromTemplateResponse = {
|
||||
addProjectFromTemplate: Project;
|
||||
};
|
||||
|
||||
export type AddProjectResponse = {
|
||||
addProject: Project
|
||||
}
|
||||
addProject: Project;
|
||||
};
|
||||
|
||||
export type UpdateProjectResponse = {
|
||||
updateProject: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export type UpdateDomainResponse = {
|
||||
updateDomain: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export type DeleteProjectResponse = {
|
||||
deleteProject: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export type DeleteDomainResponse = {
|
||||
deleteDomain: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export type AddProjectFromTemplateInput = {
|
||||
templateOwner: string;
|
||||
templateRepo: string;
|
||||
owner: string;
|
||||
name: string;
|
||||
isPrivate: boolean;
|
||||
};
|
||||
|
||||
export type AddProjectInput = {
|
||||
name: string;
|
||||
repository: string;
|
||||
prodBranch: string;
|
||||
template?: string;
|
||||
}
|
||||
};
|
||||
|
||||
export type UpdateProjectInput = {
|
||||
name?: string
|
||||
description?: string
|
||||
prodBranch?: string
|
||||
webhooks?: string[]
|
||||
organizationId?: string
|
||||
}
|
||||
name?: string;
|
||||
description?: string;
|
||||
prodBranch?: string;
|
||||
webhooks?: string[];
|
||||
organizationId?: string;
|
||||
};
|
||||
|
||||
export type UpdateDomainInput = {
|
||||
name?: string;
|
||||
branch?: string;
|
||||
redirectToId?: string | null;
|
||||
}
|
||||
};
|
||||
|
||||
export type RedeployToProdResponse = {
|
||||
redeployToProd: boolean
|
||||
}
|
||||
redeployToProd: boolean;
|
||||
};
|
||||
|
||||
export type RollbackDeploymentResponse = {
|
||||
rollbackDeployment: boolean
|
||||
}
|
||||
rollbackDeployment: boolean;
|
||||
};
|
||||
|
||||
export type DeleteDeploymentResponse = {
|
||||
deleteDeployment: boolean
|
||||
}
|
||||
deleteDeployment: boolean;
|
||||
};
|
||||
|
||||
export type AddDomainInput = {
|
||||
name: string
|
||||
}
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type FilterDomainInput = {
|
||||
branch?: string
|
||||
status?: DomainStatus
|
||||
}
|
||||
branch?: string;
|
||||
status?: DomainStatus;
|
||||
};
|
||||
|
||||
export type AddDomainResponse = {
|
||||
addDomain: true
|
||||
}
|
||||
addDomain: true;
|
||||
};
|
||||
|
||||
export type AuthenticateGitHubResponse = {
|
||||
authenticateGitHub: {
|
||||
token: string
|
||||
}
|
||||
}
|
||||
token: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type UnauthenticateGitHubResponse = {
|
||||
unauthenticateGitHub: boolean
|
||||
}
|
||||
unauthenticateGitHub: boolean;
|
||||
};
|
||||
|
||||
@@ -10575,6 +10575,11 @@ exponential-backoff@^3.1.1:
|
||||
resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6"
|
||||
integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==
|
||||
|
||||
express-async-errors@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/express-async-errors/-/express-async-errors-3.1.1.tgz#6053236d61d21ddef4892d6bd1d736889fc9da41"
|
||||
integrity sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==
|
||||
|
||||
express-session@^1.18.0:
|
||||
version "1.18.0"
|
||||
resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.18.0.tgz#a6ae39d9091f2efba5f20fc5c65a3ce7c9ce16a3"
|
||||
|
||||
Reference in New Issue
Block a user