forked from cerc-io/snowballtools-base
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
175af0f9e0 |
+1
-4
@@ -6,7 +6,4 @@ yarn-error.log
|
|||||||
|
|
||||||
packages/backend/environments/local.toml
|
packages/backend/environments/local.toml
|
||||||
packages/backend/dev/
|
packages/backend/dev/
|
||||||
packages/frontend/dist/
|
packages/frontend/dist/
|
||||||
|
|
||||||
# ignore all .DS_Store files
|
|
||||||
**/.DS_Store
|
|
||||||
@@ -1,23 +1,220 @@
|
|||||||
# snowballtools-base
|
# snowballtools-base
|
||||||
|
|
||||||
This is a [yarn workspace](https://yarnpkg.com/features/workspaces) monorepo for the dashboard.
|
## Setup
|
||||||
|
|
||||||
## Getting Started
|
- Clone the `snowballtools-base` repo
|
||||||
|
|
||||||
### Install dependencies
|
```bash
|
||||||
|
git clone git@github.com:snowball-tools/snowballtools-base.git
|
||||||
|
cd snowballtools-base
|
||||||
|
```
|
||||||
|
|
||||||
In the root of the project, run:
|
- Install dependencies in root
|
||||||
|
|
||||||
```zsh
|
```bash
|
||||||
yarn
|
yarn
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build backend
|
- Build packages
|
||||||
|
|
||||||
```zsh
|
```bash
|
||||||
yarn build --ignore frontend
|
yarn build --ignore frontend
|
||||||
```
|
```
|
||||||
|
|
||||||
### Environment variables, running the development server, and deployment
|
Let us assume the following domains for backend and frontend
|
||||||
|
- Backend server: `api.snowballtools.com`
|
||||||
|
- Frontend app: `dashboard.snowballtools.com`
|
||||||
|
|
||||||
Follow the instructions in the README.md files of the [backend](packages/backend/README.md) and [frontend](packages/frontend/README.md) packages.
|
- 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
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,76 +1 @@
|
|||||||
# backend
|
# Backend for Snowball Tools
|
||||||
|
|
||||||
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)
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
port = 8000
|
port = 8000
|
||||||
gqlPath = "/graphql"
|
gqlPath = "/graphql"
|
||||||
[server.session]
|
[server.session]
|
||||||
secret = ""
|
secret = "p4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowoi"
|
||||||
appOriginUrl = "http://localhost:3000"
|
appOriginUrl = "http://localhost:3000"
|
||||||
trustProxy = false
|
trustProxy = false
|
||||||
domain = "localhost"
|
domain = "localhost"
|
||||||
@@ -17,16 +17,6 @@
|
|||||||
clientId = ""
|
clientId = ""
|
||||||
clientSecret = ""
|
clientSecret = ""
|
||||||
|
|
||||||
[google]
|
|
||||||
clientId = ""
|
|
||||||
clientSecret = ""
|
|
||||||
|
|
||||||
[turnkey]
|
|
||||||
apiBaseUrl = "https://api.turnkey.com"
|
|
||||||
apiPrivateKey = ""
|
|
||||||
apiPublicKey = ""
|
|
||||||
defaultOrganizationId = ""
|
|
||||||
|
|
||||||
[registryConfig]
|
[registryConfig]
|
||||||
fetchDeploymentRecordDelay = 5000
|
fetchDeploymentRecordDelay = 5000
|
||||||
restEndpoint = "http://localhost:1317"
|
restEndpoint = "http://localhost:1317"
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { Permission } from './entity/ProjectMember';
|
|||||||
import { Domain } from './entity/Domain';
|
import { Domain } from './entity/Domain';
|
||||||
import { Project } from './entity/Project';
|
import { Project } from './entity/Project';
|
||||||
import { EnvironmentVariable } from './entity/EnvironmentVariable';
|
import { EnvironmentVariable } from './entity/EnvironmentVariable';
|
||||||
import { AddProjectFromTemplateInput } from './types';
|
|
||||||
|
|
||||||
const log = debug('snowball:resolver');
|
const log = debug('snowball:resolver');
|
||||||
|
|
||||||
@@ -198,26 +197,6 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
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 (
|
addProject: async (
|
||||||
_: any,
|
_: any,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,19 +5,6 @@ import { authenticateUser, createUser } from '../turnkey-backend';
|
|||||||
|
|
||||||
const router = Router();
|
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
|
// Turnkey
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Router } from 'express';
|
|||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.get('/version', async (req, res) => {
|
router.get('/version', async (req, res) => {
|
||||||
return res.send({ version: '0.0.9' });
|
return res.send({ version: '0.0.7' });
|
||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -130,14 +130,6 @@ input AddEnvironmentVariableInput {
|
|||||||
value: String!
|
value: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input AddProjectFromTemplateInput {
|
|
||||||
templateOwner: String!
|
|
||||||
templateRepo: String!
|
|
||||||
owner: String!
|
|
||||||
name: String!
|
|
||||||
isPrivate: Boolean!
|
|
||||||
}
|
|
||||||
|
|
||||||
input AddProjectInput {
|
input AddProjectInput {
|
||||||
name: String!
|
name: String!
|
||||||
repository: String!
|
repository: String!
|
||||||
@@ -212,10 +204,6 @@ type Mutation {
|
|||||||
): Boolean!
|
): Boolean!
|
||||||
removeEnvironmentVariable(environmentVariableId: String!): Boolean!
|
removeEnvironmentVariable(environmentVariableId: String!): Boolean!
|
||||||
updateDeploymentToProd(deploymentId: String!): Boolean!
|
updateDeploymentToProd(deploymentId: String!): Boolean!
|
||||||
addProjectFromTemplate(
|
|
||||||
organizationSlug: String!
|
|
||||||
data: AddProjectFromTemplateInput
|
|
||||||
): Project!
|
|
||||||
addProject(organizationSlug: String!, data: AddProjectInput): Project!
|
addProject(organizationSlug: String!, data: AddProjectInput): Project!
|
||||||
updateProject(projectId: String!, data: UpdateProjectInput): Boolean!
|
updateProject(projectId: String!, data: UpdateProjectInput): Boolean!
|
||||||
redeployToProd(deploymentId: String!): Boolean!
|
redeployToProd(deploymentId: String!): Boolean!
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import { User } from './entity/User';
|
|||||||
import { Registry } from './registry';
|
import { Registry } from './registry';
|
||||||
import { GitHubConfig, RegistryConfig } from './config';
|
import { GitHubConfig, RegistryConfig } from './config';
|
||||||
import {
|
import {
|
||||||
AddProjectFromTemplateInput,
|
|
||||||
AppDeploymentRecord,
|
AppDeploymentRecord,
|
||||||
AppDeploymentRemovalRecord,
|
AppDeploymentRemovalRecord,
|
||||||
GitPushEventPayload,
|
GitPushEventPayload,
|
||||||
@@ -644,53 +643,6 @@ export class Service {
|
|||||||
return newDeployment;
|
return newDeployment;
|
||||||
}
|
}
|
||||||
|
|
||||||
async addProjectFromTemplate(
|
|
||||||
user: User,
|
|
||||||
organizationSlug: string,
|
|
||||||
data: AddProjectFromTemplateInput,
|
|
||||||
): Promise<Project | undefined> {
|
|
||||||
try {
|
|
||||||
const octokit = await this.getOctokit(user.id);
|
|
||||||
|
|
||||||
const gitRepo = await octokit?.rest.repos.createUsingTemplate({
|
|
||||||
template_owner: data.templateOwner,
|
|
||||||
template_repo: data.templateRepo,
|
|
||||||
owner: data.owner,
|
|
||||||
name: data.name,
|
|
||||||
include_all_branches: false,
|
|
||||||
private: data.isPrivate,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!gitRepo) {
|
|
||||||
throw new Error('Failed to create repository from template');
|
|
||||||
}
|
|
||||||
|
|
||||||
const createdTemplateRepo = await octokit.rest.repos.get({
|
|
||||||
owner: data.owner,
|
|
||||||
repo: data.name,
|
|
||||||
});
|
|
||||||
|
|
||||||
const prodBranch = createdTemplateRepo.data.default_branch ?? 'main';
|
|
||||||
|
|
||||||
const project = await this.addProject(user, organizationSlug, {
|
|
||||||
name: `${gitRepo.data.owner!.login}-${gitRepo.data.name}`,
|
|
||||||
prodBranch,
|
|
||||||
repository: gitRepo.data.full_name,
|
|
||||||
// TODO: Set selected template
|
|
||||||
template: 'webapp',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!project || !project.id) {
|
|
||||||
throw new Error('Failed to create project from template');
|
|
||||||
}
|
|
||||||
|
|
||||||
return project;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error creating project from template:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async addProject(
|
async addProject(
|
||||||
user: User,
|
user: User,
|
||||||
organizationSlug: string,
|
organizationSlug: string,
|
||||||
@@ -720,7 +672,7 @@ export class Service {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Create deployment with prod branch and latest commit
|
// Create deployment with prod branch and latest commit
|
||||||
const deployment = await this.createDeployment(user.id, octokit, {
|
await this.createDeployment(user.id, octokit, {
|
||||||
project,
|
project,
|
||||||
branch: project.prodBranch,
|
branch: project.prodBranch,
|
||||||
environment: Environment.Production,
|
environment: Environment.Production,
|
||||||
@@ -731,8 +683,6 @@ export class Service {
|
|||||||
|
|
||||||
await this.createRepoHook(octokit, project);
|
await this.createRepoHook(octokit, project);
|
||||||
|
|
||||||
console.log('projectid is', project.id);
|
|
||||||
|
|
||||||
return project;
|
return project;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export interface AppDeploymentRecordAttributes {
|
|||||||
export interface AppDeploymentRemovalRecordAttributes {
|
export interface AppDeploymentRemovalRecordAttributes {
|
||||||
deployment: string;
|
deployment: string;
|
||||||
request: string;
|
request: string;
|
||||||
type: 'ApplicationDeploymentRemovalRecord';
|
type: "ApplicationDeploymentRemovalRecord";
|
||||||
version: string;
|
version: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,11 +61,3 @@ export interface AppDeploymentRecord extends RegistryRecord {
|
|||||||
export interface AppDeploymentRemovalRecord extends RegistryRecord {
|
export interface AppDeploymentRemovalRecord extends RegistryRecord {
|
||||||
attributes: AppDeploymentRemovalRecordAttributes;
|
attributes: AppDeploymentRemovalRecordAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AddProjectFromTemplateInput {
|
|
||||||
templateOwner: string;
|
|
||||||
templateRepo: string;
|
|
||||||
owner: string;
|
|
||||||
name: string;
|
|
||||||
isPrivate: boolean;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
# deployer
|
# deployer
|
||||||
|
|
||||||
- Install dependencies
|
- Install dependencies
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn
|
yarn
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
brew install jq # if you do not have jq installed already
|
brew install jq # if you do not have jq installed already
|
||||||
```
|
```
|
||||||
@@ -14,13 +12,13 @@
|
|||||||
|
|
||||||
- To deploy frontend app to `dashboard.staging.apps.snowballtools.com`
|
- To deploy frontend app to `dashboard.staging.apps.snowballtools.com`
|
||||||
|
|
||||||
```bash
|
```
|
||||||
./deploy-frontend.staging.sh
|
./deploy-frontend.staging.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
- To deploy frontend app to `dashboard.apps.snowballtools.com`
|
- To deploy frontend app to `dashboard.apps.snowballtools.com`
|
||||||
|
|
||||||
```bash
|
```
|
||||||
./deploy-frontend.sh
|
./deploy-frontend.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -29,7 +27,6 @@
|
|||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- Any config env can be updated in [records/application-deployment-request.yml](records/application-deployment-request.yml)
|
- Any config env can be updated in [records/application-deployment-request.yml](records/application-deployment-request.yml)
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
record:
|
record:
|
||||||
...
|
...
|
||||||
@@ -38,7 +35,6 @@
|
|||||||
LACONIC_HOSTED_CONFIG_app_server_url: https://snowballtools-base-api-001.apps.snowballtools.com
|
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
|
- On changing `LACONIC_HOSTED_CONFIG_app_github_clientid`, the GitHub client ID and secret need to be changed in backend config too
|
||||||
|
|
||||||
## Troubleshoot
|
## Troubleshoot
|
||||||
@@ -48,7 +44,6 @@
|
|||||||
|
|
||||||
- If deployment fails due to low bond balance
|
- If deployment fails due to low bond balance
|
||||||
- Check balances
|
- Check balances
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Account balance
|
# Account balance
|
||||||
yarn laconic cns account get
|
yarn laconic cns account get
|
||||||
@@ -56,9 +51,7 @@
|
|||||||
# Bond balance
|
# Bond balance
|
||||||
yarn laconic cns bond get --id 99c0e9aec0ac1b8187faa579be3b54f93fafb6060ac1fd29170b860df605be32
|
yarn laconic cns bond get --id 99c0e9aec0ac1b8187faa579be3b54f93fafb6060ac1fd29170b860df605be32
|
||||||
```
|
```
|
||||||
|
|
||||||
- Command to refill bond
|
- Command to refill bond
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn laconic cns bond refill --id 99c0e9aec0ac1b8187faa579be3b54f93fafb6060ac1fd29170b860df605be32 --type aphoton --quantity 10000000
|
yarn laconic cns bond refill --id 99c0e9aec0ac1b8187faa579be3b54f93fafb6060ac1fd29170b860df605be32 --type aphoton --quantity 10000000
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Repository URL
|
# Repository URL
|
||||||
REPO_URL="https://git.vdb.to/cerc-io/snowballtools-base"
|
REPO_URL="https://github.com/snowball-tools/snowballtools-base"
|
||||||
|
|
||||||
# Get the latest commit hash from the repository
|
# Get the latest commit hash from the repository
|
||||||
LATEST_HASH=$(git ls-remote $REPO_URL HEAD | awk '{print $1}')
|
LATEST_HASH=$(git ls-remote $REPO_URL HEAD | awk '{print $1}')
|
||||||
@@ -26,7 +26,7 @@ if [ -z "$NEW_APPLICATION_VERSION" ] || [ "1" == "$NEW_APPLICATION_VERSION" ]; t
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Generate application-deployment-request.yml
|
# Generate application-deployment-request.yml
|
||||||
cat >./records/application-deployment-request.yml <<EOF
|
cat > ./records/application-deployment-request.yml <<EOF
|
||||||
record:
|
record:
|
||||||
type: ApplicationDeploymentRequest
|
type: ApplicationDeploymentRequest
|
||||||
version: '1.0.0'
|
version: '1.0.0'
|
||||||
@@ -37,9 +37,9 @@ record:
|
|||||||
env:
|
env:
|
||||||
LACONIC_HOSTED_CONFIG_server_url: https://snowballtools-base-api-001.apps.snowballtools.com
|
LACONIC_HOSTED_CONFIG_server_url: https://snowballtools-base-api-001.apps.snowballtools.com
|
||||||
LACONIC_HOSTED_CONFIG_github_clientid: b7c63b235ca1dd5639ab
|
LACONIC_HOSTED_CONFIG_github_clientid: b7c63b235ca1dd5639ab
|
||||||
LACONIC_HOSTED_CONFIG_github_templaterepo: snowball-tools/test-progressive-web-app
|
LACONIC_HOSTED_CONFIG_github_templaterepo: snowball-tools-platform/test-progressive-web-app
|
||||||
LACONIC_HOSTED_CONFIG_github_pwa_templaterepo: snowball-tools/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/image-upload-pwa-example
|
LACONIC_HOSTED_CONFIG_github_image_upload_templaterepo: snowball-tools-platform/image-upload-pwa-example
|
||||||
LACONIC_HOSTED_CONFIG_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
|
LACONIC_HOSTED_CONFIG_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
|
||||||
meta:
|
meta:
|
||||||
note: Added by Snowball @ $CURRENT_DATE_TIME
|
note: Added by Snowball @ $CURRENT_DATE_TIME
|
||||||
@@ -48,7 +48,7 @@ record:
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Generate application-record.yml with incremented version
|
# Generate application-record.yml with incremented version
|
||||||
cat >./records/application-record.yml <<EOF
|
cat > ./records/application-record.yml <<EOF
|
||||||
record:
|
record:
|
||||||
type: ApplicationRecord
|
type: ApplicationRecord
|
||||||
version: $NEW_APPLICATION_VERSION
|
version: $NEW_APPLICATION_VERSION
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Repository URL
|
# Repository URL
|
||||||
REPO_URL="https://git.vdb.to/cerc-io/snowballtools-base"
|
REPO_URL="https://github.com/snowball-tools/snowballtools-base"
|
||||||
|
|
||||||
# Get the latest commit hash from the repository
|
# Get the latest commit hash from the repository
|
||||||
LATEST_HASH=$(git ls-remote $REPO_URL HEAD | awk '{print $1}')
|
LATEST_HASH=$(git ls-remote $REPO_URL HEAD | awk '{print $1}')
|
||||||
@@ -26,7 +26,7 @@ if [ -z "$NEW_APPLICATION_VERSION" ] || [ "1" == "$NEW_APPLICATION_VERSION" ]; t
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Generate application-deployment-request.yml
|
# Generate application-deployment-request.yml
|
||||||
cat >./staging-records/application-deployment-request.yml <<EOF
|
cat > ./staging-records/application-deployment-request.yml <<EOF
|
||||||
record:
|
record:
|
||||||
type: ApplicationDeploymentRequest
|
type: ApplicationDeploymentRequest
|
||||||
version: '1.0.0'
|
version: '1.0.0'
|
||||||
@@ -36,10 +36,10 @@ record:
|
|||||||
config:
|
config:
|
||||||
env:
|
env:
|
||||||
LACONIC_HOSTED_CONFIG_server_url: https://snowballtools-base-api.staging.apps.snowballtools.com
|
LACONIC_HOSTED_CONFIG_server_url: https://snowballtools-base-api.staging.apps.snowballtools.com
|
||||||
LACONIC_HOSTED_CONFIG_github_clientid: Ov23liOaoahRTYd4nSCV
|
LACONIC_HOSTED_CONFIG_github_clientid: 905c09553f527d2cdff5
|
||||||
LACONIC_HOSTED_CONFIG_github_templaterepo: snowball-tools/test-progressive-web-app
|
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_pwa_templaterepo: snowball-tools/image-upload-pwa-example
|
||||||
LACONIC_HOSTED_CONFIG_github_image_upload_templaterepo: snowball-tools/image-upload-pwa-example
|
LACONIC_HOSTED_CONFIG_github_image_upload_templaterepo: snowball-tools-platform/image-upload-pwa-example
|
||||||
LACONIC_HOSTED_CONFIG_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
|
LACONIC_HOSTED_CONFIG_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
|
||||||
LACONIC_HOSTED_CONFIG_lit_relay_api_key: 15DDD969-E75F-404D-AAD9-58A37C4FD354_snowball
|
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_aplchemy_api_key: THvPart_gqI5x02RNYSBntlmwA66I_qc
|
||||||
@@ -54,7 +54,7 @@ record:
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Generate application-record.yml with incremented version
|
# Generate application-record.yml with incremented version
|
||||||
cat >./staging-records/application-record.yml <<EOF
|
cat > ./staging-records/application-record.yml <<EOF
|
||||||
record:
|
record:
|
||||||
type: ApplicationRecord
|
type: ApplicationRecord
|
||||||
version: $NEW_APPLICATION_VERSION
|
version: $NEW_APPLICATION_VERSION
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
record:
|
record:
|
||||||
type: ApplicationDeploymentRequest
|
type: ApplicationDeploymentRequest
|
||||||
version: "1.0.0"
|
version: '1.0.0'
|
||||||
name: snowballtools-base-frontend@0.1.8
|
name: snowballtools-base-frontend@0.1.8
|
||||||
application: crn://snowballtools/applications/snowballtools-base-frontend@0.1.8
|
application: crn://snowballtools/applications/snowballtools-base-frontend@0.1.8
|
||||||
dns: dashboard
|
dns: dashboard
|
||||||
@@ -8,11 +8,11 @@ record:
|
|||||||
env:
|
env:
|
||||||
LACONIC_HOSTED_CONFIG_app_server_url: https://snowballtools-base-api-001.apps.snowballtools.com
|
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_clientid: b7c63b235ca1dd5639ab
|
||||||
LACONIC_HOSTED_CONFIG_app_github_templaterepo: snowball-tools/test-progressive-web-app
|
LACONIC_HOSTED_CONFIG_app_github_templaterepo: snowball-tools-platform/test-progressive-web-app
|
||||||
LACONIC_HOSTED_CONFIG_app_github_pwa_templaterepo: snowball-tools/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/image-upload-pwa-example
|
LACONIC_HOSTED_CONFIG_app_github_image_upload_templaterepo: snowball-tools-platform/image-upload-pwa-example
|
||||||
LACONIC_HOSTED_CONFIG_app_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
|
LACONIC_HOSTED_CONFIG_app_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
|
||||||
meta:
|
meta:
|
||||||
note: Added by Snowball @ Thu Apr 4 14:49:41 UTC 2024
|
note: Added by Snowball @ Thu Apr 4 14:49:41 UTC 2024
|
||||||
repository: "https://git.vdb.to/cerc-io/snowballtools-base"
|
repository: "https://github.com/snowball-tools/snowballtools-base"
|
||||||
repository_ref: 351db16336eacc3e1f9119ceb8d1282b8e27a27e
|
repository_ref: 351db16336eacc3e1f9119ceb8d1282b8e27a27e
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ record:
|
|||||||
type: ApplicationRecord
|
type: ApplicationRecord
|
||||||
version: 0.0.2
|
version: 0.0.2
|
||||||
repository_ref: 351db16336eacc3e1f9119ceb8d1282b8e27a27e
|
repository_ref: 351db16336eacc3e1f9119ceb8d1282b8e27a27e
|
||||||
repository: ["https://git.vdb.to/cerc-io/snowballtools-base"]
|
repository: ["https://github.com/snowball-tools/snowballtools-base"]
|
||||||
app_type: webapp
|
app_type: webapp
|
||||||
name: snowballtools-base-frontend
|
name: snowballtools-base-frontend
|
||||||
app_version: 0.1.8
|
app_version: 0.1.8
|
||||||
|
|||||||
@@ -7,18 +7,18 @@ record:
|
|||||||
config:
|
config:
|
||||||
env:
|
env:
|
||||||
LACONIC_HOSTED_CONFIG_server_url: https://snowballtools-base-api.staging.apps.snowballtools.com
|
LACONIC_HOSTED_CONFIG_server_url: https://snowballtools-base-api.staging.apps.snowballtools.com
|
||||||
LACONIC_HOSTED_CONFIG_github_clientid: Ov23liOaoahRTYd4nSCV
|
LACONIC_HOSTED_CONFIG_github_clientid: 905c09553f527d2cdff5
|
||||||
LACONIC_HOSTED_CONFIG_github_templaterepo: snowball-tools/test-progressive-web-app
|
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_pwa_templaterepo: snowball-tools/image-upload-pwa-example
|
||||||
LACONIC_HOSTED_CONFIG_github_image_upload_templaterepo: snowball-tools/image-upload-pwa-example
|
LACONIC_HOSTED_CONFIG_github_image_upload_templaterepo: snowball-tools-platform/image-upload-pwa-example
|
||||||
LACONIC_HOSTED_CONFIG_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
|
LACONIC_HOSTED_CONFIG_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
|
||||||
LACONIC_HOSTED_CONFIG_lit_relay_api_key: 15DDD969-E75F-404D-AAD9-58A37C4FD354_snowball
|
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_aplchemy_api_key: THvPart_gqI5x02RNYSBntlmwA66I_qc
|
||||||
LACONIC_HOSTED_CONFIG_bugsnag_api_key: 8c480cd5386079f9dd44f9581264a073
|
LACONIC_HOSTED_CONFIG_bugsnag_api_key: 8c480cd5386079f9dd44f9581264a073
|
||||||
LACONIC_HOSTED_CONFIG_passkey_wallet_rpid: dashboard.staging.apps.snowballtools.com
|
LACONIC_HOSTED_CONFIG_passkey_wallet_rpid: localhost
|
||||||
LACONIC_HOSTED_CONFIG_turnkey_api_base_url: https://api.turnkey.com
|
LACONIC_HOSTED_CONFIG_turnkey_api_base_url: https://api.turnkey.com/
|
||||||
LACONIC_HOSTED_CONFIG_turnkey_organization_id: 5049ae99-5bca-40b3-8317-504384d4e591
|
LACONIC_HOSTED_CONFIG_turnkey_organization_id: 5049ae99-5bca-40b3-8317-504384d4e591
|
||||||
meta:
|
meta:
|
||||||
note: Added by Snowball @ Mon Jun 24 23:51:48 UTC 2024
|
note: Added by Snowball @ Tuesday 21 May 2024 06:17:23 AM UTC
|
||||||
repository: "https://git.vdb.to/cerc-io/snowballtools-base"
|
repository: "https://github.com/snowball-tools/snowballtools-base"
|
||||||
repository_ref: 61e3e88a6c9d57e95441059369ee5a46f5c07601
|
repository_ref: 8488cfab8353321ed05c4234bf1b914c9ad3aa99
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
record:
|
record:
|
||||||
type: ApplicationRecord
|
type: ApplicationRecord
|
||||||
version: 0.0.1
|
version: 0.0.2
|
||||||
repository_ref: 61e3e88a6c9d57e95441059369ee5a46f5c07601
|
repository_ref: 8488cfab8353321ed05c4234bf1b914c9ad3aa99
|
||||||
repository: ["https://git.vdb.to/cerc-io/snowballtools-base"]
|
repository: ["https://github.com/snowball-tools/snowballtools-base"]
|
||||||
app_type: webapp
|
app_type: webapp
|
||||||
name: staging-snowballtools-base-frontend
|
name: staging-snowballtools-base-frontend
|
||||||
app_version: 0.0.0
|
app_version: 0.0.0
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Check if the live web app deployer is in a working state
|
Check if the live web app deployer is in a working state
|
||||||
|
|
||||||
- Web app repo used: <https://github.com/snowball-tools/test-progressive-web-app> (main branch)
|
- Web app repo used: https://github.com/snowball-tools-platform/test-progressive-web-app (main branch)
|
||||||
- Config used: [../config.yml](../config.yml)
|
- Config used: [../config.yml](../config.yml)
|
||||||
- The script [test-webapp-deployment-undeployment.sh](./test-webapp-deployment-undeployment.sh) performs the following:
|
- 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
|
- 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:
|
record:
|
||||||
type: ApplicationDeploymentRequest
|
type: ApplicationDeploymentRequest
|
||||||
version: "1.0.0"
|
version: '1.0.0'
|
||||||
name: deployment-test-app@0.1.24
|
name: deployment-test-app@0.1.24
|
||||||
application: crn://snowballtools/applications/deployment-test-app@0.1.24
|
application: crn://snowballtools/applications/deployment-test-app@0.1.24
|
||||||
dns: deployment-ci-test
|
dns: deployment-ci-test
|
||||||
@@ -11,5 +11,5 @@ record:
|
|||||||
CERC_WEBAPP_DEBUG: 0
|
CERC_WEBAPP_DEBUG: 0
|
||||||
meta:
|
meta:
|
||||||
note: Deployment test @ Thu 11 Apr 2024 07:29:19 AM UTC
|
note: Deployment test @ Thu 11 Apr 2024 07:29:19 AM UTC
|
||||||
repository: "https://github.com/snowball-tools/test-progressive-web-app"
|
repository: "https://github.com/snowball-tools-platform/test-progressive-web-app"
|
||||||
repository_ref: 05819619487a0d2dbc5453b6d1ccff3044c0dd26
|
repository_ref: 05819619487a0d2dbc5453b6d1ccff3044c0dd26
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ record:
|
|||||||
type: ApplicationRecord
|
type: ApplicationRecord
|
||||||
version: 0.0.1
|
version: 0.0.1
|
||||||
repository_ref: 05819619487a0d2dbc5453b6d1ccff3044c0dd26
|
repository_ref: 05819619487a0d2dbc5453b6d1ccff3044c0dd26
|
||||||
repository: ["https://github.com/snowball-tools/test-progressive-web-app"]
|
repository: ["https://github.com/snowball-tools-platform/test-progressive-web-app"]
|
||||||
app_type: webapp
|
app_type: webapp
|
||||||
name: deployment-test-app
|
name: deployment-test-app
|
||||||
app_version: 0.1.24
|
app_version: 0.1.24
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Repository URL
|
# Repository URL
|
||||||
REPO_URL="https://github.com/snowball-tools/test-progressive-web-app"
|
REPO_URL="https://github.com/snowball-tools-platform/test-progressive-web-app"
|
||||||
|
|
||||||
# Get the latest commit hash from the repository
|
# Get the latest commit hash from the repository
|
||||||
LATEST_HASH=$(git ls-remote $REPO_URL HEAD | awk '{print $1}')
|
LATEST_HASH=$(git ls-remote $REPO_URL HEAD | awk '{print $1}')
|
||||||
@@ -32,7 +32,7 @@ fi
|
|||||||
# Generate application-record.yml with incremented version
|
# Generate application-record.yml with incremented version
|
||||||
RECORD_FILE=packages/deployer/test/records/application-record.yml
|
RECORD_FILE=packages/deployer/test/records/application-record.yml
|
||||||
|
|
||||||
cat >$RECORD_FILE <<EOF
|
cat > $RECORD_FILE <<EOF
|
||||||
record:
|
record:
|
||||||
type: ApplicationRecord
|
type: ApplicationRecord
|
||||||
version: $NEW_APPLICATION_VERSION
|
version: $NEW_APPLICATION_VERSION
|
||||||
@@ -46,7 +46,7 @@ EOF
|
|||||||
# Generate application-deployment-request.yml
|
# Generate application-deployment-request.yml
|
||||||
REQUEST_RECORD_FILE=packages/deployer/test/records/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:
|
record:
|
||||||
type: ApplicationDeploymentRequest
|
type: ApplicationDeploymentRequest
|
||||||
version: '1.0.0'
|
version: '1.0.0'
|
||||||
@@ -115,7 +115,7 @@ while true; do
|
|||||||
else
|
else
|
||||||
echo "ApplicationDeploymentRecord not found, retrying in $RETRY_INTERVAL sec..."
|
echo "ApplicationDeploymentRecord not found, retrying in $RETRY_INTERVAL sec..."
|
||||||
sleep $RETRY_INTERVAL
|
sleep $RETRY_INTERVAL
|
||||||
retry_count=$((retry_count + 1))
|
retry_count=$((retry_count+1))
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "ApplicationDeploymentRecord found"
|
echo "ApplicationDeploymentRecord found"
|
||||||
@@ -154,7 +154,7 @@ while true; do
|
|||||||
else
|
else
|
||||||
echo "Deployment URL $fetched_url is not active, received code $url_response, retrying in $retry_interval sec..."
|
echo "Deployment URL $fetched_url is not active, received code $url_response, retrying in $retry_interval sec..."
|
||||||
sleep $retry_interval
|
sleep $retry_interval
|
||||||
retry_count=$((retry_count + 1))
|
retry_count=$((retry_count+1))
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -162,7 +162,7 @@ done
|
|||||||
# Generate application-deployment-removal-request.yml
|
# Generate application-deployment-removal-request.yml
|
||||||
REMOVAL_REQUEST_RECORD_FILE=packages/deployer/test/records/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:
|
record:
|
||||||
deployment: $DEPLOYMENT_RECORD_ID
|
deployment: $DEPLOYMENT_RECORD_ID
|
||||||
type: ApplicationDeploymentRemovalRequest
|
type: ApplicationDeploymentRemovalRequest
|
||||||
@@ -190,7 +190,7 @@ while true; do
|
|||||||
else
|
else
|
||||||
echo "ApplicationDeploymentRemovalRecord not found, retrying in $RETRY_INTERVAL sec..."
|
echo "ApplicationDeploymentRemovalRecord not found, retrying in $RETRY_INTERVAL sec..."
|
||||||
sleep $RETRY_INTERVAL
|
sleep $RETRY_INTERVAL
|
||||||
retry_count=$((retry_count + 1))
|
retry_count=$((retry_count+1))
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "ApplicationDeploymentRemovalRecord found"
|
echo "ApplicationDeploymentRemovalRecord found"
|
||||||
@@ -217,7 +217,7 @@ while true; do
|
|||||||
else
|
else
|
||||||
echo "Deployment URL $fetched_url is still active, received code $url_response, retrying in $retry_interval sec..."
|
echo "Deployment URL $fetched_url is still active, received code $url_response, retrying in $retry_interval sec..."
|
||||||
sleep $retry_interval
|
sleep $retry_interval
|
||||||
retry_count=$((retry_count + 1))
|
retry_count=$((retry_count+1))
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -14,4 +14,4 @@ VITE_BUGSNAG_API_KEY=
|
|||||||
|
|
||||||
VITE_PASSKEY_WALLET_RPID=
|
VITE_PASSKEY_WALLET_RPID=
|
||||||
VITE_TURNKEY_API_BASE_URL=
|
VITE_TURNKEY_API_BASE_URL=
|
||||||
VITE_TURNKEY_ORGANIZATION_ID=
|
VITE_TURNKEY_ORGANIZATION_ID=
|
||||||
@@ -9,7 +9,6 @@ import { join, dirname } from 'path';
|
|||||||
function getAbsolutePath(value: string): any {
|
function getAbsolutePath(value: string): any {
|
||||||
return dirname(require.resolve(join(value, 'package.json')));
|
return dirname(require.resolve(join(value, 'package.json')));
|
||||||
}
|
}
|
||||||
|
|
||||||
const config: StorybookConfig = {
|
const config: StorybookConfig = {
|
||||||
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
|
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
|
||||||
addons: [
|
addons: [
|
||||||
@@ -27,7 +26,6 @@ const config: StorybookConfig = {
|
|||||||
docs: {
|
docs: {
|
||||||
autodocs: 'tag',
|
autodocs: 'tag',
|
||||||
},
|
},
|
||||||
staticDirs: ['../public'],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|||||||
+23
-56
@@ -1,63 +1,30 @@
|
|||||||
# frontend
|
# React + TypeScript + Vite
|
||||||
|
|
||||||
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).
|
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||||
|
|
||||||
## Getting Started
|
Currently, two official plugins are available:
|
||||||
|
|
||||||
### Install dependencies
|
- [@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
|
||||||
|
|
||||||
In the root of the project, run:
|
## Expanding the ESLint configuration
|
||||||
|
|
||||||
```zsh
|
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||||
yarn
|
|
||||||
|
- 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,
|
||||||
|
},
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build backend
|
- 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`
|
||||||
```zsh
|
- 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
|
||||||
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)
|
|
||||||
|
|||||||
@@ -62,6 +62,7 @@
|
|||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-dropdown": "^1.11.0",
|
"react-dropdown": "^1.11.0",
|
||||||
"react-hook-form": "^7.49.0",
|
"react-hook-form": "^7.49.0",
|
||||||
|
"react-hot-toast": "^2.4.1",
|
||||||
"react-oauth-popup": "^1.0.5",
|
"react-oauth-popup": "^1.0.5",
|
||||||
"react-router-dom": "^6.20.1",
|
"react-router-dom": "^6.20.1",
|
||||||
"react-timer-hook": "^3.0.7",
|
"react-timer-hook": "^3.0.7",
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useEffect } from 'react';
|
|
||||||
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
||||||
|
|
||||||
import Projects from './pages/org-slug';
|
import Projects from './pages/org-slug';
|
||||||
@@ -11,8 +10,8 @@ import ProjectSearchLayout from './layouts/ProjectSearch';
|
|||||||
import Index from './pages';
|
import Index from './pages';
|
||||||
import AuthPage from './pages/AuthPage';
|
import AuthPage from './pages/AuthPage';
|
||||||
import { DashboardLayout } from './pages/org-slug/layout';
|
import { DashboardLayout } from './pages/org-slug/layout';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import Web3Provider from 'context/Web3Provider';
|
import Web3Provider from 'context/Web3Provider';
|
||||||
import { baseUrl } from 'utils/constants';
|
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
@@ -60,7 +59,7 @@ function App() {
|
|||||||
// Hacky way of checking session
|
// Hacky way of checking session
|
||||||
// TODO: Handle redirect backs
|
// TODO: Handle redirect backs
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch(`${baseUrl}/auth/session`, {
|
fetch(`${import.meta.env.VITE_SERVER_URL}/auth/session`, {
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
import {
|
|
||||||
VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO,
|
|
||||||
VITE_GITHUB_PWA_TEMPLATE_REPO,
|
|
||||||
} from 'utils/constants';
|
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
name: 'Progressive Web App (PWA)',
|
name: 'Progressive Web App (PWA)',
|
||||||
icon: 'pwa',
|
icon: 'pwa',
|
||||||
repoFullName: `${VITE_GITHUB_PWA_TEMPLATE_REPO}`,
|
repoFullName: `${import.meta.env.VITE_GITHUB_PWA_TEMPLATE_REPO}`,
|
||||||
isComingSoon: false,
|
isComingSoon: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '2',
|
id: '2',
|
||||||
name: 'Image Upload PWA',
|
name: 'Image Upload PWA',
|
||||||
icon: 'pwa',
|
icon: 'pwa',
|
||||||
repoFullName: `${VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO}`,
|
repoFullName: `${import.meta.env.VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO}`,
|
||||||
isComingSoon: false,
|
isComingSoon: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { useCombobox } from 'downshift';
|
import { useCombobox } from 'downshift';
|
||||||
import { Project } from 'gql-client';
|
import { Project } from 'gql-client';
|
||||||
import { useDebounceValue } from 'usehooks-ts';
|
import { useDebounce } from 'usehooks-ts';
|
||||||
|
|
||||||
import SearchBar from 'components/SearchBar';
|
import SearchBar from 'components/SearchBar';
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
import { useGQLClient } from 'context/GQLClientContext';
|
||||||
@@ -42,7 +42,7 @@ export const ProjectSearchBar = ({ onChange }: ProjectSearchBarProps) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [debouncedInputValue, _] = useDebounceValue<string>(inputValue, 300);
|
const debouncedInputValue = useDebounce<string>(inputValue, 300);
|
||||||
|
|
||||||
const fetchProjects = useCallback(
|
const fetchProjects = useCallback(
|
||||||
async (inputValue: string) => {
|
async (inputValue: string) => {
|
||||||
@@ -62,7 +62,7 @@ export const ProjectSearchBar = ({ onChange }: ProjectSearchBarProps) => {
|
|||||||
<div className="relative w-full lg:w-fit">
|
<div className="relative w-full lg:w-fit">
|
||||||
<SearchBar {...getInputProps()} />
|
<SearchBar {...getInputProps()} />
|
||||||
<div
|
<div
|
||||||
{...getMenuProps({}, { suppressRefError: true })}
|
{...getMenuProps()}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex flex-col shadow-dropdown rounded-xl bg-surface-card absolute w-[459px] max-h-52 overflow-y-auto px-2 py-2 gap-1 z-50',
|
'flex flex-col shadow-dropdown rounded-xl bg-surface-card absolute w-[459px] max-h-52 overflow-y-auto px-2 py-2 gap-1 z-50',
|
||||||
{ hidden: !inputValue || !isOpen },
|
{ hidden: !inputValue || !isOpen },
|
||||||
|
|||||||
+37
-52
@@ -5,7 +5,7 @@ import { CrossIcon, SearchIcon } from 'components/shared/CustomIcon';
|
|||||||
import { Input } from 'components/shared/Input';
|
import { Input } from 'components/shared/Input';
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
import { useGQLClient } from 'context/GQLClientContext';
|
||||||
import { Project } from 'gql-client';
|
import { Project } from 'gql-client';
|
||||||
import { useDebounceValue } from 'usehooks-ts';
|
import { useDebounce } from 'usehooks-ts';
|
||||||
import { ProjectSearchBarItem } from './ProjectSearchBarItem';
|
import { ProjectSearchBarItem } from './ProjectSearchBarItem';
|
||||||
import { ProjectSearchBarEmpty } from './ProjectSearchBarEmpty';
|
import { ProjectSearchBarEmpty } from './ProjectSearchBarEmpty';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
@@ -27,30 +27,25 @@ export const ProjectSearchBarDialog = ({
|
|||||||
const client = useGQLClient();
|
const client = useGQLClient();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const {
|
const { getInputProps, getItemProps, inputValue, setInputValue } =
|
||||||
getInputProps,
|
useCombobox({
|
||||||
getItemProps,
|
items,
|
||||||
getMenuProps,
|
itemToString(item) {
|
||||||
inputValue,
|
return item ? item.name : '';
|
||||||
setInputValue,
|
},
|
||||||
} = useCombobox({
|
selectedItem,
|
||||||
items,
|
onSelectedItemChange: ({ selectedItem: newSelectedItem }) => {
|
||||||
itemToString(item) {
|
if (newSelectedItem) {
|
||||||
return item ? item.name : '';
|
setSelectedItem(newSelectedItem);
|
||||||
},
|
onClickItem?.(newSelectedItem);
|
||||||
selectedItem,
|
navigate(
|
||||||
onSelectedItemChange: ({ selectedItem: newSelectedItem }) => {
|
`/${newSelectedItem.organization.slug}/projects/${newSelectedItem.id}`,
|
||||||
if (newSelectedItem) {
|
);
|
||||||
setSelectedItem(newSelectedItem);
|
}
|
||||||
onClickItem?.(newSelectedItem);
|
},
|
||||||
navigate(
|
});
|
||||||
`/${newSelectedItem.organization.slug}/projects/${newSelectedItem.id}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const [debouncedInputValue, _] = useDebounceValue<string>(inputValue, 300);
|
const debouncedInputValue = useDebounce<string>(inputValue, 300);
|
||||||
|
|
||||||
const fetchProjects = useCallback(
|
const fetchProjects = useCallback(
|
||||||
async (inputValue: string) => {
|
async (inputValue: string) => {
|
||||||
@@ -80,7 +75,7 @@ export const ProjectSearchBarDialog = ({
|
|||||||
<div className="h-full flex flex-col fixed top-0 inset-0">
|
<div className="h-full flex flex-col fixed top-0 inset-0">
|
||||||
<div className="py-2.5 px-4 flex items-center justify-between border-b border-border-separator/[0.06]">
|
<div className="py-2.5 px-4 flex items-center justify-between border-b border-border-separator/[0.06]">
|
||||||
<Input
|
<Input
|
||||||
{...getInputProps({}, { suppressRefError: true })}
|
{...getInputProps()}
|
||||||
leftIcon={<SearchIcon />}
|
leftIcon={<SearchIcon />}
|
||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
appearance="borderless"
|
appearance="borderless"
|
||||||
@@ -91,33 +86,23 @@ export const ProjectSearchBarDialog = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<div
|
<div className="flex flex-col gap-1 px-2 py-2">
|
||||||
className="flex flex-col gap-1 px-2 py-2"
|
{items.length > 0
|
||||||
{...getMenuProps(
|
? items.map((item, index) => (
|
||||||
{},
|
<>
|
||||||
{
|
<div className="px-2 py-2">
|
||||||
suppressRefError: true,
|
<p className="text-elements-mid-em text-xs font-medium">
|
||||||
},
|
Suggestions
|
||||||
)}
|
</p>
|
||||||
>
|
</div>
|
||||||
{items.length > 0 ? (
|
<ProjectSearchBarItem
|
||||||
<>
|
key={item.id}
|
||||||
<div className="px-2 py-2">
|
item={item}
|
||||||
<p className="text-elements-mid-em text-xs font-medium">
|
{...getItemProps({ item, index })}
|
||||||
Suggestions
|
/>
|
||||||
</p>
|
</>
|
||||||
</div>
|
))
|
||||||
{items.map((item, index) => (
|
: inputValue && <ProjectSearchBarEmpty />}
|
||||||
<ProjectSearchBarItem
|
|
||||||
key={item.id}
|
|
||||||
item={item}
|
|
||||||
{...getItemProps({ item, index })}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
inputValue && <ProjectSearchBarEmpty />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog.Content>
|
</Dialog.Content>
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ import { useToast } from '../../shared/Toast';
|
|||||||
import { IconWithFrame } from '../../shared/IconWithFrame';
|
import { IconWithFrame } from '../../shared/IconWithFrame';
|
||||||
import { Heading } from '../../shared/Heading';
|
import { Heading } from '../../shared/Heading';
|
||||||
import { MockConnectGitCard } from './MockConnectGitCard';
|
import { MockConnectGitCard } from './MockConnectGitCard';
|
||||||
import { VITE_GITHUB_CLIENT_ID } from 'utils/constants';
|
|
||||||
|
|
||||||
const SCOPES = 'repo user';
|
const SCOPES = 'repo user';
|
||||||
const GITHUB_OAUTH_URL = `https://github.com/login/oauth/authorize?client_id=${VITE_GITHUB_CLIENT_ID}&scope=${encodeURIComponent(SCOPES)}`;
|
const GITHUB_OAUTH_URL = `https://github.com/login/oauth/authorize?client_id=${
|
||||||
|
import.meta.env.VITE_GITHUB_CLIENT_ID
|
||||||
|
}&scope=${encodeURIComponent(SCOPES)}`;
|
||||||
|
|
||||||
interface ConnectAccountInterface {
|
interface ConnectAccountInterface {
|
||||||
onAuth: (token: string) => void;
|
onAuth: (token: string) => void;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useState } from 'react';
|
|||||||
import { Domain, DomainStatus, Project } from 'gql-client';
|
import { Domain, DomainStatus, Project } from 'gql-client';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
Chip,
|
||||||
Typography,
|
Typography,
|
||||||
Menu,
|
Menu,
|
||||||
MenuHandler,
|
MenuHandler,
|
||||||
@@ -14,15 +15,6 @@ import EditDomainDialog from './EditDomainDialog';
|
|||||||
import { useGQLClient } from 'context/GQLClientContext';
|
import { useGQLClient } from 'context/GQLClientContext';
|
||||||
import { DeleteDomainDialog } from 'components/projects/Dialog/DeleteDomainDialog';
|
import { DeleteDomainDialog } from 'components/projects/Dialog/DeleteDomainDialog';
|
||||||
import { useToast } from 'components/shared/Toast';
|
import { useToast } from 'components/shared/Toast';
|
||||||
import { Tag } from 'components/shared/Tag';
|
|
||||||
import {
|
|
||||||
CheckIcon,
|
|
||||||
CrossIcon,
|
|
||||||
GearIcon,
|
|
||||||
LoadingIcon,
|
|
||||||
} from 'components/shared/CustomIcon';
|
|
||||||
import { Heading } from 'components/shared/Heading';
|
|
||||||
import { Button } from 'components/shared/Button';
|
|
||||||
|
|
||||||
enum RefreshStatus {
|
enum RefreshStatus {
|
||||||
IDLE,
|
IDLE,
|
||||||
@@ -87,29 +79,22 @@ const DomainCard = ({
|
|||||||
<>
|
<>
|
||||||
<div className="flex justify-between py-3">
|
<div className="flex justify-between py-3">
|
||||||
<div className="flex justify-start gap-1">
|
<div className="flex justify-start gap-1">
|
||||||
<Heading as="h6" className="flex-col">
|
<Typography variant="h6">
|
||||||
{domain.name}{' '}
|
<i>^</i> {domain.name}
|
||||||
<Tag
|
</Typography>
|
||||||
type={
|
<Chip
|
||||||
domain.status === DomainStatus.Live ? 'positive' : 'negative'
|
className="w-fit capitalize"
|
||||||
}
|
value={domain.status}
|
||||||
leftIcon={
|
color={domain.status === DomainStatus.Live ? 'green' : 'orange'}
|
||||||
domain.status === DomainStatus.Live ? (
|
variant="ghost"
|
||||||
<CheckIcon />
|
icon={<i>^</i>}
|
||||||
) : (
|
/>
|
||||||
<CrossIcon />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{domain.status}
|
|
||||||
</Tag>
|
|
||||||
</Heading>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-start gap-1">
|
<div className="flex justify-start gap-1">
|
||||||
<i
|
<i
|
||||||
id="refresh"
|
id="refresh"
|
||||||
className="cursor-pointer"
|
className="cursor-pointer w-8 h-8"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
SetRefreshStatus(RefreshStatus.CHECKING);
|
SetRefreshStatus(RefreshStatus.CHECKING);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -117,17 +102,11 @@ const DomainCard = ({
|
|||||||
}, CHECK_FAIL_TIMEOUT);
|
}, CHECK_FAIL_TIMEOUT);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{refreshStatus === RefreshStatus.CHECKING ? (
|
{refreshStatus === RefreshStatus.CHECKING ? 'L' : 'R'}
|
||||||
<LoadingIcon className="animate-spin" />
|
|
||||||
) : (
|
|
||||||
'L'
|
|
||||||
)}
|
|
||||||
</i>
|
</i>
|
||||||
<Menu placement="bottom-end">
|
<Menu placement="bottom-end">
|
||||||
<MenuHandler>
|
<MenuHandler>
|
||||||
<Button iconOnly>
|
<button className="border-2 rounded-full w-8 h-8">...</button>
|
||||||
<GearIcon />
|
|
||||||
</Button>
|
|
||||||
</MenuHandler>
|
</MenuHandler>
|
||||||
<MenuList>
|
<MenuList>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
@@ -164,13 +143,13 @@ const DomainCard = ({
|
|||||||
{domain.status === DomainStatus.Pending && (
|
{domain.status === DomainStatus.Pending && (
|
||||||
<Card className="bg-slate-100 p-4 text-sm">
|
<Card className="bg-slate-100 p-4 text-sm">
|
||||||
{refreshStatus === RefreshStatus.IDLE ? (
|
{refreshStatus === RefreshStatus.IDLE ? (
|
||||||
<Heading>
|
<Typography variant="small">
|
||||||
^ Add these records to your domain and refresh to check
|
^ Add these records to your domain and refresh to check
|
||||||
</Heading>
|
</Typography>
|
||||||
) : refreshStatus === RefreshStatus.CHECKING ? (
|
) : refreshStatus === RefreshStatus.CHECKING ? (
|
||||||
<Heading className="text-blue-500">
|
<Typography variant="small" className="text-blue-500">
|
||||||
^ Checking records for {domain.name}
|
^ Checking records for {domain.name}
|
||||||
</Heading>
|
</Typography>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex gap-2 text-red-500 mb-2">
|
<div className="flex gap-2 text-red-500 mb-2">
|
||||||
<div className="grow">
|
<div className="grow">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useCallback, useEffect, useMemo } from 'react';
|
||||||
import { Controller, useForm, SubmitHandler } from 'react-hook-form';
|
import { Controller, useForm, SubmitHandler } from 'react-hook-form';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
import { Domain } from 'gql-client';
|
import { Domain } from 'gql-client';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -8,11 +9,10 @@ import {
|
|||||||
Option,
|
Option,
|
||||||
} from '@snowballtools/material-tailwind-react-fork';
|
} from '@snowballtools/material-tailwind-react-fork';
|
||||||
|
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
import { useGQLClient } from '../../../../context/GQLClientContext';
|
||||||
import { Modal } from 'components/shared/Modal';
|
import { Modal } from 'components/shared/Modal';
|
||||||
import { Button } from 'components/shared/Button';
|
import { Button } from 'components/shared/Button';
|
||||||
import { Input } from 'components/shared/Input';
|
import { Input } from 'components/shared/Input';
|
||||||
import { useToast } from 'components/shared/Toast';
|
|
||||||
|
|
||||||
const DEFAULT_REDIRECT_OPTIONS = ['none'];
|
const DEFAULT_REDIRECT_OPTIONS = ['none'];
|
||||||
|
|
||||||
@@ -40,7 +40,6 @@ const EditDomainDialog = ({
|
|||||||
onUpdate,
|
onUpdate,
|
||||||
}: EditDomainDialogProp) => {
|
}: EditDomainDialogProp) => {
|
||||||
const client = useGQLClient();
|
const client = useGQLClient();
|
||||||
const { toast, dismiss } = useToast();
|
|
||||||
|
|
||||||
const getRedirectUrl = (domain: Domain) => {
|
const getRedirectUrl = (domain: Domain) => {
|
||||||
const redirectDomain = domain.redirectTo;
|
const redirectDomain = domain.redirectTo;
|
||||||
@@ -100,20 +99,10 @@ const EditDomainDialog = ({
|
|||||||
|
|
||||||
if (updateDomain) {
|
if (updateDomain) {
|
||||||
await onUpdate();
|
await onUpdate();
|
||||||
toast({
|
toast.success(`Domain ${domain.name} has been updated`);
|
||||||
id: 'domain_id_updated',
|
|
||||||
title: `Domain ${domain.name} has been updated`,
|
|
||||||
variant: 'success',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
reset();
|
reset();
|
||||||
toast({
|
toast.error(`Error updating domain ${domain.name}`);
|
||||||
id: 'domain_id_error_update',
|
|
||||||
title: `Error updating domain ${domain.name}`,
|
|
||||||
variant: 'error',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleOpen();
|
handleOpen();
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import { useState } from 'react';
|
|||||||
import { DeleteWebhookDialog } from 'components/projects/Dialog/DeleteWebhookDialog';
|
import { DeleteWebhookDialog } from 'components/projects/Dialog/DeleteWebhookDialog';
|
||||||
import { Button } from 'components/shared/Button';
|
import { Button } from 'components/shared/Button';
|
||||||
import { useToast } from 'components/shared/Toast';
|
import { useToast } from 'components/shared/Toast';
|
||||||
import { Input } from 'components/shared/Input';
|
|
||||||
import { CopyIcon, TrashIcon } from 'components/shared/CustomIcon';
|
|
||||||
|
|
||||||
interface WebhookCardProps {
|
interface WebhookCardProps {
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
@@ -16,12 +14,11 @@ const WebhookCard = ({ webhookUrl, onDelete }: WebhookCardProps) => {
|
|||||||
|
|
||||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-between w-full mb-3 gap-3">
|
<div className="flex justify-between w-full mb-3">
|
||||||
<Input value={webhookUrl} disabled />
|
{webhookUrl}
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<Button
|
<Button
|
||||||
iconOnly
|
size="sm"
|
||||||
size="md"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigator.clipboard.writeText(webhookUrl);
|
navigator.clipboard.writeText(webhookUrl);
|
||||||
toast({
|
toast({
|
||||||
@@ -32,17 +29,16 @@ const WebhookCard = ({ webhookUrl, onDelete }: WebhookCardProps) => {
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CopyIcon />
|
Copy
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
iconOnly
|
size="sm"
|
||||||
size="md"
|
|
||||||
variant="danger"
|
variant="danger"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDeleteDialogOpen(true);
|
setDeleteDialogOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TrashIcon />
|
X
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<DeleteWebhookDialog
|
<DeleteWebhookDialog
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import { cn } from 'utils/classnames';
|
|||||||
import { useMediaQuery } from 'usehooks-ts';
|
import { useMediaQuery } from 'usehooks-ts';
|
||||||
import { SIDEBAR_MENU } from './constants';
|
import { SIDEBAR_MENU } from './constants';
|
||||||
import { UserSelect } from 'components/shared/UserSelect';
|
import { UserSelect } from 'components/shared/UserSelect';
|
||||||
import { baseUrl } from 'utils/constants';
|
|
||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
mobileOpen?: boolean;
|
mobileOpen?: boolean;
|
||||||
@@ -84,7 +83,7 @@ export const Sidebar = ({ mobileOpen }: SidebarProps) => {
|
|||||||
}, [orgSlug]);
|
}, [orgSlug]);
|
||||||
|
|
||||||
const handleLogOut = useCallback(async () => {
|
const handleLogOut = useCallback(async () => {
|
||||||
await fetch(`${baseUrl}/auth/logout`, {
|
await fetch(`${import.meta.env.VITE_SERVER_URL}/auth/logout`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,117 +0,0 @@
|
|||||||
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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { VerifyCodeInput } from './VerifyCodeInput';
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
export { Avatar } from './Avatar';
|
|
||||||
export { Badge } from './Badge';
|
|
||||||
export { Button } from './Button';
|
|
||||||
export { Calendar } from './Calendar';
|
|
||||||
export { Checkbox } from './Checkbox';
|
|
||||||
export { DatePicker } from './DatePicker';
|
|
||||||
export { DotBorder } from './DotBorder';
|
|
||||||
export { Heading } from './Heading';
|
|
||||||
export { IconWithFrame } from './IconWithFrame';
|
|
||||||
export { InlineNotification } from './InlineNotification';
|
|
||||||
export { Input } from './Input';
|
|
||||||
export { Modal } from './Modal';
|
|
||||||
export { OverflownText } from './OverflownText';
|
|
||||||
export { Radio } from './Radio';
|
|
||||||
export { SegmentedControls } from './SegmentedControls';
|
|
||||||
export { Select } from './Select';
|
|
||||||
export { Sidebar } from './Sidebar';
|
|
||||||
export { Step } from './Steps';
|
|
||||||
export { Switch } from './Switch';
|
|
||||||
export { Table } from './Table';
|
|
||||||
export { Tabs } from './Tabs';
|
|
||||||
export { Tag } from './Tag';
|
|
||||||
export { useToast } from './Toast';
|
|
||||||
export { Tooltip } from './Tooltip';
|
|
||||||
export { UserSelect } from './UserSelect';
|
|
||||||
export { VerifyCodeInput } from './VerifyCodeInput';
|
|
||||||
export { WavyBorder } from './WavyBorder';
|
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||||
|
|
||||||
import { VITE_WALLET_CONNECT_ID } from 'utils/constants';
|
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
if (!VITE_WALLET_CONNECT_ID) {
|
if (!import.meta.env.VITE_WALLET_CONNECT_ID) {
|
||||||
throw new Error('Error: REACT_APP_WALLET_CONNECT_ID env config is not set');
|
throw new Error('Error: REACT_APP_WALLET_CONNECT_ID env config is not set');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import { GQLClientProvider } from './context/GQLClientContext';
|
|||||||
import { SERVER_GQL_PATH } from './constants';
|
import { SERVER_GQL_PATH } from './constants';
|
||||||
import { Toaster } from 'components/shared/Toast';
|
import { Toaster } from 'components/shared/Toast';
|
||||||
import { LogErrorBoundary } from 'utils/log-error';
|
import { LogErrorBoundary } from 'utils/log-error';
|
||||||
import { baseUrl } from 'utils/constants';
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
console.log(`v-${__VERSION__}`);
|
console.log(`v-${__VERSION__}`);
|
||||||
@@ -23,8 +22,8 @@ const root = ReactDOM.createRoot(
|
|||||||
document.getElementById('root') as HTMLElement,
|
document.getElementById('root') as HTMLElement,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert(baseUrl, 'VITE_SERVER_URL is not set in env');
|
assert(import.meta.env.VITE_SERVER_URL, 'VITE_SERVER_URL is not set in env');
|
||||||
const gqlEndpoint = `${baseUrl}/${SERVER_GQL_PATH}`;
|
const gqlEndpoint = `${import.meta.env.VITE_SERVER_URL}/${SERVER_GQL_PATH}`;
|
||||||
|
|
||||||
const gqlClient = new GQLClient({ gqlEndpoint });
|
const gqlClient = new GQLClient({ gqlEndpoint });
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const ProjectSearch = () => {
|
|||||||
return (
|
return (
|
||||||
<section className="h-full flex flex-col">
|
<section className="h-full flex flex-col">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="sticky hidden lg:block top-0 border-b bg-base-bg border-border-separator/[0.06] hover:z-30">
|
<div className="sticky hidden lg:block top-0 border-b bg-base-bg border-border-separator/[0.06] z-30">
|
||||||
<div className="flex pr-6 pl-2 py-2 items-center">
|
<div className="flex pr-6 pl-2 py-2 items-center">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<ProjectSearchBar
|
<ProjectSearchBar
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
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)} />
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -21,7 +21,6 @@ import {
|
|||||||
turnkeySignin,
|
turnkeySignin,
|
||||||
turnkeySignup,
|
turnkeySignup,
|
||||||
} from 'utils/turnkey-frontend';
|
} from 'utils/turnkey-frontend';
|
||||||
import { verifyAccessCode } from 'utils/accessCode';
|
|
||||||
|
|
||||||
type Provider = 'google' | 'github' | 'apple' | 'email';
|
type Provider = 'google' | 'github' | 'apple' | 'email';
|
||||||
|
|
||||||
@@ -112,29 +111,6 @@ export const SignUp = ({ onDone }: Props) => {
|
|||||||
const loading = provider;
|
const loading = provider;
|
||||||
const emailValid = /.@./.test(email);
|
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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="self-stretch p-3 xs:p-6 flex-col justify-center items-center gap-5 flex">
|
<div className="self-stretch p-3 xs:p-6 flex-col justify-center items-center gap-5 flex">
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
import { snowball } from 'utils/use-snowball';
|
import { snowball } from 'utils/use-snowball';
|
||||||
import { Login } from './Login';
|
import { Login } from './Login';
|
||||||
|
import { SignUp } from './SignUp';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
import { Done } from './Done';
|
import { Done } from './Done';
|
||||||
import { AccessSignUp } from './AccessSignUp';
|
|
||||||
|
|
||||||
type Screen = 'login' | 'signup' | 'success';
|
type Screen = 'login' | 'signup' | 'success';
|
||||||
|
|
||||||
const DASHBOARD_URL = '/';
|
const DASHBOARD_URL = '/';
|
||||||
|
|
||||||
export const SnowballAuth: React.FC = () => {
|
export const SnowballAuth = () => {
|
||||||
const path = window.location.pathname;
|
const path = window.location.pathname;
|
||||||
const [screen, setScreen] = useState<Screen>(
|
const [screen, setScreen] = useState<Screen>(
|
||||||
path === '/login' ? 'login' : 'signup',
|
path === '/login' ? 'login' : 'signup',
|
||||||
@@ -31,7 +30,7 @@ export const SnowballAuth: React.FC = () => {
|
|||||||
|
|
||||||
if (screen === 'signup') {
|
if (screen === 'signup') {
|
||||||
return (
|
return (
|
||||||
<AccessSignUp
|
<SignUp
|
||||||
onDone={() => {
|
onDone={() => {
|
||||||
setScreen('success');
|
setScreen('success');
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,19 +1,5 @@
|
|||||||
import { Heading } from 'components/shared/Heading';
|
|
||||||
|
|
||||||
const Settings = () => {
|
const Settings = () => {
|
||||||
return (
|
return <div className="p-5">Settings page</div>;
|
||||||
<section className="px-4 md:px-6 py-6 flex flex-col gap-6">
|
|
||||||
{/* Header */}
|
|
||||||
<div className="flex items-center">
|
|
||||||
<div className="grow">
|
|
||||||
<div className="flex gap-4 items-center">
|
|
||||||
<Heading as="h2" className="text-[24px]">
|
|
||||||
Settings
|
|
||||||
</Heading>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Settings;
|
export default Settings;
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { Link, useParams } from 'react-router-dom';
|
import { Link, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { ProjectCard } from 'components/projects/ProjectCard';
|
|
||||||
import { Heading, Badge, Button } from 'components/shared';
|
|
||||||
import { PlusIcon } from 'components/shared/CustomIcon';
|
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
|
||||||
import { Project } from 'gql-client';
|
import { Project } from 'gql-client';
|
||||||
|
import { Button } from 'components/shared/Button';
|
||||||
|
|
||||||
|
import { PlusIcon } from 'components/shared/CustomIcon';
|
||||||
|
import { ProjectCard } from 'components/projects/ProjectCard';
|
||||||
|
import { Heading } from 'components/shared/Heading';
|
||||||
|
import { Badge } from 'components/shared/Badge';
|
||||||
|
import { useGQLClient } from 'context/GQLClientContext';
|
||||||
|
|
||||||
const Projects = () => {
|
const Projects = () => {
|
||||||
const client = useGQLClient();
|
const client = useGQLClient();
|
||||||
|
|||||||
@@ -11,128 +11,98 @@ import {
|
|||||||
import { Heading } from 'components/shared/Heading';
|
import { Heading } from 'components/shared/Heading';
|
||||||
|
|
||||||
import logoAnimation from 'components/../../public/lottie/logo.json';
|
import logoAnimation from 'components/../../public/lottie/logo.json';
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
|
||||||
import { Project } from 'gql-client';
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
const Id = () => {
|
const Id = () => {
|
||||||
const { id, orgSlug } = useParams();
|
const { id, orgSlug } = useParams();
|
||||||
const client = useGQLClient();
|
|
||||||
const [project, setProject] = useState<Project | null>(null);
|
|
||||||
|
|
||||||
const handleSetupDomain = async () => {
|
const handleSetupDomain = () => {
|
||||||
if (id) {
|
//TODO: Implement this
|
||||||
// console.log('id', id);
|
|
||||||
// console.log('getting project for id', id);
|
|
||||||
const project = await client.getProject(id);
|
|
||||||
// console.log('project found:', project);
|
|
||||||
if (project && project.project) {
|
|
||||||
// console.log('project:', project.project);
|
|
||||||
setProject(project.project);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
window.location.href = '/';
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
handleSetupDomain();
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="flex flex-col gap-8 lg:gap-11 max-w-[522px] mx-auto py-6 lg:py-12">
|
||||||
{project ? (
|
{/* Icon */}
|
||||||
<div className="flex flex-col gap-8 lg:gap-11 max-w-[522px] mx-auto py-6 lg:py-12">
|
<div className="flex justify-center">
|
||||||
{/* Icon */}
|
<Lottie animationData={logoAnimation} loop={false} size={40} />
|
||||||
<div className="flex justify-center">
|
</div>
|
||||||
<Lottie animationData={logoAnimation} loop={false} size={40} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Heading */}
|
{/* Heading */}
|
||||||
<div className="flex flex-col items-center gap-1.5">
|
<div className="flex flex-col items-center gap-1.5">
|
||||||
<Heading as="h3" className="font-medium text-xl">
|
<Heading as="h3" className="font-medium text-xl">
|
||||||
Project deployed successfully.
|
Project deployed successfully.
|
||||||
</Heading>
|
</Heading>
|
||||||
<p className="flex flex-col items-center lg:flex-row font-sans gap-0.5 lg:gap-2 text-sm text-elements-high-em">
|
<p className="flex flex-col items-center lg:flex-row font-sans gap-0.5 lg:gap-2 text-sm text-elements-high-em">
|
||||||
Your project has been deployed at{' '}
|
Your project has been deployed at{' '}
|
||||||
<Button
|
<Button
|
||||||
className="no-underline text-elements-link"
|
className="no-underline text-elements-link"
|
||||||
// TODO: use dynamic value
|
// TODO: use dynamic value
|
||||||
href={project ? `https://${project.subDomain}` : ''}
|
href="https://www.iglootools.snowballtools.xyz"
|
||||||
as="a"
|
as="a"
|
||||||
variant="link-emphasized"
|
variant="link-emphasized"
|
||||||
external
|
external
|
||||||
leftIcon={<LinkChainIcon />}
|
leftIcon={<LinkChainIcon />}
|
||||||
>
|
>
|
||||||
{project.subDomain}
|
{/* // TODO: use dynamic value */}
|
||||||
|
www.iglootools.snowballtools.xyz
|
||||||
|
</Button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Card */}
|
||||||
|
<div className="bg-base-bg-alternate rounded-xl shadow-inset w-full px-1 py-1">
|
||||||
|
{/* Trigger question */}
|
||||||
|
<div className="flex gap-2 justify-center items-center py-3">
|
||||||
|
<div className="h-5 w-5">
|
||||||
|
<QuestionMarkRoundFilledIcon size={18} />
|
||||||
|
</div>
|
||||||
|
<Heading as="h5" className="font-sans font-medium text-sm">
|
||||||
|
{`Wondering what's next?`}
|
||||||
|
</Heading>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* CTA card */}
|
||||||
|
<div className="bg-surface-card rounded-xl shadow-card-sm px-4 py-4">
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Badge variant="secondary">1</Badge>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<Heading as="h6" className="text-sm font-sans">
|
||||||
|
Add a custom domain
|
||||||
|
</Heading>
|
||||||
|
<p className="text-xs text-elements-low-em font-sans">
|
||||||
|
Make it easy for your visitors to remember your URL with a
|
||||||
|
custom domain.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button onClick={handleSetupDomain} variant="tertiary" size="sm">
|
||||||
|
Setup domain
|
||||||
</Button>
|
</Button>
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Card */}
|
|
||||||
<div className="bg-base-bg-alternate rounded-xl shadow-inset w-full px-1 py-1">
|
|
||||||
{/* Trigger question */}
|
|
||||||
<div className="flex gap-2 justify-center items-center py-3">
|
|
||||||
<div className="h-5 w-5">
|
|
||||||
<QuestionMarkRoundFilledIcon size={18} />
|
|
||||||
</div>
|
|
||||||
<Heading as="h5" className="font-sans font-medium text-sm">
|
|
||||||
{`Wondering what's next?`}
|
|
||||||
</Heading>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* CTA card */}
|
|
||||||
<div className="bg-surface-card rounded-xl shadow-card-sm px-4 py-4">
|
|
||||||
<div className="flex gap-2">
|
|
||||||
<Badge variant="secondary">1</Badge>
|
|
||||||
<div className="space-y-3">
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<Heading as="h6" className="text-sm font-sans">
|
|
||||||
Add a custom domain
|
|
||||||
</Heading>
|
|
||||||
<p className="text-xs text-elements-low-em font-sans">
|
|
||||||
Make it easy for your visitors to remember your URL with a
|
|
||||||
custom domain.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
onClick={handleSetupDomain}
|
|
||||||
variant="tertiary"
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
Setup domain
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* CTA Buttons */}
|
|
||||||
<div className="flex flex-col lg:flex-row justify-center gap-3">
|
|
||||||
<div className="w-full lg:w-fit">
|
|
||||||
<Link to="/">
|
|
||||||
<Button
|
|
||||||
leftIcon={<ArrowLeftCircleFilledIcon />}
|
|
||||||
fullWidth
|
|
||||||
variant="tertiary"
|
|
||||||
>
|
|
||||||
Back to projects
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
<div className="w-full lg:w-fit">
|
|
||||||
<Link to={`/${orgSlug}/projects/${id}`}>
|
|
||||||
<Button fullWidth variant="primary">
|
|
||||||
View project
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
</div>
|
||||||
<></>
|
|
||||||
)}
|
{/* CTA Buttons */}
|
||||||
</>
|
<div className="flex flex-col lg:flex-row justify-center gap-3">
|
||||||
|
<div className="w-full lg:w-fit">
|
||||||
|
<Link to="/">
|
||||||
|
<Button
|
||||||
|
leftIcon={<ArrowLeftCircleFilledIcon />}
|
||||||
|
fullWidth
|
||||||
|
variant="tertiary"
|
||||||
|
>
|
||||||
|
Back to projects
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="w-full lg:w-fit">
|
||||||
|
<Link to={`/${orgSlug}/projects/${id}`}>
|
||||||
|
<Button fullWidth variant="primary">
|
||||||
|
View project
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,7 @@ import { Template } from '../../../../../types/types';
|
|||||||
import { Heading } from 'components/shared/Heading';
|
import { Heading } from 'components/shared/Heading';
|
||||||
import { Input } from 'components/shared/Input';
|
import { Input } from 'components/shared/Input';
|
||||||
import { Select, SelectOption } from 'components/shared/Select';
|
import { Select, SelectOption } from 'components/shared/Select';
|
||||||
import {
|
import { ArrowRightCircleFilledIcon } from 'components/shared/CustomIcon';
|
||||||
ArrowRightCircleFilledIcon,
|
|
||||||
LoadingIcon,
|
|
||||||
} from 'components/shared/CustomIcon';
|
|
||||||
import { Checkbox } from 'components/shared/Checkbox';
|
import { Checkbox } from 'components/shared/Checkbox';
|
||||||
import { Button } from 'components/shared/Button';
|
import { Button } from 'components/shared/Button';
|
||||||
import { useToast } from 'components/shared/Toast';
|
import { useToast } from 'components/shared/Toast';
|
||||||
@@ -53,22 +50,36 @@ const CreateRepo = () => {
|
|||||||
assert(template.repoFullName, 'Template URL not provided');
|
assert(template.repoFullName, 'Template URL not provided');
|
||||||
const [owner, repo] = template.repoFullName.split('/');
|
const [owner, repo] = template.repoFullName.split('/');
|
||||||
|
|
||||||
setIsLoading(true);
|
// 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,
|
||||||
|
});
|
||||||
|
|
||||||
const { addProjectFromTemplate } = await client.addProjectFromTemplate(
|
if (!gitRepo) {
|
||||||
orgSlug!,
|
return;
|
||||||
{
|
}
|
||||||
templateOwner: owner,
|
|
||||||
templateRepo: repo,
|
|
||||||
owner: data.account,
|
|
||||||
name: data.repoName,
|
|
||||||
isPrivate: false,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
navigate(
|
// Refetch to always get correct default branch
|
||||||
`deploy?projectId=${addProjectFromTemplate.id}&templateId=${template.id}`,
|
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}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
|
||||||
@@ -195,13 +206,7 @@ const CreateRepo = () => {
|
|||||||
{...buttonSize}
|
{...buttonSize}
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!Boolean(template.repoFullName) || isLoading}
|
disabled={!Boolean(template.repoFullName) || isLoading}
|
||||||
rightIcon={
|
rightIcon={<ArrowRightCircleFilledIcon />}
|
||||||
isLoading ? (
|
|
||||||
<LoadingIcon className="animate-spin" />
|
|
||||||
) : (
|
|
||||||
<ArrowRightCircleFilledIcon />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
Deploy
|
Deploy
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { Domain, DomainStatus } from 'gql-client';
|
||||||
import { Link, useNavigate, useOutletContext } from 'react-router-dom';
|
import { Link, useNavigate, useOutletContext } from 'react-router-dom';
|
||||||
import { RequestError } from 'octokit';
|
import { RequestError } from 'octokit';
|
||||||
|
|
||||||
import { useOctokit } from 'context/OctokitContext';
|
import { useOctokit } from '../../../../context/OctokitContext';
|
||||||
import { GitCommitWithBranch, OutletContextType } from '../../../../types';
|
import { GitCommitWithBranch, OutletContextType } from '../../../../types';
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
import { useGQLClient } from '../../../../context/GQLClientContext';
|
||||||
import { Button, Heading, Avatar, Tag } from 'components/shared';
|
import { Button } from 'components/shared/Button';
|
||||||
|
import { Heading } from 'components/shared/Heading';
|
||||||
|
import { Avatar } from 'components/shared/Avatar';
|
||||||
import { getInitials } from 'utils/geInitials';
|
import { getInitials } from 'utils/geInitials';
|
||||||
import {
|
import {
|
||||||
BranchStrokeIcon,
|
BranchStrokeIcon,
|
||||||
@@ -15,12 +18,12 @@ import {
|
|||||||
GithubStrokeIcon,
|
GithubStrokeIcon,
|
||||||
GlobeIcon,
|
GlobeIcon,
|
||||||
LinkIcon,
|
LinkIcon,
|
||||||
CalendarDaysIcon,
|
|
||||||
} from 'components/shared/CustomIcon';
|
} from 'components/shared/CustomIcon';
|
||||||
|
import { Tag } from 'components/shared/Tag';
|
||||||
import { Activity } from 'components/projects/project/overview/Activity';
|
import { Activity } from 'components/projects/project/overview/Activity';
|
||||||
import { OverviewInfo } from 'components/projects/project/overview/OverviewInfo';
|
import { OverviewInfo } from 'components/projects/project/overview/OverviewInfo';
|
||||||
|
import { CalendarDaysIcon } from 'components/shared/CustomIcon/CalendarDaysIcon';
|
||||||
import { relativeTimeMs } from 'utils/time';
|
import { relativeTimeMs } from 'utils/time';
|
||||||
import { Domain, DomainStatus } from 'gql-client';
|
|
||||||
|
|
||||||
const COMMITS_PER_PAGE = 4;
|
const COMMITS_PER_PAGE = 4;
|
||||||
|
|
||||||
@@ -128,12 +131,9 @@ const OverviewTabPanel = () => {
|
|||||||
<Heading className="text-lg leading-6 font-medium truncate">
|
<Heading className="text-lg leading-6 font-medium truncate">
|
||||||
{project.name}
|
{project.name}
|
||||||
</Heading>
|
</Heading>
|
||||||
<a
|
<p className="text-sm text-elements-low-em tracking-tight truncate">
|
||||||
href={`https://${project.subDomain}`}
|
|
||||||
className="text-sm text-elements-low-em tracking-tight truncate"
|
|
||||||
>
|
|
||||||
{project.subDomain}
|
{project.subDomain}
|
||||||
</a>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<OverviewInfo label="Domain" icon={<GlobeIcon />}>
|
<OverviewInfo label="Domain" icon={<GlobeIcon />}>
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useFieldArray, useForm } from 'react-hook-form';
|
import { useFieldArray, useForm } from 'react-hook-form';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { Environment, EnvironmentVariable } from 'gql-client';
|
||||||
|
|
||||||
import { Collapse } from '@snowballtools/material-tailwind-react-fork';
|
import { Collapse } from '@snowballtools/material-tailwind-react-fork';
|
||||||
|
|
||||||
import AddEnvironmentVariableRow from 'components/projects/project/settings/AddEnvironmentVariableRow';
|
import AddEnvironmentVariableRow from 'components/projects/project/settings/AddEnvironmentVariableRow';
|
||||||
import DisplayEnvironmentVariables from 'components/projects/project/settings/DisplayEnvironmentVariables';
|
import DisplayEnvironmentVariables from 'components/projects/project/settings/DisplayEnvironmentVariables';
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
import { useGQLClient } from '../../../../../context/GQLClientContext';
|
||||||
import { EnvironmentVariablesFormValues } from '../../../../../types';
|
import { EnvironmentVariablesFormValues } from '../../../../../types';
|
||||||
import HorizontalLine from 'components/HorizontalLine';
|
import HorizontalLine from 'components/HorizontalLine';
|
||||||
import { Heading } from 'components/shared/Heading';
|
import { Heading } from 'components/shared/Heading';
|
||||||
@@ -15,13 +17,10 @@ import { Checkbox } from 'components/shared/Checkbox';
|
|||||||
import { PlusIcon } from 'components/shared/CustomIcon';
|
import { PlusIcon } from 'components/shared/CustomIcon';
|
||||||
import { InlineNotification } from 'components/shared/InlineNotification';
|
import { InlineNotification } from 'components/shared/InlineNotification';
|
||||||
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
||||||
import { useToast } from 'components/shared/Toast';
|
|
||||||
import { Environment, EnvironmentVariable } from 'gql-client';
|
|
||||||
|
|
||||||
export const EnvironmentVariablesTabPanel = () => {
|
export const EnvironmentVariablesTabPanel = () => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const client = useGQLClient();
|
const client = useGQLClient();
|
||||||
const { toast, dismiss } = useToast();
|
|
||||||
|
|
||||||
const [environmentVariables, setEnvironmentVariables] = useState<
|
const [environmentVariables, setEnvironmentVariables] = useState<
|
||||||
EnvironmentVariable[]
|
EnvironmentVariable[]
|
||||||
@@ -119,25 +118,13 @@ export const EnvironmentVariablesTabPanel = () => {
|
|||||||
|
|
||||||
fetchEnvironmentVariables(id);
|
fetchEnvironmentVariables(id);
|
||||||
|
|
||||||
toast({
|
toast.success(
|
||||||
id:
|
createFormData.variables.length > 1
|
||||||
createFormData.variables.length > 1
|
? `${createFormData.variables.length} variables added`
|
||||||
? 'env_variable_added'
|
: `Variable added`,
|
||||||
: 'env_variables_added',
|
);
|
||||||
title:
|
|
||||||
createFormData.variables.length > 1
|
|
||||||
? `${createFormData.variables.length} variables added`
|
|
||||||
: `Variable added`,
|
|
||||||
variant: 'success',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
toast({
|
toast.error('Environment variables not added');
|
||||||
id: 'env_variables_not_added',
|
|
||||||
title: 'Environment variables not added',
|
|
||||||
variant: 'error',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[id, client],
|
[id, client],
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
import toast from 'react-hot-toast';
|
||||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { useGQLClient } from 'context/GQLClientContext';
|
import { useGQLClient } from '../../../../../../../context/GQLClientContext';
|
||||||
import { Table } from 'components/shared/Table';
|
import { Table } from 'components/shared/Table';
|
||||||
import { Button } from 'components/shared/Button';
|
import { Button } from 'components/shared/Button';
|
||||||
import { InlineNotification } from 'components/shared/InlineNotification';
|
import { InlineNotification } from 'components/shared/InlineNotification';
|
||||||
import { ArrowRightCircleIcon } from 'components/shared/CustomIcon';
|
import { ArrowRightCircleIcon } from 'components/shared/CustomIcon';
|
||||||
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
import { ProjectSettingContainer } from 'components/projects/project/settings/ProjectSettingContainer';
|
||||||
import { useToast } from 'components/shared/Toast';
|
|
||||||
|
|
||||||
const Config = () => {
|
const Config = () => {
|
||||||
const { id, orgSlug } = useParams();
|
const { id, orgSlug } = useParams();
|
||||||
@@ -14,26 +14,15 @@ const Config = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const primaryDomainName = searchParams.get('name');
|
const primaryDomainName = searchParams.get('name');
|
||||||
const { toast, dismiss } = useToast();
|
|
||||||
|
|
||||||
const handleSubmitDomain = async () => {
|
const handleSubmitDomain = async () => {
|
||||||
if (primaryDomainName === null) {
|
if (primaryDomainName === null) {
|
||||||
toast({
|
toast.error('Cannot resolve domain name');
|
||||||
id: 'unresolvable_domain_name',
|
|
||||||
title: 'Cannot resolve domain name',
|
|
||||||
variant: 'error',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id === undefined) {
|
if (id === undefined) {
|
||||||
toast({
|
toast.error('Cannot find project');
|
||||||
id: 'domain_cannot_find_project',
|
|
||||||
title: 'Cannot find project',
|
|
||||||
variant: 'error',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,20 +31,10 @@ const Config = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (isAdded) {
|
if (isAdded) {
|
||||||
toast({
|
toast.success('Domain added successfully');
|
||||||
id: 'domain_added_successfully',
|
|
||||||
title: 'Domain added successfully',
|
|
||||||
variant: 'success',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
navigate(`/${orgSlug}/projects/${id}/settings/domains`);
|
navigate(`/${orgSlug}/projects/${id}/settings/domains`);
|
||||||
} else {
|
} else {
|
||||||
toast({
|
toast.error('Error adding domain');
|
||||||
id: 'generic_error_adding_domain',
|
|
||||||
title: 'Error adding domaint',
|
|
||||||
variant: 'error',
|
|
||||||
onDismiss: dismiss,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,9 @@ const meta: Meta<typeof ChevronDownSmallIcon> = {
|
|||||||
title: 'Icons/ChevronDownSmallIcon',
|
title: 'Icons/ChevronDownSmallIcon',
|
||||||
component: ChevronDownSmallIcon,
|
component: ChevronDownSmallIcon,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
argTypes: {
|
args: {
|
||||||
size: {
|
size: 'string | number' as unknown as any,
|
||||||
control: 'text',
|
name: 'string',
|
||||||
},
|
|
||||||
name: {
|
|
||||||
control: 'text',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,9 @@ const meta: Meta<typeof ChevronRight> = {
|
|||||||
title: 'Icons/ChevronRight',
|
title: 'Icons/ChevronRight',
|
||||||
component: ChevronRight,
|
component: ChevronRight,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
argTypes: {
|
args: {
|
||||||
size: {
|
size: 'string | number' as unknown as any,
|
||||||
control: 'text',
|
name: 'string',
|
||||||
},
|
|
||||||
name: {
|
|
||||||
control: 'text',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,9 @@ const meta: Meta<typeof ChevronUpDown> = {
|
|||||||
title: 'Icons/ChevronUpDown',
|
title: 'Icons/ChevronUpDown',
|
||||||
component: ChevronUpDown,
|
component: ChevronUpDown,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
argTypes: {
|
args: {
|
||||||
size: {
|
size: 'string | number' as unknown as any,
|
||||||
control: 'text',
|
name: 'string',
|
||||||
},
|
|
||||||
name: {
|
|
||||||
control: 'text',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,16 +3,12 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
import { ChevronUpSmallIcon } from 'components/shared/CustomIcon';
|
import { ChevronUpSmallIcon } from 'components/shared/CustomIcon';
|
||||||
|
|
||||||
const meta: Meta<typeof ChevronUpSmallIcon> = {
|
const meta: Meta<typeof ChevronUpSmallIcon> = {
|
||||||
title: 'Icons/ChevronUpSmallIcon',
|
title: 'Components/ChevronUpSmallIcon',
|
||||||
component: ChevronUpSmallIcon,
|
component: ChevronUpSmallIcon,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
argTypes: {
|
args: {
|
||||||
size: {
|
size: 'string | number' as unknown as any,
|
||||||
control: 'text',
|
name: 'string',
|
||||||
},
|
|
||||||
name: {
|
|
||||||
control: 'text',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
import { CollaboratorsIcon } from 'components/shared/CustomIcon';
|
import { CollaboratorsIcon } from 'components/shared/CustomIcon';
|
||||||
|
|
||||||
const meta: Meta<typeof CollaboratorsIcon> = {
|
const meta: Meta<typeof CollaboratorsIcon> = {
|
||||||
title: 'Icons/CollaboratorsIcon',
|
title: 'Components/CollaboratorsIcon',
|
||||||
component: CollaboratorsIcon,
|
component: CollaboratorsIcon,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
argTypes: {
|
argTypes: {
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import { StoryObj, Meta } from '@storybook/react';
|
|
||||||
|
|
||||||
import { ProjectSearchBar } from 'components/projects/ProjectSearchBar';
|
|
||||||
|
|
||||||
const meta: Meta<typeof ProjectSearchBar> = {
|
|
||||||
title: 'Components/ProjectSearchBar',
|
|
||||||
component: ProjectSearchBar,
|
|
||||||
tags: ['autodocs'],
|
|
||||||
argTypes: {
|
|
||||||
onChange: {
|
|
||||||
action: 'change',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
|
|
||||||
type Story = StoryObj<typeof ProjectSearchBar>;
|
|
||||||
|
|
||||||
export const Default: Story = {};
|
|
||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
DomainStatus,
|
DomainStatus,
|
||||||
Domain,
|
Domain,
|
||||||
Environment,
|
Environment,
|
||||||
Permission,
|
|
||||||
} from 'gql-client';
|
} from 'gql-client';
|
||||||
|
|
||||||
export const user: User = {
|
export const user: User = {
|
||||||
@@ -45,7 +44,7 @@ export const organization: Organization = {
|
|||||||
export const member: ProjectMember = {
|
export const member: ProjectMember = {
|
||||||
id: '1',
|
id: '1',
|
||||||
member: user,
|
member: user,
|
||||||
permissions: [Permission.Edit],
|
permissions: [],
|
||||||
isPending: false,
|
isPending: false,
|
||||||
createdAt: '2021-08-01T00:00:00.000Z',
|
createdAt: '2021-08-01T00:00:00.000Z',
|
||||||
updatedAt: '2021-08-01T00:00:00.000Z',
|
updatedAt: '2021-08-01T00:00:00.000Z',
|
||||||
@@ -71,7 +70,7 @@ export const environmentVariable1: EnvironmentVariable = {
|
|||||||
|
|
||||||
export const domain0: Domain = {
|
export const domain0: Domain = {
|
||||||
id: '1',
|
id: '1',
|
||||||
name: 'domain.com',
|
name: 'Domain',
|
||||||
createdAt: '2021-08-01T00:00:00.000Z',
|
createdAt: '2021-08-01T00:00:00.000Z',
|
||||||
updatedAt: '2021-08-01T00:00:00.000Z',
|
updatedAt: '2021-08-01T00:00:00.000Z',
|
||||||
branch: 'Branch',
|
branch: 'Branch',
|
||||||
@@ -79,16 +78,6 @@ export const domain0: Domain = {
|
|||||||
redirectTo: null,
|
redirectTo: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const domain1: Domain = {
|
|
||||||
id: '2',
|
|
||||||
name: 'www.domain.com',
|
|
||||||
createdAt: '2021-08-01T00:00:00.000Z',
|
|
||||||
updatedAt: '2021-08-01T00:00:00.000Z',
|
|
||||||
branch: 'Branch',
|
|
||||||
status: DomainStatus.Live,
|
|
||||||
redirectTo: domain0,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deployment0: Deployment = {
|
export const deployment0: Deployment = {
|
||||||
id: '1',
|
id: '1',
|
||||||
url: 'https://deployment.com',
|
url: 'https://deployment.com',
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
import { StoryObj, Meta } from '@storybook/react';
|
|
||||||
|
|
||||||
import DomainCard from 'components/projects/project/settings/DomainCard';
|
|
||||||
import { domain0, domain1, project } from '../../MockStoriesData';
|
|
||||||
|
|
||||||
const meta: Meta<typeof DomainCard> = {
|
|
||||||
title: 'Project/Settings/DomainCard',
|
|
||||||
component: DomainCard,
|
|
||||||
tags: ['autodocs'],
|
|
||||||
argTypes: {
|
|
||||||
domains: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
domain: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
branches: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
project: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
onUpdate: {
|
|
||||||
action: 'update',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
|
|
||||||
type Story = StoryObj<typeof DomainCard>;
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
args: {
|
|
||||||
domains: [domain0, domain1],
|
|
||||||
domain: domain0,
|
|
||||||
branches: ['main'],
|
|
||||||
project: project,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
import { StoryObj, Meta } from '@storybook/react';
|
|
||||||
|
|
||||||
import EditDomainDialog from 'components/projects/project/settings/EditDomainDialog';
|
|
||||||
|
|
||||||
const meta: Meta<typeof EditDomainDialog> = {
|
|
||||||
title: 'Components/EditDomainDialog',
|
|
||||||
component: EditDomainDialog,
|
|
||||||
tags: ['autodocs'],
|
|
||||||
argTypes: {
|
|
||||||
domains: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
open: {
|
|
||||||
control: {
|
|
||||||
type: 'boolean',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
handleOpen: {
|
|
||||||
action: 'open',
|
|
||||||
},
|
|
||||||
domain: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
branches: {
|
|
||||||
control: {
|
|
||||||
type: 'object',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
onUpdate: {
|
|
||||||
action: 'update',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
|
|
||||||
type Story = StoryObj<typeof EditDomainDialog>;
|
|
||||||
|
|
||||||
export const Default: Story = {};
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
|
||||||
|
|
||||||
import WebhookCard from 'components/projects/project/settings/WebhookCard';
|
|
||||||
|
|
||||||
const meta: Meta<typeof WebhookCard> = {
|
|
||||||
title: 'Project/Settings/WebhookCard',
|
|
||||||
component: WebhookCard,
|
|
||||||
tags: ['autodocs'],
|
|
||||||
argTypes: {
|
|
||||||
webhookUrl: {
|
|
||||||
control: {
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
onDelete: {
|
|
||||||
action: 'delete',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
|
|
||||||
type Story = StoryObj<typeof WebhookCard>;
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
args: {
|
|
||||||
webhookUrl: 'https://api.retool.com',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
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()}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
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 Bugsnag from '@bugsnag/js';
|
||||||
import BugsnagPluginReact from '@bugsnag/plugin-react';
|
import BugsnagPluginReact from '@bugsnag/plugin-react';
|
||||||
import BugsnagPerformance from '@bugsnag/browser-performance';
|
import BugsnagPerformance from '@bugsnag/browser-performance';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
import { VITE_BUGSNAG_API_KEY } from './constants';
|
const bugsnagApiKey = import.meta.env.VITE_BUGSNAG_API_KEY;
|
||||||
|
|
||||||
if (VITE_BUGSNAG_API_KEY) {
|
if (bugsnagApiKey) {
|
||||||
Bugsnag.start({
|
Bugsnag.start({
|
||||||
apiKey: VITE_BUGSNAG_API_KEY,
|
apiKey: bugsnagApiKey,
|
||||||
plugins: [new BugsnagPluginReact()],
|
plugins: [new BugsnagPluginReact()],
|
||||||
});
|
});
|
||||||
BugsnagPerformance.start({ apiKey: VITE_BUGSNAG_API_KEY });
|
BugsnagPerformance.start({ apiKey: bugsnagApiKey });
|
||||||
}
|
}
|
||||||
|
|
||||||
export const errorLoggingEnabled = !!VITE_BUGSNAG_API_KEY;
|
export const errorLoggingEnabled = !!bugsnagApiKey;
|
||||||
|
|
||||||
export const LogErrorBoundary = VITE_BUGSNAG_API_KEY
|
export const LogErrorBoundary = bugsnagApiKey
|
||||||
? Bugsnag.getPlugin('react')!.createErrorBoundary(React)
|
? Bugsnag.getPlugin('react')!.createErrorBoundary(React)
|
||||||
: ({ children }: any) => children;
|
: ({ children }: any) => children;
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ export function logError(error: Error) {
|
|||||||
}
|
}
|
||||||
console.error(...errors);
|
console.error(...errors);
|
||||||
|
|
||||||
if (VITE_BUGSNAG_API_KEY) {
|
if (import.meta.env.VITE_BUGSNAG_API_KEY) {
|
||||||
Bugsnag.notify(error);
|
Bugsnag.notify(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import { SiweMessage } from 'siwe';
|
|||||||
import { PKPEthersWallet } from '@lit-protocol/pkp-ethers';
|
import { PKPEthersWallet } from '@lit-protocol/pkp-ethers';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
import { baseUrl } from './constants';
|
|
||||||
|
|
||||||
const domain = window.location.host;
|
const domain = window.location.host;
|
||||||
const origin = window.location.origin;
|
const origin = window.location.origin;
|
||||||
|
|
||||||
@@ -19,7 +17,7 @@ export async function signInWithEthereum(
|
|||||||
);
|
);
|
||||||
const signature = await wallet.signMessage(message);
|
const signature = await wallet.signMessage(message);
|
||||||
|
|
||||||
const res = await fetch(`${baseUrl}/auth/validate`, {
|
const res = await fetch(`${import.meta.env.VITE_SERVER_URL}/auth/validate`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { TurnkeyClient, getWebAuthnAttestation } from '@turnkey/http';
|
import { TurnkeyClient, getWebAuthnAttestation } from '@turnkey/http';
|
||||||
import { WebauthnStamper } from '@turnkey/webauthn-stamper';
|
import { WebauthnStamper } from '@turnkey/webauthn-stamper';
|
||||||
|
|
||||||
import { baseUrl, PASSKEY_WALLET_RPID, TURNKEY_BASE_URL } from './constants';
|
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!;
|
||||||
|
|
||||||
// All algorithms can be found here: https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
// All algorithms can be found here: https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
||||||
// We only support ES256, which is listed here
|
// We only support ES256, which is listed here
|
||||||
|
|||||||
@@ -5,17 +5,16 @@ import {
|
|||||||
LitGoogleAuth,
|
LitGoogleAuth,
|
||||||
LitPasskeyAuth,
|
LitPasskeyAuth,
|
||||||
} from '@snowballtools/auth-lit';
|
} from '@snowballtools/auth-lit';
|
||||||
import { VITE_LIT_RELAY_API_KEY } from './constants';
|
|
||||||
|
|
||||||
export const snowball = Snowball.withAuth({
|
export const snowball = Snowball.withAuth({
|
||||||
google: LitGoogleAuth.configure({
|
google: LitGoogleAuth.configure({
|
||||||
litRelayApiKey: VITE_LIT_RELAY_API_KEY!,
|
litRelayApiKey: import.meta.env.VITE_LIT_RELAY_API_KEY!,
|
||||||
}),
|
}),
|
||||||
// apple: LitAppleAuth.configure({
|
// apple: LitAppleAuth.configure({
|
||||||
// litRelayApiKey: VITE_LIT_RELAY_API_KEY!,
|
// litRelayApiKey: import.meta.env.VITE_LIT_RELAY_API_KEY!,
|
||||||
// }),
|
// }),
|
||||||
passkey: LitPasskeyAuth.configure({
|
passkey: LitPasskeyAuth.configure({
|
||||||
litRelayApiKey: VITE_LIT_RELAY_API_KEY!,
|
litRelayApiKey: import.meta.env.VITE_LIT_RELAY_API_KEY!,
|
||||||
}),
|
}),
|
||||||
}).create({
|
}).create({
|
||||||
initialChain: SnowballChain.sepolia,
|
initialChain: SnowballChain.sepolia,
|
||||||
|
|||||||
Vendored
+1
-12
@@ -185,9 +185,6 @@ type RemoveEnvironmentVariableResponse = {
|
|||||||
type UpdateDeploymentToProdResponse = {
|
type UpdateDeploymentToProdResponse = {
|
||||||
updateDeploymentToProd: boolean;
|
updateDeploymentToProd: boolean;
|
||||||
};
|
};
|
||||||
type AddProjectFromTemplateResponse = {
|
|
||||||
addProjectFromTemplate: Project;
|
|
||||||
};
|
|
||||||
type AddProjectResponse = {
|
type AddProjectResponse = {
|
||||||
addProject: Project;
|
addProject: Project;
|
||||||
};
|
};
|
||||||
@@ -203,13 +200,6 @@ type DeleteProjectResponse = {
|
|||||||
type DeleteDomainResponse = {
|
type DeleteDomainResponse = {
|
||||||
deleteDomain: boolean;
|
deleteDomain: boolean;
|
||||||
};
|
};
|
||||||
type AddProjectFromTemplateInput = {
|
|
||||||
templateOwner: string;
|
|
||||||
templateRepo: string;
|
|
||||||
owner: string;
|
|
||||||
name: string;
|
|
||||||
isPrivate: boolean;
|
|
||||||
};
|
|
||||||
type AddProjectInput = {
|
type AddProjectInput = {
|
||||||
name: string;
|
name: string;
|
||||||
repository: string;
|
repository: string;
|
||||||
@@ -277,7 +267,6 @@ declare class GQLClient {
|
|||||||
updateEnvironmentVariable(environmentVariableId: string, data: UpdateEnvironmentVariableInput): Promise<UpdateEnvironmentVariableResponse>;
|
updateEnvironmentVariable(environmentVariableId: string, data: UpdateEnvironmentVariableInput): Promise<UpdateEnvironmentVariableResponse>;
|
||||||
removeEnvironmentVariable(environmentVariableId: string): Promise<RemoveEnvironmentVariableResponse>;
|
removeEnvironmentVariable(environmentVariableId: string): Promise<RemoveEnvironmentVariableResponse>;
|
||||||
updateDeploymentToProd(deploymentId: string): Promise<UpdateDeploymentToProdResponse>;
|
updateDeploymentToProd(deploymentId: string): Promise<UpdateDeploymentToProdResponse>;
|
||||||
addProjectFromTemplate(organizationSlug: string, data: AddProjectFromTemplateInput): Promise<AddProjectFromTemplateResponse>;
|
|
||||||
addProject(organizationSlug: string, data: AddProjectInput): Promise<AddProjectResponse>;
|
addProject(organizationSlug: string, data: AddProjectInput): Promise<AddProjectResponse>;
|
||||||
updateProject(projectId: string, data: UpdateProjectInput): Promise<UpdateProjectResponse>;
|
updateProject(projectId: string, data: UpdateProjectInput): Promise<UpdateProjectResponse>;
|
||||||
updateDomain(domainId: string, data: UpdateDomainInput): Promise<UpdateDomainResponse>;
|
updateDomain(domainId: string, data: UpdateDomainInput): Promise<UpdateDomainResponse>;
|
||||||
@@ -292,4 +281,4 @@ declare class GQLClient {
|
|||||||
unauthenticateGithub(): Promise<UnauthenticateGitHubResponse>;
|
unauthenticateGithub(): Promise<UnauthenticateGitHubResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 };
|
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 };
|
||||||
|
|||||||
Vendored
+1
-12
@@ -185,9 +185,6 @@ type RemoveEnvironmentVariableResponse = {
|
|||||||
type UpdateDeploymentToProdResponse = {
|
type UpdateDeploymentToProdResponse = {
|
||||||
updateDeploymentToProd: boolean;
|
updateDeploymentToProd: boolean;
|
||||||
};
|
};
|
||||||
type AddProjectFromTemplateResponse = {
|
|
||||||
addProjectFromTemplate: Project;
|
|
||||||
};
|
|
||||||
type AddProjectResponse = {
|
type AddProjectResponse = {
|
||||||
addProject: Project;
|
addProject: Project;
|
||||||
};
|
};
|
||||||
@@ -203,13 +200,6 @@ type DeleteProjectResponse = {
|
|||||||
type DeleteDomainResponse = {
|
type DeleteDomainResponse = {
|
||||||
deleteDomain: boolean;
|
deleteDomain: boolean;
|
||||||
};
|
};
|
||||||
type AddProjectFromTemplateInput = {
|
|
||||||
templateOwner: string;
|
|
||||||
templateRepo: string;
|
|
||||||
owner: string;
|
|
||||||
name: string;
|
|
||||||
isPrivate: boolean;
|
|
||||||
};
|
|
||||||
type AddProjectInput = {
|
type AddProjectInput = {
|
||||||
name: string;
|
name: string;
|
||||||
repository: string;
|
repository: string;
|
||||||
@@ -277,7 +267,6 @@ declare class GQLClient {
|
|||||||
updateEnvironmentVariable(environmentVariableId: string, data: UpdateEnvironmentVariableInput): Promise<UpdateEnvironmentVariableResponse>;
|
updateEnvironmentVariable(environmentVariableId: string, data: UpdateEnvironmentVariableInput): Promise<UpdateEnvironmentVariableResponse>;
|
||||||
removeEnvironmentVariable(environmentVariableId: string): Promise<RemoveEnvironmentVariableResponse>;
|
removeEnvironmentVariable(environmentVariableId: string): Promise<RemoveEnvironmentVariableResponse>;
|
||||||
updateDeploymentToProd(deploymentId: string): Promise<UpdateDeploymentToProdResponse>;
|
updateDeploymentToProd(deploymentId: string): Promise<UpdateDeploymentToProdResponse>;
|
||||||
addProjectFromTemplate(organizationSlug: string, data: AddProjectFromTemplateInput): Promise<AddProjectFromTemplateResponse>;
|
|
||||||
addProject(organizationSlug: string, data: AddProjectInput): Promise<AddProjectResponse>;
|
addProject(organizationSlug: string, data: AddProjectInput): Promise<AddProjectResponse>;
|
||||||
updateProject(projectId: string, data: UpdateProjectInput): Promise<UpdateProjectResponse>;
|
updateProject(projectId: string, data: UpdateProjectInput): Promise<UpdateProjectResponse>;
|
||||||
updateDomain(domainId: string, data: UpdateDomainInput): Promise<UpdateDomainResponse>;
|
updateDomain(domainId: string, data: UpdateDomainInput): Promise<UpdateDomainResponse>;
|
||||||
@@ -292,4 +281,4 @@ declare class GQLClient {
|
|||||||
unauthenticateGithub(): Promise<UnauthenticateGitHubResponse>;
|
unauthenticateGithub(): Promise<UnauthenticateGitHubResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 };
|
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 };
|
||||||
|
|||||||
Vendored
+56
-87
@@ -267,112 +267,93 @@ query ($projectId: String!, $filter: FilterDomainsInput) {
|
|||||||
// src/mutations.ts
|
// src/mutations.ts
|
||||||
var import_client2 = require("@apollo/client");
|
var import_client2 = require("@apollo/client");
|
||||||
var removeProjectMember = import_client2.gql`
|
var removeProjectMember = import_client2.gql`
|
||||||
mutation ($projectMemberId: String!) {
|
mutation ($projectMemberId: String!) {
|
||||||
removeProjectMember(projectMemberId: $projectMemberId)
|
removeProjectMember(projectMemberId: $projectMemberId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var updateProjectMember = import_client2.gql`
|
var updateProjectMember = import_client2.gql`
|
||||||
mutation ($projectMemberId: String!, $data: UpdateProjectMemberInput) {
|
mutation ($projectMemberId: String!, $data: UpdateProjectMemberInput) {
|
||||||
updateProjectMember(projectMemberId: $projectMemberId, data: $data)
|
updateProjectMember(projectMemberId: $projectMemberId, data: $data)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var addProjectMember = import_client2.gql`
|
var addProjectMember = import_client2.gql`
|
||||||
mutation ($projectId: String!, $data: AddProjectMemberInput) {
|
mutation ($projectId: String!, $data: AddProjectMemberInput) {
|
||||||
addProjectMember(projectId: $projectId, data: $data)
|
addProjectMember(projectId: $projectId, data: $data)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var addEnvironmentVariables = import_client2.gql`
|
var addEnvironmentVariables = import_client2.gql`
|
||||||
mutation ($projectId: String!, $data: [AddEnvironmentVariableInput!]) {
|
mutation ($projectId: String!, $data: [AddEnvironmentVariableInput!]) {
|
||||||
addEnvironmentVariables(projectId: $projectId, data: $data)
|
addEnvironmentVariables(projectId: $projectId, data: $data)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var updateEnvironmentVariable = import_client2.gql`
|
var updateEnvironmentVariable = import_client2.gql`
|
||||||
mutation (
|
mutation ($environmentVariableId: String!, $data: UpdateEnvironmentVariableInput!) {
|
||||||
$environmentVariableId: String!
|
updateEnvironmentVariable(environmentVariableId: $environmentVariableId, data: $data)
|
||||||
$data: UpdateEnvironmentVariableInput!
|
}
|
||||||
) {
|
|
||||||
updateEnvironmentVariable(
|
|
||||||
environmentVariableId: $environmentVariableId
|
|
||||||
data: $data
|
|
||||||
)
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
var removeEnvironmentVariable = import_client2.gql`
|
var removeEnvironmentVariable = import_client2.gql`
|
||||||
mutation ($environmentVariableId: String!) {
|
mutation ($environmentVariableId: String!) {
|
||||||
removeEnvironmentVariable(environmentVariableId: $environmentVariableId)
|
removeEnvironmentVariable(environmentVariableId: $environmentVariableId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var updateDeploymentToProd = import_client2.gql`
|
var updateDeploymentToProd = import_client2.gql`
|
||||||
mutation ($deploymentId: String!) {
|
mutation ($deploymentId: String!) {
|
||||||
updateDeploymentToProd(deploymentId: $deploymentId)
|
updateDeploymentToProd(deploymentId: $deploymentId)
|
||||||
}
|
}
|
||||||
`;
|
|
||||||
var addProjectFromTemplate = import_client2.gql`
|
|
||||||
mutation ($organizationSlug: String!, $data: AddProjectFromTemplateInput) {
|
|
||||||
addProjectFromTemplate(organizationSlug: $organizationSlug, data: $data) {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
var addProject = import_client2.gql`
|
var addProject = import_client2.gql`
|
||||||
mutation ($organizationSlug: String!, $data: AddProjectInput) {
|
mutation ($organizationSlug: String!, $data: AddProjectInput) {
|
||||||
addProject(organizationSlug: $organizationSlug, data: $data) {
|
addProject(organizationSlug: $organizationSlug, data: $data) {
|
||||||
id
|
id
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`;
|
}`;
|
||||||
var updateProjectMutation = import_client2.gql`
|
var updateProjectMutation = import_client2.gql`
|
||||||
mutation ($projectId: String!, $data: UpdateProjectInput) {
|
mutation ($projectId: String!, $data: UpdateProjectInput) {
|
||||||
updateProject(projectId: $projectId, data: $data)
|
updateProject(projectId: $projectId, data: $data)
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
var updateDomainMutation = import_client2.gql`
|
var updateDomainMutation = import_client2.gql`
|
||||||
mutation ($domainId: String!, $data: UpdateDomainInput!) {
|
mutation ($domainId: String!, $data: UpdateDomainInput!) {
|
||||||
updateDomain(domainId: $domainId, data: $data)
|
updateDomain(domainId: $domainId, data: $data)
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
var redeployToProd = import_client2.gql`
|
var redeployToProd = import_client2.gql`
|
||||||
mutation ($deploymentId: String!) {
|
mutation ($deploymentId: String!) {
|
||||||
redeployToProd(deploymentId: $deploymentId)
|
redeployToProd(deploymentId: $deploymentId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var deleteProject = import_client2.gql`
|
var deleteProject = import_client2.gql`
|
||||||
mutation ($projectId: String!) {
|
mutation ($projectId: String!) {
|
||||||
deleteProject(projectId: $projectId)
|
deleteProject(projectId: $projectId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var deleteDomain = import_client2.gql`
|
var deleteDomain = import_client2.gql`
|
||||||
mutation ($domainId: String!) {
|
mutation ($domainId: String!) {
|
||||||
deleteDomain(domainId: $domainId)
|
deleteDomain(domainId: $domainId)
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
var rollbackDeployment = import_client2.gql`
|
var rollbackDeployment = import_client2.gql`
|
||||||
mutation ($projectId: String!, $deploymentId: String!) {
|
mutation ($projectId: String! ,$deploymentId: String!) {
|
||||||
rollbackDeployment(projectId: $projectId, deploymentId: $deploymentId)
|
rollbackDeployment(projectId: $projectId, deploymentId: $deploymentId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var deleteDeployment = import_client2.gql`
|
var deleteDeployment = import_client2.gql`
|
||||||
mutation ($deploymentId: String!) {
|
mutation ($deploymentId: String!) {
|
||||||
deleteDeployment(deploymentId: $deploymentId)
|
deleteDeployment(deploymentId: $deploymentId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var addDomain = import_client2.gql`
|
var addDomain = import_client2.gql`
|
||||||
mutation ($projectId: String!, $data: AddDomainInput!) {
|
mutation ($projectId: String!, $data: AddDomainInput!) {
|
||||||
addDomain(projectId: $projectId, data: $data)
|
addDomain(projectId: $projectId, data: $data)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var authenticateGitHub = import_client2.gql`
|
var authenticateGitHub = import_client2.gql`
|
||||||
mutation ($code: String!) {
|
mutation ($code: String!) {
|
||||||
authenticateGitHub(code: $code) {
|
authenticateGitHub(code: $code) {
|
||||||
token
|
token
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`;
|
}`;
|
||||||
var unauthenticateGitHub = import_client2.gql`
|
var unauthenticateGitHub = import_client2.gql`
|
||||||
mutation {
|
mutation {
|
||||||
unauthenticateGitHub
|
unauthenticateGitHub
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
|
|
||||||
// src/client.ts
|
// src/client.ts
|
||||||
var defaultOptions = {
|
var defaultOptions = {
|
||||||
@@ -557,18 +538,6 @@ var GQLClient = class {
|
|||||||
return data;
|
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) {
|
addProject(organizationSlug, data) {
|
||||||
return __async(this, null, function* () {
|
return __async(this, null, function* () {
|
||||||
const result = yield this.client.mutate({
|
const result = yield this.client.mutate({
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+56
-87
@@ -240,112 +240,93 @@ query ($projectId: String!, $filter: FilterDomainsInput) {
|
|||||||
// src/mutations.ts
|
// src/mutations.ts
|
||||||
import { gql as gql2 } from "@apollo/client";
|
import { gql as gql2 } from "@apollo/client";
|
||||||
var removeProjectMember = gql2`
|
var removeProjectMember = gql2`
|
||||||
mutation ($projectMemberId: String!) {
|
mutation ($projectMemberId: String!) {
|
||||||
removeProjectMember(projectMemberId: $projectMemberId)
|
removeProjectMember(projectMemberId: $projectMemberId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var updateProjectMember = gql2`
|
var updateProjectMember = gql2`
|
||||||
mutation ($projectMemberId: String!, $data: UpdateProjectMemberInput) {
|
mutation ($projectMemberId: String!, $data: UpdateProjectMemberInput) {
|
||||||
updateProjectMember(projectMemberId: $projectMemberId, data: $data)
|
updateProjectMember(projectMemberId: $projectMemberId, data: $data)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var addProjectMember = gql2`
|
var addProjectMember = gql2`
|
||||||
mutation ($projectId: String!, $data: AddProjectMemberInput) {
|
mutation ($projectId: String!, $data: AddProjectMemberInput) {
|
||||||
addProjectMember(projectId: $projectId, data: $data)
|
addProjectMember(projectId: $projectId, data: $data)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var addEnvironmentVariables = gql2`
|
var addEnvironmentVariables = gql2`
|
||||||
mutation ($projectId: String!, $data: [AddEnvironmentVariableInput!]) {
|
mutation ($projectId: String!, $data: [AddEnvironmentVariableInput!]) {
|
||||||
addEnvironmentVariables(projectId: $projectId, data: $data)
|
addEnvironmentVariables(projectId: $projectId, data: $data)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var updateEnvironmentVariable = gql2`
|
var updateEnvironmentVariable = gql2`
|
||||||
mutation (
|
mutation ($environmentVariableId: String!, $data: UpdateEnvironmentVariableInput!) {
|
||||||
$environmentVariableId: String!
|
updateEnvironmentVariable(environmentVariableId: $environmentVariableId, data: $data)
|
||||||
$data: UpdateEnvironmentVariableInput!
|
}
|
||||||
) {
|
|
||||||
updateEnvironmentVariable(
|
|
||||||
environmentVariableId: $environmentVariableId
|
|
||||||
data: $data
|
|
||||||
)
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
var removeEnvironmentVariable = gql2`
|
var removeEnvironmentVariable = gql2`
|
||||||
mutation ($environmentVariableId: String!) {
|
mutation ($environmentVariableId: String!) {
|
||||||
removeEnvironmentVariable(environmentVariableId: $environmentVariableId)
|
removeEnvironmentVariable(environmentVariableId: $environmentVariableId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var updateDeploymentToProd = gql2`
|
var updateDeploymentToProd = gql2`
|
||||||
mutation ($deploymentId: String!) {
|
mutation ($deploymentId: String!) {
|
||||||
updateDeploymentToProd(deploymentId: $deploymentId)
|
updateDeploymentToProd(deploymentId: $deploymentId)
|
||||||
}
|
}
|
||||||
`;
|
|
||||||
var addProjectFromTemplate = gql2`
|
|
||||||
mutation ($organizationSlug: String!, $data: AddProjectFromTemplateInput) {
|
|
||||||
addProjectFromTemplate(organizationSlug: $organizationSlug, data: $data) {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
var addProject = gql2`
|
var addProject = gql2`
|
||||||
mutation ($organizationSlug: String!, $data: AddProjectInput) {
|
mutation ($organizationSlug: String!, $data: AddProjectInput) {
|
||||||
addProject(organizationSlug: $organizationSlug, data: $data) {
|
addProject(organizationSlug: $organizationSlug, data: $data) {
|
||||||
id
|
id
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`;
|
}`;
|
||||||
var updateProjectMutation = gql2`
|
var updateProjectMutation = gql2`
|
||||||
mutation ($projectId: String!, $data: UpdateProjectInput) {
|
mutation ($projectId: String!, $data: UpdateProjectInput) {
|
||||||
updateProject(projectId: $projectId, data: $data)
|
updateProject(projectId: $projectId, data: $data)
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
var updateDomainMutation = gql2`
|
var updateDomainMutation = gql2`
|
||||||
mutation ($domainId: String!, $data: UpdateDomainInput!) {
|
mutation ($domainId: String!, $data: UpdateDomainInput!) {
|
||||||
updateDomain(domainId: $domainId, data: $data)
|
updateDomain(domainId: $domainId, data: $data)
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
var redeployToProd = gql2`
|
var redeployToProd = gql2`
|
||||||
mutation ($deploymentId: String!) {
|
mutation ($deploymentId: String!) {
|
||||||
redeployToProd(deploymentId: $deploymentId)
|
redeployToProd(deploymentId: $deploymentId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var deleteProject = gql2`
|
var deleteProject = gql2`
|
||||||
mutation ($projectId: String!) {
|
mutation ($projectId: String!) {
|
||||||
deleteProject(projectId: $projectId)
|
deleteProject(projectId: $projectId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var deleteDomain = gql2`
|
var deleteDomain = gql2`
|
||||||
mutation ($domainId: String!) {
|
mutation ($domainId: String!) {
|
||||||
deleteDomain(domainId: $domainId)
|
deleteDomain(domainId: $domainId)
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
var rollbackDeployment = gql2`
|
var rollbackDeployment = gql2`
|
||||||
mutation ($projectId: String!, $deploymentId: String!) {
|
mutation ($projectId: String! ,$deploymentId: String!) {
|
||||||
rollbackDeployment(projectId: $projectId, deploymentId: $deploymentId)
|
rollbackDeployment(projectId: $projectId, deploymentId: $deploymentId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var deleteDeployment = gql2`
|
var deleteDeployment = gql2`
|
||||||
mutation ($deploymentId: String!) {
|
mutation ($deploymentId: String!) {
|
||||||
deleteDeployment(deploymentId: $deploymentId)
|
deleteDeployment(deploymentId: $deploymentId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var addDomain = gql2`
|
var addDomain = gql2`
|
||||||
mutation ($projectId: String!, $data: AddDomainInput!) {
|
mutation ($projectId: String!, $data: AddDomainInput!) {
|
||||||
addDomain(projectId: $projectId, data: $data)
|
addDomain(projectId: $projectId, data: $data)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
var authenticateGitHub = gql2`
|
var authenticateGitHub = gql2`
|
||||||
mutation ($code: String!) {
|
mutation ($code: String!) {
|
||||||
authenticateGitHub(code: $code) {
|
authenticateGitHub(code: $code) {
|
||||||
token
|
token
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`;
|
}`;
|
||||||
var unauthenticateGitHub = gql2`
|
var unauthenticateGitHub = gql2`
|
||||||
mutation {
|
mutation {
|
||||||
unauthenticateGitHub
|
unauthenticateGitHub
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
|
|
||||||
// src/client.ts
|
// src/client.ts
|
||||||
var defaultOptions = {
|
var defaultOptions = {
|
||||||
@@ -530,18 +511,6 @@ var GQLClient = class {
|
|||||||
return data;
|
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) {
|
addProject(organizationSlug, data) {
|
||||||
return __async(this, null, function* () {
|
return __async(this, null, function* () {
|
||||||
const result = yield this.client.mutate({
|
const result = yield this.client.mutate({
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -228,21 +228,6 @@ export class GQLClient {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
async addProject(
|
||||||
organizationSlug: string,
|
organizationSlug: string,
|
||||||
data: types.AddProjectInput
|
data: types.AddProjectInput
|
||||||
|
|||||||
@@ -1,127 +1,107 @@
|
|||||||
import { gql } from "@apollo/client";
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
export const removeProjectMember = gql`
|
export const removeProjectMember = gql`
|
||||||
mutation ($projectMemberId: String!) {
|
mutation ($projectMemberId: String!) {
|
||||||
removeProjectMember(projectMemberId: $projectMemberId)
|
removeProjectMember(projectMemberId: $projectMemberId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const updateProjectMember = gql`
|
export const updateProjectMember = gql`
|
||||||
mutation ($projectMemberId: String!, $data: UpdateProjectMemberInput) {
|
mutation ($projectMemberId: String!, $data: UpdateProjectMemberInput) {
|
||||||
updateProjectMember(projectMemberId: $projectMemberId, data: $data)
|
updateProjectMember(projectMemberId: $projectMemberId, data: $data)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const addProjectMember = gql`
|
export const addProjectMember = gql`
|
||||||
mutation ($projectId: String!, $data: AddProjectMemberInput) {
|
mutation ($projectId: String!, $data: AddProjectMemberInput) {
|
||||||
addProjectMember(projectId: $projectId, data: $data)
|
addProjectMember(projectId: $projectId, data: $data)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const addEnvironmentVariables = gql`
|
export const addEnvironmentVariables = gql`
|
||||||
mutation ($projectId: String!, $data: [AddEnvironmentVariableInput!]) {
|
mutation ($projectId: String!, $data: [AddEnvironmentVariableInput!]) {
|
||||||
addEnvironmentVariables(projectId: $projectId, data: $data)
|
addEnvironmentVariables(projectId: $projectId, data: $data)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const updateEnvironmentVariable = gql`
|
export const updateEnvironmentVariable = gql`
|
||||||
mutation (
|
mutation ($environmentVariableId: String!, $data: UpdateEnvironmentVariableInput!) {
|
||||||
$environmentVariableId: String!
|
updateEnvironmentVariable(environmentVariableId: $environmentVariableId, data: $data)
|
||||||
$data: UpdateEnvironmentVariableInput!
|
}
|
||||||
) {
|
|
||||||
updateEnvironmentVariable(
|
|
||||||
environmentVariableId: $environmentVariableId
|
|
||||||
data: $data
|
|
||||||
)
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const removeEnvironmentVariable = gql`
|
export const removeEnvironmentVariable = gql`
|
||||||
mutation ($environmentVariableId: String!) {
|
mutation ($environmentVariableId: String!) {
|
||||||
removeEnvironmentVariable(environmentVariableId: $environmentVariableId)
|
removeEnvironmentVariable(environmentVariableId: $environmentVariableId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const updateDeploymentToProd = gql`
|
export const updateDeploymentToProd = gql`
|
||||||
mutation ($deploymentId: String!) {
|
mutation ($deploymentId: String!) {
|
||||||
updateDeploymentToProd(deploymentId: $deploymentId)
|
updateDeploymentToProd(deploymentId: $deploymentId)
|
||||||
}
|
}
|
||||||
`;
|
|
||||||
|
|
||||||
export const addProjectFromTemplate = gql`
|
|
||||||
mutation ($organizationSlug: String!, $data: AddProjectFromTemplateInput) {
|
|
||||||
addProjectFromTemplate(organizationSlug: $organizationSlug, data: $data) {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const addProject = gql`
|
export const addProject = gql`
|
||||||
mutation ($organizationSlug: String!, $data: AddProjectInput) {
|
mutation ($organizationSlug: String!, $data: AddProjectInput) {
|
||||||
addProject(organizationSlug: $organizationSlug, data: $data) {
|
addProject(organizationSlug: $organizationSlug, data: $data) {
|
||||||
id
|
id
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`;
|
}`;
|
||||||
|
|
||||||
export const updateProjectMutation = gql`
|
export const updateProjectMutation = gql`
|
||||||
mutation ($projectId: String!, $data: UpdateProjectInput) {
|
mutation ($projectId: String!, $data: UpdateProjectInput) {
|
||||||
updateProject(projectId: $projectId, data: $data)
|
updateProject(projectId: $projectId, data: $data)
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
|
|
||||||
export const updateDomainMutation = gql`
|
export const updateDomainMutation = gql`
|
||||||
mutation ($domainId: String!, $data: UpdateDomainInput!) {
|
mutation ($domainId: String!, $data: UpdateDomainInput!) {
|
||||||
updateDomain(domainId: $domainId, data: $data)
|
updateDomain(domainId: $domainId, data: $data)
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
|
|
||||||
export const redeployToProd = gql`
|
export const redeployToProd = gql`
|
||||||
mutation ($deploymentId: String!) {
|
mutation ($deploymentId: String!) {
|
||||||
redeployToProd(deploymentId: $deploymentId)
|
redeployToProd(deploymentId: $deploymentId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const deleteProject = gql`
|
export const deleteProject = gql`
|
||||||
mutation ($projectId: String!) {
|
mutation ($projectId: String!) {
|
||||||
deleteProject(projectId: $projectId)
|
deleteProject(projectId: $projectId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const deleteDomain = gql`
|
export const deleteDomain = gql`
|
||||||
mutation ($domainId: String!) {
|
mutation ($domainId: String!) {
|
||||||
deleteDomain(domainId: $domainId)
|
deleteDomain(domainId: $domainId)
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
|
|
||||||
export const rollbackDeployment = gql`
|
export const rollbackDeployment = gql`
|
||||||
mutation ($projectId: String!, $deploymentId: String!) {
|
mutation ($projectId: String! ,$deploymentId: String!) {
|
||||||
rollbackDeployment(projectId: $projectId, deploymentId: $deploymentId)
|
rollbackDeployment(projectId: $projectId, deploymentId: $deploymentId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const deleteDeployment = gql`
|
export const deleteDeployment = gql`
|
||||||
mutation ($deploymentId: String!) {
|
mutation ($deploymentId: String!) {
|
||||||
deleteDeployment(deploymentId: $deploymentId)
|
deleteDeployment(deploymentId: $deploymentId)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const addDomain = gql`
|
export const addDomain = gql`
|
||||||
mutation ($projectId: String!, $data: AddDomainInput!) {
|
mutation ($projectId: String!, $data: AddDomainInput!) {
|
||||||
addDomain(projectId: $projectId, data: $data)
|
addDomain(projectId: $projectId, data: $data)
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const authenticateGitHub = gql`
|
export const authenticateGitHub = gql`
|
||||||
mutation ($code: String!) {
|
mutation ($code: String!) {
|
||||||
authenticateGitHub(code: $code) {
|
authenticateGitHub(code: $code) {
|
||||||
token
|
token
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`;
|
}`;
|
||||||
|
|
||||||
export const unauthenticateGitHub = gql`
|
export const unauthenticateGitHub = gql`
|
||||||
mutation {
|
mutation {
|
||||||
unauthenticateGitHub
|
unauthenticateGitHub
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
|
|||||||
+167
-180
@@ -1,311 +1,298 @@
|
|||||||
import { addProjectFromTemplate } from "./mutations";
|
|
||||||
// Note: equivalent to types present in GQL schema
|
// Note: equivalent to types present in GQL schema
|
||||||
|
|
||||||
export enum Role {
|
export enum Role {
|
||||||
Owner = "Owner",
|
Owner = 'Owner',
|
||||||
Maintainer = "Maintainer",
|
Maintainer = 'Maintainer',
|
||||||
Reader = "Reader",
|
Reader = 'Reader',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Permission {
|
export enum Permission {
|
||||||
View = "View",
|
View = 'View',
|
||||||
Edit = "Edit",
|
Edit = 'Edit',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Environment {
|
export enum Environment {
|
||||||
Production = "Production",
|
Production = 'Production',
|
||||||
Preview = "Preview",
|
Preview = 'Preview',
|
||||||
Development = "Development",
|
Development = 'Development',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DeploymentStatus {
|
export enum DeploymentStatus {
|
||||||
Building = "Building",
|
Building = 'Building',
|
||||||
Ready = "Ready",
|
Ready = 'Ready',
|
||||||
Error = "Error",
|
Error = 'Error',
|
||||||
Deleting = "Deleting",
|
Deleting = 'Deleting'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DomainStatus {
|
export enum DomainStatus {
|
||||||
Live = "Live",
|
Live = 'Live',
|
||||||
Pending = "Pending",
|
Pending = 'Pending',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EnvironmentVariable = {
|
export type EnvironmentVariable = {
|
||||||
id: string;
|
id: string
|
||||||
environment: Environment;
|
environment: Environment
|
||||||
key: string;
|
key: string
|
||||||
value: string;
|
value: string
|
||||||
createdAt: string;
|
createdAt: string
|
||||||
updatedAt: string;
|
updatedAt: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export type Domain = {
|
export type Domain = {
|
||||||
id: string;
|
id: string
|
||||||
branch: string;
|
branch: string
|
||||||
name: string;
|
name: string
|
||||||
status: DomainStatus;
|
status: DomainStatus
|
||||||
redirectTo: Domain | null;
|
redirectTo: Domain | null
|
||||||
createdAt: string;
|
createdAt: string
|
||||||
updatedAt: string;
|
updatedAt: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export type User = {
|
export type User = {
|
||||||
id: string;
|
id: string
|
||||||
name: string | null;
|
name: string | null
|
||||||
email: string;
|
email: string
|
||||||
isVerified: boolean;
|
isVerified: boolean
|
||||||
createdAt: string;
|
createdAt: string
|
||||||
updatedAt: string;
|
updatedAt: string
|
||||||
gitHubToken: string | null;
|
gitHubToken: string | null
|
||||||
};
|
}
|
||||||
|
|
||||||
export type Deployment = {
|
export type Deployment = {
|
||||||
id: string;
|
id: string
|
||||||
domain: Domain;
|
domain: Domain
|
||||||
branch: string;
|
branch: string
|
||||||
commitHash: string;
|
commitHash: string
|
||||||
commitMessage: string;
|
commitMessage: string
|
||||||
url?: string;
|
url?: string
|
||||||
environment: Environment;
|
environment: Environment
|
||||||
isCurrent: boolean;
|
isCurrent: boolean
|
||||||
status: DeploymentStatus;
|
status: DeploymentStatus
|
||||||
createdBy: User;
|
createdBy: User
|
||||||
createdAt: string;
|
createdAt: string
|
||||||
updatedAt: string;
|
updatedAt: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export type OrganizationMember = {
|
export type OrganizationMember = {
|
||||||
id: string;
|
id: string
|
||||||
member: User;
|
member: User
|
||||||
role: Role;
|
role: Role
|
||||||
createdAt: string;
|
createdAt: string
|
||||||
updatedAt: string;
|
updatedAt: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export type ProjectMember = {
|
export type ProjectMember = {
|
||||||
id: string;
|
id: string
|
||||||
member: User;
|
member: User
|
||||||
permissions: Permission[];
|
permissions: Permission[]
|
||||||
isPending: boolean;
|
isPending: boolean
|
||||||
createdAt: string;
|
createdAt: string
|
||||||
updatedAt: string;
|
updatedAt: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export type OrganizationProject = {
|
export type OrganizationProject = {
|
||||||
id: string;
|
id: string
|
||||||
owner: User;
|
owner: User
|
||||||
deployments: Deployment[];
|
deployments: Deployment[]
|
||||||
name: string;
|
name: string
|
||||||
repository: string;
|
repository: string
|
||||||
prodBranch: string;
|
prodBranch: string
|
||||||
description: string;
|
description: string
|
||||||
template: string;
|
template: string
|
||||||
framework: string;
|
framework: string
|
||||||
webhooks: string[];
|
webhooks: string[]
|
||||||
members: ProjectMember[];
|
members: ProjectMember[]
|
||||||
environmentVariables: EnvironmentVariable[];
|
environmentVariables: EnvironmentVariable[]
|
||||||
createdAt: string;
|
createdAt: string
|
||||||
updatedAt: string;
|
updatedAt: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export type Organization = {
|
export type Organization = {
|
||||||
id: string;
|
id: string
|
||||||
name: string;
|
name: string
|
||||||
slug: string;
|
slug: string
|
||||||
projects: OrganizationProject[];
|
projects: OrganizationProject[]
|
||||||
createdAt: string;
|
createdAt: string
|
||||||
updatedAt: string;
|
updatedAt: string
|
||||||
members: OrganizationMember[];
|
members: OrganizationMember[]
|
||||||
};
|
}
|
||||||
|
|
||||||
export type Project = {
|
export type Project = {
|
||||||
id: string;
|
id: string
|
||||||
owner: User;
|
owner: User
|
||||||
deployments: Deployment[];
|
deployments: Deployment[]
|
||||||
name: string;
|
name: string
|
||||||
repository: string;
|
repository: string
|
||||||
prodBranch: string;
|
prodBranch: string
|
||||||
description: string;
|
description: string
|
||||||
template: string;
|
template: string
|
||||||
framework: string;
|
framework: string
|
||||||
webhooks: string[];
|
webhooks: string[]
|
||||||
members: ProjectMember[];
|
members: ProjectMember[]
|
||||||
environmentVariables: EnvironmentVariable[];
|
environmentVariables: EnvironmentVariable[]
|
||||||
createdAt: string;
|
createdAt: string
|
||||||
updatedAt: string;
|
updatedAt: string
|
||||||
organization: Organization;
|
organization: Organization
|
||||||
icon: string;
|
icon: string
|
||||||
subDomain: string;
|
subDomain: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export type GetProjectMembersResponse = {
|
export type GetProjectMembersResponse = {
|
||||||
projectMembers: ProjectMember[];
|
projectMembers: ProjectMember[]
|
||||||
};
|
}
|
||||||
|
|
||||||
export type AddProjectMemberResponse = {
|
export type AddProjectMemberResponse = {
|
||||||
addProjectMember: boolean;
|
addProjectMember: boolean
|
||||||
};
|
}
|
||||||
|
|
||||||
export type RemoveProjectMemberResponse = {
|
export type RemoveProjectMemberResponse = {
|
||||||
removeProjectMember: boolean;
|
removeProjectMember: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type UpdateProjectMemberResponse = {
|
export type UpdateProjectMemberResponse = {
|
||||||
updateProjectMember: boolean;
|
updateProjectMember: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type GetDeploymentsResponse = {
|
export type GetDeploymentsResponse = {
|
||||||
deployments: Deployment[];
|
deployments: Deployment[]
|
||||||
};
|
}
|
||||||
|
|
||||||
export type GetEnvironmentVariablesResponse = {
|
export type GetEnvironmentVariablesResponse = {
|
||||||
environmentVariables: EnvironmentVariable[];
|
environmentVariables: EnvironmentVariable[]
|
||||||
};
|
}
|
||||||
|
|
||||||
export type GetOrganizationsResponse = {
|
export type GetOrganizationsResponse = {
|
||||||
organizations: Organization[];
|
organizations: Organization[]
|
||||||
};
|
}
|
||||||
|
|
||||||
export type GetUserResponse = {
|
export type GetUserResponse = {
|
||||||
user: User;
|
user: User
|
||||||
};
|
}
|
||||||
|
|
||||||
export type GetProjectResponse = {
|
export type GetProjectResponse = {
|
||||||
project: Project | null;
|
project: Project | null
|
||||||
};
|
}
|
||||||
|
|
||||||
export type GetProjectsInOrganizationResponse = {
|
export type GetProjectsInOrganizationResponse = {
|
||||||
projectsInOrganization: Project[];
|
projectsInOrganization: Project[]
|
||||||
};
|
}
|
||||||
|
|
||||||
export type GetDomainsResponse = {
|
export type GetDomainsResponse = {
|
||||||
domains: Domain[];
|
domains: Domain[]
|
||||||
};
|
}
|
||||||
|
|
||||||
export type SearchProjectsResponse = {
|
export type SearchProjectsResponse = {
|
||||||
searchProjects: Project[];
|
searchProjects: Project[]
|
||||||
};
|
}
|
||||||
|
|
||||||
export type AddEnvironmentVariablesResponse = {
|
export type AddEnvironmentVariablesResponse = {
|
||||||
addEnvironmentVariables: boolean;
|
addEnvironmentVariables: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type AddEnvironmentVariableInput = {
|
export type AddEnvironmentVariableInput = {
|
||||||
environments: string[];
|
environments: string[];
|
||||||
key: string;
|
key: string;
|
||||||
value: string;
|
value: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type UpdateEnvironmentVariableInput = {
|
export type UpdateEnvironmentVariableInput = {
|
||||||
key: string;
|
key: string;
|
||||||
value: string;
|
value: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type UpdateProjectMemberInput = {
|
export type UpdateProjectMemberInput = {
|
||||||
permissions: Permission[];
|
permissions: Permission[];
|
||||||
};
|
}
|
||||||
|
|
||||||
export type AddProjectMemberInput = {
|
export type AddProjectMemberInput = {
|
||||||
email: string;
|
email: string;
|
||||||
permissions: Permission[];
|
permissions: Permission[]
|
||||||
};
|
}
|
||||||
|
|
||||||
export type UpdateEnvironmentVariableResponse = {
|
export type UpdateEnvironmentVariableResponse = {
|
||||||
updateEnvironmentVariable: boolean;
|
updateEnvironmentVariable: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type RemoveEnvironmentVariableResponse = {
|
export type RemoveEnvironmentVariableResponse = {
|
||||||
removeEnvironmentVariable: boolean;
|
removeEnvironmentVariable: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type UpdateDeploymentToProdResponse = {
|
export type UpdateDeploymentToProdResponse = {
|
||||||
updateDeploymentToProd: boolean;
|
updateDeploymentToProd: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type AddProjectFromTemplateResponse = {
|
|
||||||
addProjectFromTemplate: Project;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AddProjectResponse = {
|
export type AddProjectResponse = {
|
||||||
addProject: Project;
|
addProject: Project
|
||||||
};
|
}
|
||||||
|
|
||||||
export type UpdateProjectResponse = {
|
export type UpdateProjectResponse = {
|
||||||
updateProject: boolean;
|
updateProject: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type UpdateDomainResponse = {
|
export type UpdateDomainResponse = {
|
||||||
updateDomain: boolean;
|
updateDomain: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type DeleteProjectResponse = {
|
export type DeleteProjectResponse = {
|
||||||
deleteProject: boolean;
|
deleteProject: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type DeleteDomainResponse = {
|
export type DeleteDomainResponse = {
|
||||||
deleteDomain: boolean;
|
deleteDomain: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type AddProjectFromTemplateInput = {
|
|
||||||
templateOwner: string;
|
|
||||||
templateRepo: string;
|
|
||||||
owner: string;
|
|
||||||
name: string;
|
|
||||||
isPrivate: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AddProjectInput = {
|
export type AddProjectInput = {
|
||||||
name: string;
|
name: string;
|
||||||
repository: string;
|
repository: string;
|
||||||
prodBranch: string;
|
prodBranch: string;
|
||||||
template?: string;
|
template?: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type UpdateProjectInput = {
|
export type UpdateProjectInput = {
|
||||||
name?: string;
|
name?: string
|
||||||
description?: string;
|
description?: string
|
||||||
prodBranch?: string;
|
prodBranch?: string
|
||||||
webhooks?: string[];
|
webhooks?: string[]
|
||||||
organizationId?: string;
|
organizationId?: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export type UpdateDomainInput = {
|
export type UpdateDomainInput = {
|
||||||
name?: string;
|
name?: string;
|
||||||
branch?: string;
|
branch?: string;
|
||||||
redirectToId?: string | null;
|
redirectToId?: string | null;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type RedeployToProdResponse = {
|
export type RedeployToProdResponse = {
|
||||||
redeployToProd: boolean;
|
redeployToProd: boolean
|
||||||
};
|
}
|
||||||
|
|
||||||
export type RollbackDeploymentResponse = {
|
export type RollbackDeploymentResponse = {
|
||||||
rollbackDeployment: boolean;
|
rollbackDeployment: boolean
|
||||||
};
|
}
|
||||||
|
|
||||||
export type DeleteDeploymentResponse = {
|
export type DeleteDeploymentResponse = {
|
||||||
deleteDeployment: boolean;
|
deleteDeployment: boolean
|
||||||
};
|
}
|
||||||
|
|
||||||
export type AddDomainInput = {
|
export type AddDomainInput = {
|
||||||
name: string;
|
name: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export type FilterDomainInput = {
|
export type FilterDomainInput = {
|
||||||
branch?: string;
|
branch?: string
|
||||||
status?: DomainStatus;
|
status?: DomainStatus
|
||||||
};
|
}
|
||||||
|
|
||||||
export type AddDomainResponse = {
|
export type AddDomainResponse = {
|
||||||
addDomain: true;
|
addDomain: true
|
||||||
};
|
}
|
||||||
|
|
||||||
export type AuthenticateGitHubResponse = {
|
export type AuthenticateGitHubResponse = {
|
||||||
authenticateGitHub: {
|
authenticateGitHub: {
|
||||||
token: string;
|
token: string
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export type UnauthenticateGitHubResponse = {
|
export type UnauthenticateGitHubResponse = {
|
||||||
unauthenticateGitHub: boolean;
|
unauthenticateGitHub: boolean
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -11264,6 +11264,11 @@ globby@11.1.0, globby@^11.0.1, globby@^11.0.2, globby@^11.0.3, globby@^11.1.0:
|
|||||||
merge2 "^1.4.1"
|
merge2 "^1.4.1"
|
||||||
slash "^3.0.0"
|
slash "^3.0.0"
|
||||||
|
|
||||||
|
goober@^2.1.10:
|
||||||
|
version "2.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.14.tgz#4a5c94fc34dc086a8e6035360ae1800005135acd"
|
||||||
|
integrity sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==
|
||||||
|
|
||||||
google-protobuf@^3.19.4:
|
google-protobuf@^3.19.4:
|
||||||
version "3.21.2"
|
version "3.21.2"
|
||||||
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4"
|
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4"
|
||||||
@@ -15323,6 +15328,13 @@ react-hook-form@^7.49.0:
|
|||||||
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.51.3.tgz#7486dd2d52280b6b28048c099a98d2545931cab3"
|
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.51.3.tgz#7486dd2d52280b6b28048c099a98d2545931cab3"
|
||||||
integrity sha512-cvJ/wbHdhYx8aviSWh28w9ImjmVsb5Y05n1+FW786vEZQJV5STNM0pW6ujS+oiBecb0ARBxJFyAnXj9+GHXACQ==
|
integrity sha512-cvJ/wbHdhYx8aviSWh28w9ImjmVsb5Y05n1+FW786vEZQJV5STNM0pW6ujS+oiBecb0ARBxJFyAnXj9+GHXACQ==
|
||||||
|
|
||||||
|
react-hot-toast@^2.4.1:
|
||||||
|
version "2.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.4.1.tgz#df04295eda8a7b12c4f968e54a61c8d36f4c0994"
|
||||||
|
integrity sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==
|
||||||
|
dependencies:
|
||||||
|
goober "^2.1.10"
|
||||||
|
|
||||||
react-inspector@6.0.2:
|
react-inspector@6.0.2:
|
||||||
version "6.0.2"
|
version "6.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-6.0.2.tgz#aa3028803550cb6dbd7344816d5c80bf39d07e9d"
|
resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-6.0.2.tgz#aa3028803550cb6dbd7344816d5c80bf39d07e9d"
|
||||||
|
|||||||
Reference in New Issue
Block a user