forked from cerc-io/snowballtools-base
Refactor mutation GQL methods to service class and display organization name (#53)
* Refactor mutation methods to service class * Refactor database methods to service class * Display organization name in sidebar * Handle review comments --------- Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
parent
ac7064afa5
commit
da92ddfba3
@ -1,24 +1,20 @@
|
||||
import { DataSource, DeepPartial } from 'typeorm';
|
||||
import { DataSource, DeepPartial, FindManyOptions, FindOneOptions } from 'typeorm';
|
||||
import path from 'path';
|
||||
import debug from 'debug';
|
||||
import assert from 'assert';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { lowercase, numbers } from 'nanoid-dictionary';
|
||||
|
||||
import { DatabaseConfig } from './config';
|
||||
import { User } from './entity/User';
|
||||
import { Organization } from './entity/Organization';
|
||||
import { Project } from './entity/Project';
|
||||
import { Deployment, Environment } from './entity/Deployment';
|
||||
import { Permission, ProjectMember } from './entity/ProjectMember';
|
||||
import { Deployment } from './entity/Deployment';
|
||||
import { ProjectMember } from './entity/ProjectMember';
|
||||
import { EnvironmentVariable } from './entity/EnvironmentVariable';
|
||||
import { Domain } from './entity/Domain';
|
||||
import { PROJECT_DOMAIN } from './constants';
|
||||
|
||||
const log = debug('snowball:database');
|
||||
|
||||
const nanoid = customAlphabet(lowercase + numbers, 8);
|
||||
|
||||
// TODO: Fix order of methods
|
||||
export class Database {
|
||||
private dataSource: DataSource;
|
||||
@ -38,11 +34,16 @@ export class Database {
|
||||
log('database initialized');
|
||||
}
|
||||
|
||||
async getUser (userId: number): Promise<User | null> {
|
||||
async getUser (options: FindOneOptions<User>): Promise<User | null> {
|
||||
const userRepository = this.dataSource.getRepository(User);
|
||||
const user = await userRepository.findOneBy({
|
||||
id: userId
|
||||
});
|
||||
const user = await userRepository.findOne(options);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
async createUser (data: DeepPartial<User>): Promise<User> {
|
||||
const userRepository = this.dataSource.getRepository(User);
|
||||
const user = await userRepository.save(data);
|
||||
|
||||
return user;
|
||||
}
|
||||
@ -146,6 +147,27 @@ export class Database {
|
||||
return deployments;
|
||||
}
|
||||
|
||||
async getDeployment (options: FindOneOptions<Deployment>): Promise<Deployment | null> {
|
||||
const deploymentRepository = this.dataSource.getRepository(Deployment);
|
||||
const deployment = await deploymentRepository.findOne(options);
|
||||
|
||||
return deployment;
|
||||
}
|
||||
|
||||
async getDomains (options: FindManyOptions<Domain>): Promise<Domain[]> {
|
||||
const domainRepository = this.dataSource.getRepository(Domain);
|
||||
const domains = await domainRepository.find(options);
|
||||
|
||||
return domains;
|
||||
}
|
||||
|
||||
async createDeployement (data: DeepPartial<Deployment>): Promise<Deployment> {
|
||||
const deploymentRepository = this.dataSource.getRepository(Deployment);
|
||||
const deployment = await deploymentRepository.save(data);
|
||||
|
||||
return deployment;
|
||||
}
|
||||
|
||||
async getProjectMembersByProjectId (projectId: string): Promise<ProjectMember[]> {
|
||||
const projectMemberRepository = this.dataSource.getRepository(ProjectMember);
|
||||
|
||||
@ -201,60 +223,18 @@ export class Database {
|
||||
}
|
||||
}
|
||||
|
||||
async addProjectMember (projectId: string, data: {
|
||||
email: string,
|
||||
permissions: Permission[]
|
||||
}): Promise<boolean> {
|
||||
async addProjectMember (data: DeepPartial<ProjectMember>): Promise<ProjectMember> {
|
||||
const projectMemberRepository = this.dataSource.getRepository(ProjectMember);
|
||||
const userRepository = this.dataSource.getRepository(User);
|
||||
const newProjectMember = await projectMemberRepository.save(data);
|
||||
|
||||
let user = await userRepository.findOneBy({
|
||||
email: data.email
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
user = await userRepository.save({
|
||||
email: data.email,
|
||||
isVerified: false
|
||||
});
|
||||
}
|
||||
|
||||
const newProjectMember = await projectMemberRepository.save({
|
||||
project: {
|
||||
id: projectId
|
||||
},
|
||||
permissions: data.permissions,
|
||||
isPending: true,
|
||||
member: {
|
||||
id: user.id
|
||||
}
|
||||
});
|
||||
|
||||
return Boolean(newProjectMember);
|
||||
return newProjectMember;
|
||||
}
|
||||
|
||||
async addEnvironmentVariablesByProjectId (projectId: string, environmentVariables: {
|
||||
environments: string[];
|
||||
key: string;
|
||||
value: string;
|
||||
}[]): Promise<boolean> {
|
||||
async addEnvironmentVariables (data: DeepPartial<EnvironmentVariable>[]): Promise<EnvironmentVariable[]> {
|
||||
const environmentVariableRepository = this.dataSource.getRepository(EnvironmentVariable);
|
||||
const savedEnvironmentVariables = await environmentVariableRepository.save(data);
|
||||
|
||||
const formattedEnvironmentVariables = environmentVariables.map((environmentVariable) => {
|
||||
return environmentVariable.environments.map((environment) => {
|
||||
return ({
|
||||
key: environmentVariable.key,
|
||||
value: environmentVariable.value,
|
||||
environment: environment as Environment,
|
||||
project: Object.assign(new Project(), {
|
||||
id: projectId
|
||||
})
|
||||
});
|
||||
});
|
||||
}).flat();
|
||||
|
||||
const savedEnvironmentVariables = await environmentVariableRepository.save(formattedEnvironmentVariables);
|
||||
return savedEnvironmentVariables.length > 0;
|
||||
return savedEnvironmentVariables;
|
||||
}
|
||||
|
||||
async updateEnvironmentVariable (environmentVariableId: string, update: DeepPartial<EnvironmentVariable>): Promise<boolean> {
|
||||
@ -363,40 +343,6 @@ export class Database {
|
||||
}
|
||||
}
|
||||
|
||||
async redeployToProdById (userId: string, deploymentId: string): Promise<Deployment> {
|
||||
const deploymentRepository = this.dataSource.getRepository(Deployment);
|
||||
const deployment = await deploymentRepository.findOne({
|
||||
relations: {
|
||||
project: true,
|
||||
domain: true,
|
||||
createdBy: true
|
||||
},
|
||||
where: {
|
||||
id: deploymentId
|
||||
}
|
||||
});
|
||||
|
||||
if (deployment === null) {
|
||||
throw new Error('Deployment not found');
|
||||
}
|
||||
const { createdAt, updatedAt, ...updatedDeployment } = deployment;
|
||||
|
||||
if (updatedDeployment.environment === Environment.Production) {
|
||||
// TODO: Put isCurrent field in project
|
||||
updatedDeployment.isCurrent = true;
|
||||
updatedDeployment.createdBy = Object.assign(new User(), {
|
||||
id: Number(userId)
|
||||
});
|
||||
}
|
||||
|
||||
await deploymentRepository.update({ id: deploymentId }, { domain: null, isCurrent: false });
|
||||
|
||||
updatedDeployment.id = nanoid();
|
||||
updatedDeployment.url = `${updatedDeployment.id}-${updatedDeployment.project.subDomain}`;
|
||||
|
||||
return deploymentRepository.save(updatedDeployment);
|
||||
}
|
||||
|
||||
async deleteProjectById (projectId: string): Promise<boolean> {
|
||||
const projectRepository = this.dataSource.getRepository(Project);
|
||||
const project = await projectRepository.findOneOrFail({
|
||||
@ -416,16 +362,6 @@ export class Database {
|
||||
async deleteDomainById (domainId: string): Promise<boolean> {
|
||||
const domainRepository = this.dataSource.getRepository(Domain);
|
||||
|
||||
const domainsRedirectedFrom = await domainRepository.find({
|
||||
where: {
|
||||
redirectToId: Number(domainId)
|
||||
}
|
||||
});
|
||||
|
||||
if (domainsRedirectedFrom.length > 0) {
|
||||
throw new Error('Cannot delete domain since it has redirects from other domains');
|
||||
}
|
||||
|
||||
const deleteResult = await domainRepository.softDelete({ id: Number(domainId) });
|
||||
|
||||
if (deleteResult.affected) {
|
||||
|
@ -7,10 +7,10 @@ import { OAuthApp } from '@octokit/oauth-app';
|
||||
import { Service } from './service';
|
||||
import { Database } from './database';
|
||||
import { isUserOwner } from './utils';
|
||||
import { Environment } from './entity/Deployment';
|
||||
import { Permission } from './entity/ProjectMember';
|
||||
import { Domain } from './entity/Domain';
|
||||
import { Project } from './entity/Project';
|
||||
import { EnvironmentVariable } from './entity/EnvironmentVariable';
|
||||
|
||||
const log = debug('snowball:database');
|
||||
|
||||
@ -86,12 +86,7 @@ export const createResolvers = async (db: Database, app: OAuthApp, service: Serv
|
||||
permissions: Permission[]
|
||||
}
|
||||
}) => {
|
||||
try {
|
||||
return await db.updateProjectMemberById(projectMemberId, data);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
return service.updateProjectMember(projectMemberId, data);
|
||||
},
|
||||
|
||||
addProjectMember: async (_: any, { projectId, data }: {
|
||||
@ -101,100 +96,43 @@ export const createResolvers = async (db: Database, app: OAuthApp, service: Serv
|
||||
permissions: Permission[]
|
||||
}
|
||||
}) => {
|
||||
try {
|
||||
// TODO: Send invitation
|
||||
return await db.addProjectMember(projectId, data);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
return service.addProjectMember(projectId, data);
|
||||
},
|
||||
|
||||
addEnvironmentVariables: async (_: any, { projectId, environmentVariables }: { projectId: string, environmentVariables: { environments: string[], key: string, value: string}[] }) => {
|
||||
try {
|
||||
return await db.addEnvironmentVariablesByProjectId(projectId, environmentVariables);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
addEnvironmentVariables: async (_: any, { projectId, data }: { projectId: string, data: { environments: string[], key: string, value: string}[] }) => {
|
||||
return service.addEnvironmentVariables(projectId, data);
|
||||
},
|
||||
|
||||
updateEnvironmentVariable: async (_: any, { environmentVariableId, environmentVariable }: { environmentVariableId: string, environmentVariable : {
|
||||
key: string
|
||||
value: string
|
||||
}}) => {
|
||||
try {
|
||||
return await db.updateEnvironmentVariable(environmentVariableId, environmentVariable);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
updateEnvironmentVariable: async (_: any, { environmentVariableId, data }: { environmentVariableId: string, data : DeepPartial<EnvironmentVariable>}) => {
|
||||
return service.updateEnvironmentVariable(environmentVariableId, data);
|
||||
},
|
||||
|
||||
removeEnvironmentVariable: async (_: any, { environmentVariableId }: { environmentVariableId: string}) => {
|
||||
try {
|
||||
return await db.deleteEnvironmentVariable(environmentVariableId);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
return service.removeEnvironmentVariable(environmentVariableId);
|
||||
},
|
||||
|
||||
updateDeploymentToProd: async (_: any, { deploymentId }: { deploymentId: string }) => {
|
||||
try {
|
||||
return await db.updateDeploymentById(deploymentId, {
|
||||
environment: Environment.Production
|
||||
});
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
return service.updateDeploymentToProd(deploymentId);
|
||||
},
|
||||
|
||||
addProject: async (_: any, { projectDetails }: { projectDetails: DeepPartial<Project> }, context: any) => {
|
||||
try {
|
||||
await db.addProject(context.userId, projectDetails);
|
||||
return true;
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
addProject: async (_: any, { data }: { data: DeepPartial<Project> }, context: any) => {
|
||||
return service.addProject(context.userId, data);
|
||||
},
|
||||
|
||||
updateProject: async (_: any, { projectId, projectDetails }: { projectId: string, projectDetails: DeepPartial<Project> }) => {
|
||||
try {
|
||||
return await db.updateProjectById(projectId, projectDetails);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
return service.updateProject(projectId, projectDetails);
|
||||
},
|
||||
|
||||
redeployToProd: async (_: any, { deploymentId }: { deploymentId: string }, context: any) => {
|
||||
try {
|
||||
return await db.redeployToProdById(context.userId, deploymentId);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
return service.redeployToProd(context.userId, deploymentId);
|
||||
},
|
||||
|
||||
deleteProject: async (_: any, { projectId }: { projectId: string }) => {
|
||||
try {
|
||||
return await db.deleteProjectById(projectId);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
return service.deleteProject(projectId);
|
||||
},
|
||||
|
||||
deleteDomain: async (_: any, { domainId }: { domainId: string }) => {
|
||||
try {
|
||||
return await db.deleteDomainById(domainId);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
return service.deleteDomain(domainId);
|
||||
},
|
||||
|
||||
rollbackDeployment: async (_: any, { projectId, deploymentId }: {deploymentId: string, projectId: string }) => {
|
||||
|
@ -184,8 +184,8 @@ type Mutation {
|
||||
addProjectMember(projectId: String!, data: AddProjectMemberInput): Boolean!
|
||||
updateProjectMember(projectMemberId: String!, data: UpdateProjectMemberInput): Boolean!
|
||||
removeProjectMember(projectMemberId: String!): Boolean!
|
||||
addEnvironmentVariables(projectId: String!, environmentVariables: [AddEnvironmentVariableInput!]): Boolean!
|
||||
updateEnvironmentVariable(environmentVariableId: String!, environmentVariable: UpdateEnvironmentVariableInput!): Boolean!
|
||||
addEnvironmentVariables(projectId: String!, data: [AddEnvironmentVariableInput!]): Boolean!
|
||||
updateEnvironmentVariable(environmentVariableId: String!, data: UpdateEnvironmentVariableInput!): Boolean!
|
||||
removeEnvironmentVariable(environmentVariableId: String!): Boolean!
|
||||
updateDeploymentToProd(deploymentId: String!): Boolean!
|
||||
addProject(projectDetails: AddProjectInput): Boolean!
|
||||
|
@ -1,11 +1,20 @@
|
||||
import debug from 'debug';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { lowercase, numbers } from 'nanoid-dictionary';
|
||||
|
||||
import { Database } from './database';
|
||||
import { Deployment } from './entity/Deployment';
|
||||
import { Deployment, Environment } from './entity/Deployment';
|
||||
import { Domain } from './entity/Domain';
|
||||
import { EnvironmentVariable } from './entity/EnvironmentVariable';
|
||||
import { Organization } from './entity/Organization';
|
||||
import { Project } from './entity/Project';
|
||||
import { ProjectMember } from './entity/ProjectMember';
|
||||
import { Permission, ProjectMember } from './entity/ProjectMember';
|
||||
import { User } from './entity/User';
|
||||
import { DeepPartial } from 'typeorm';
|
||||
|
||||
const log = debug('snowball:service');
|
||||
|
||||
const nanoid = customAlphabet(lowercase + numbers, 8);
|
||||
|
||||
export class Service {
|
||||
private db: Database;
|
||||
@ -15,7 +24,11 @@ export class Service {
|
||||
}
|
||||
|
||||
async getUser (userId: number): Promise<User | null> {
|
||||
return this.db.getUser(userId);
|
||||
return this.db.getUser({
|
||||
where: {
|
||||
id: userId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async getOrganizationsByUserId (userId: number): Promise<Organization[]> {
|
||||
@ -57,4 +70,189 @@ export class Service {
|
||||
const dbDomains = await this.db.getDomainsByProjectId(projectId);
|
||||
return dbDomains;
|
||||
}
|
||||
|
||||
async updateProjectMember (projectMemberId: string, data: {permissions: Permission[]}): Promise<boolean> {
|
||||
try {
|
||||
return await this.db.updateProjectMemberById(projectMemberId, data);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async addProjectMember (projectId: string,
|
||||
data: {
|
||||
email: string,
|
||||
permissions: Permission[]
|
||||
}): Promise<boolean> {
|
||||
try {
|
||||
// TODO: Send invitation
|
||||
let user = await this.db.getUser({
|
||||
where: {
|
||||
email: data.email
|
||||
}
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
user = await this.db.createUser({
|
||||
email: data.email
|
||||
});
|
||||
}
|
||||
|
||||
const newProjectMember = await this.db.addProjectMember({
|
||||
project: {
|
||||
id: projectId
|
||||
},
|
||||
permissions: data.permissions,
|
||||
isPending: true,
|
||||
member: {
|
||||
id: user.id
|
||||
}
|
||||
});
|
||||
|
||||
return Boolean(newProjectMember);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async addEnvironmentVariables (projectId: string, data: { environments: string[], key: string, value: string}[]): Promise<boolean> {
|
||||
try {
|
||||
const formattedEnvironmentVariables = data.map((environmentVariable) => {
|
||||
return environmentVariable.environments.map((environment) => {
|
||||
return ({
|
||||
key: environmentVariable.key,
|
||||
value: environmentVariable.value,
|
||||
environment: environment as Environment,
|
||||
project: Object.assign(new Project(), {
|
||||
id: projectId
|
||||
})
|
||||
});
|
||||
});
|
||||
}).flat();
|
||||
|
||||
const savedEnvironmentVariables = await this.db.addEnvironmentVariables(formattedEnvironmentVariables);
|
||||
return savedEnvironmentVariables.length > 0;
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async updateEnvironmentVariable (environmentVariableId: string, data : DeepPartial<EnvironmentVariable>): Promise<boolean> {
|
||||
try {
|
||||
return await this.db.updateEnvironmentVariable(environmentVariableId, data);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async removeEnvironmentVariable (environmentVariableId: string): Promise<boolean> {
|
||||
try {
|
||||
return await this.db.deleteEnvironmentVariable(environmentVariableId);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async updateDeploymentToProd (deploymentId: string): Promise<boolean> {
|
||||
try {
|
||||
return await this.db.updateDeploymentById(deploymentId, {
|
||||
environment: Environment.Production
|
||||
});
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async addProject (userId: string, data: DeepPartial<Project>): Promise<boolean> {
|
||||
try {
|
||||
await this.db.addProject(userId, data);
|
||||
return true;
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async updateProject (projectId: string, data: DeepPartial<Project>): Promise<boolean> {
|
||||
try {
|
||||
return await this.db.updateProjectById(projectId, data);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteProject (projectId: string): Promise<boolean> {
|
||||
try {
|
||||
return await this.db.deleteProjectById(projectId);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteDomain (domainId: string): Promise<boolean> {
|
||||
try {
|
||||
const domainsRedirectedFrom = await this.db.getDomains({
|
||||
where: {
|
||||
redirectToId: Number(domainId)
|
||||
}
|
||||
});
|
||||
|
||||
if (domainsRedirectedFrom.length > 0) {
|
||||
throw new Error('Cannot delete domain since it has redirects from other domains');
|
||||
}
|
||||
|
||||
return await this.db.deleteDomainById(domainId);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async redeployToProd (userId: string, deploymentId: string): Promise<Deployment| boolean> {
|
||||
try {
|
||||
const deployment = await this.db.getDeployment({
|
||||
relations: {
|
||||
project: true,
|
||||
domain: true,
|
||||
createdBy: true
|
||||
},
|
||||
where: {
|
||||
id: deploymentId
|
||||
}
|
||||
});
|
||||
|
||||
if (deployment === null) {
|
||||
throw new Error('Deployment not found');
|
||||
}
|
||||
|
||||
const { createdAt, updatedAt, ...updatedDeployment } = deployment;
|
||||
|
||||
if (updatedDeployment.environment === Environment.Production) {
|
||||
// TODO: Put isCurrent field in project
|
||||
updatedDeployment.isCurrent = true;
|
||||
updatedDeployment.createdBy = Object.assign(new User(), {
|
||||
id: Number(userId)
|
||||
});
|
||||
}
|
||||
|
||||
updatedDeployment.id = nanoid();
|
||||
updatedDeployment.url = `${updatedDeployment.id}-${updatedDeployment.project.subDomain}`;
|
||||
|
||||
const oldDeployment = await this.db.updateDeploymentById(deploymentId, { domain: null, isCurrent: false });
|
||||
const newDeployement = await this.db.createDeployement(updatedDeployment);
|
||||
|
||||
return oldDeployment && Boolean(newDeployement);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import React from 'react';
|
||||
import { Link, NavLink } from 'react-router-dom';
|
||||
import { Organization } from 'gql-client';
|
||||
|
||||
import { Card, CardBody, Typography } from '@material-tailwind/react';
|
||||
|
||||
const Sidebar = () => {
|
||||
const Sidebar = ({ organization }: { organization: Organization }) => {
|
||||
return (
|
||||
<div className="flex flex-col h-full p-4">
|
||||
<div className="grow">
|
||||
@ -13,8 +14,12 @@ const Sidebar = () => {
|
||||
</Link>
|
||||
</div>
|
||||
<Card className="-ml-1 my-2">
|
||||
<CardBody className="p-1 py-2">
|
||||
<Typography>Organization</Typography>
|
||||
<CardBody className="p-1 py-2 flex gap-2">
|
||||
<div>^</div>
|
||||
<div>
|
||||
<Typography>{organization.name}</Typography>
|
||||
<Typography>Organization</Typography>
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
<div>
|
||||
|
@ -1,19 +1,42 @@
|
||||
import React from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Organization } from 'gql-client';
|
||||
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
import Sidebar from '../components/Sidebar';
|
||||
import { useGQLClient } from '../context/GQLClientContext';
|
||||
|
||||
// TODO: Implement organization switcher
|
||||
// TODO: Projects get organization details through routes instead of context
|
||||
const USER_ORGANIZATION_INDEX = 0;
|
||||
|
||||
const Dashboard = () => {
|
||||
const client = useGQLClient();
|
||||
const [organizations, setOrganizations] = useState<Organization[]>([]);
|
||||
|
||||
const fetchUserOrganizations = useCallback(async () => {
|
||||
const { organizations } = await client.getOrganizations();
|
||||
setOrganizations(organizations);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetchUserOrganizations();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-5 h-screen bg-light-blue-50">
|
||||
<div className="h-full">
|
||||
<Sidebar />
|
||||
</div>
|
||||
<div className="col-span-4 h-full p-3 overflow-y-hidden">
|
||||
<div className="bg-white rounded-3xl h-full overflow-y-auto">
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
{organizations.length > 0 && (
|
||||
<>
|
||||
<div className="h-full">
|
||||
<Sidebar organization={organizations[USER_ORGANIZATION_INDEX]} />
|
||||
</div>
|
||||
<div className="col-span-4 h-full p-3 overflow-y-hidden">
|
||||
<div className="bg-white rounded-3xl h-full overflow-y-auto">
|
||||
<Outlet context={organizations[USER_ORGANIZATION_INDEX]} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Outlet, useNavigate } from 'react-router-dom';
|
||||
import { Outlet, useNavigate, useOutletContext } from 'react-router-dom';
|
||||
import { Organization } from 'gql-client';
|
||||
|
||||
import { IconButton, Typography } from '@material-tailwind/react';
|
||||
|
||||
@ -8,7 +9,7 @@ import ProjectSearchBar from '../components/projects/ProjectSearchBar';
|
||||
|
||||
const ProjectSearch = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const organization = useOutletContext<Organization>();
|
||||
return (
|
||||
<div>
|
||||
<div className="sticky top-0 bg-white z-30">
|
||||
@ -33,7 +34,7 @@ const ProjectSearch = () => {
|
||||
<HorizontalLine />
|
||||
</div>
|
||||
<div className="z-0">
|
||||
<Outlet />
|
||||
<Outlet context={organization} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link, useOutletContext } from 'react-router-dom';
|
||||
import { Organization } from 'gql-client';
|
||||
|
||||
import { Button, Typography, Chip } from '@material-tailwind/react';
|
||||
|
||||
@ -8,16 +9,16 @@ import { useGQLClient } from '../context/GQLClientContext';
|
||||
import { ProjectDetails } from '../types/project';
|
||||
import { COMMIT_DETAILS } from '../constants';
|
||||
|
||||
// TODO: Implement organization switcher
|
||||
const USER_ORGANIZATION_ID = '1';
|
||||
|
||||
const Projects = () => {
|
||||
const client = useGQLClient();
|
||||
const organization = useOutletContext<Organization>();
|
||||
|
||||
const [projects, setProjects] = useState<ProjectDetails[]>([]);
|
||||
|
||||
const fetchProjects = useCallback(async () => {
|
||||
const { projectsInOrganization } =
|
||||
await client.getProjectsInOrganization(USER_ORGANIZATION_ID);
|
||||
const { projectsInOrganization } = await client.getProjectsInOrganization(
|
||||
organization.id,
|
||||
);
|
||||
|
||||
const updatedProjects = projectsInOrganization.map((project) => {
|
||||
return {
|
||||
|
@ -148,28 +148,28 @@ export class GQLClient {
|
||||
return data;
|
||||
}
|
||||
|
||||
async addEnvironmentVariables (projectId: string, environmentVariables: AddEnvironmentVariableInput[]): Promise<AddEnvironmentVariablesResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
async addEnvironmentVariables (projectId: string, data: AddEnvironmentVariableInput[]): Promise<AddEnvironmentVariablesResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: addEnvironmentVariables,
|
||||
variables: {
|
||||
projectId,
|
||||
environmentVariables
|
||||
data
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async updateEnvironmentVariable (environmentVariableId: string, environmentVariable: UpdateEnvironmentVariableInput): Promise<UpdateEnvironmentVariableResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
async updateEnvironmentVariable (environmentVariableId: string, data: UpdateEnvironmentVariableInput): Promise<UpdateEnvironmentVariableResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: updateEnvironmentVariable,
|
||||
variables: {
|
||||
environmentVariableId,
|
||||
environmentVariable
|
||||
data
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async removeEnvironmentVariable (environmentVariableId: string): Promise<RemoveEnvironmentVariableResponse> {
|
||||
|
@ -19,14 +19,14 @@ mutation ($projectId: String!, $data: AddProjectMemberInput) {
|
||||
`;
|
||||
|
||||
export const addEnvironmentVariables = gql`
|
||||
mutation ($projectId: String!, $environmentVariables: [AddEnvironmentVariableInput!]) {
|
||||
addEnvironmentVariables(projectId: $projectId, environmentVariables: $environmentVariables)
|
||||
mutation ($projectId: String!, $data: [AddEnvironmentVariableInput!]) {
|
||||
addEnvironmentVariables(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
|
||||
export const updateEnvironmentVariable = gql`
|
||||
mutation ($environmentVariableId: String!, $environmentVariable: UpdateEnvironmentVariableInput!) {
|
||||
updateEnvironmentVariable(environmentVariableId: $environmentVariableId, environmentVariable: $environmentVariable)
|
||||
mutation ($environmentVariableId: String!, $data: UpdateEnvironmentVariableInput!) {
|
||||
updateEnvironmentVariable(environmentVariableId: $environmentVariableId, data: $data)
|
||||
}
|
||||
`;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user