Implement organization switcher and use slug in URL (#59)

* Implement dropdown for organizations switcher

* Add dynamic route for organization id

* Update routes for organization slug

* Use organization slug for adding project

* Refactor to fetch organizations at sidebar component

* Update organization switcher based on searched project

* Refactor types in frontend

---------

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
2024-02-07 18:41:54 +05:30
committed by GitHub
co-authored by neeraj
parent 6d1a48905a
commit 413ed03eb8
37 changed files with 293 additions and 246 deletions
+13 -5
View File
@@ -56,6 +56,13 @@ export class Database {
return updateResult.affected > 0;
}
async getOrganization (options: FindOneOptions<Organization>): Promise<Organization | null> {
const organizationRepository = this.dataSource.getRepository(Organization);
const organization = await organizationRepository.findOne(options);
return organization;
}
async getOrganizationsByUserId (userId: string): Promise<Organization[]> {
const organizationRepository = this.dataSource.getRepository(Organization);
@@ -108,7 +115,7 @@ export class Database {
return project;
}
async getProjectsInOrganization (userId: string, organizationId: string): Promise<Project[]> {
async getProjectsInOrganization (userId: string, organizationSlug: string): Promise<Project[]> {
const projectRepository = this.dataSource.getRepository(Project);
const projects = await projectRepository
@@ -116,9 +123,10 @@ export class Database {
.leftJoinAndSelect('project.deployments', 'deployments', 'deployments.isCurrent = true')
.leftJoinAndSelect('deployments.domain', 'domain')
.leftJoin('project.projectMembers', 'projectMembers')
.where('(project.ownerId = :userId OR projectMembers.userId = :userId) AND project.organizationId = :organizationId', {
.leftJoin('project.organization', 'organization')
.where('(project.ownerId = :userId OR projectMembers.userId = :userId) AND organization.slug = :organizationSlug', {
userId,
organizationId
organizationSlug
})
.getMany();
@@ -297,7 +305,7 @@ export class Database {
return Boolean(updateResult.affected);
}
async addProject (userId: string, projectDetails: DeepPartial<Project>): Promise<Project> {
async addProject (userId: string, organizationId: string, projectDetails: DeepPartial<Project>): Promise<Project> {
const projectRepository = this.dataSource.getRepository(Project);
// TODO: Check if organization exists
@@ -312,7 +320,7 @@ export class Database {
});
newProject.organization = Object.assign(new Organization(), {
id: projectDetails.organizationId
id: organizationId
});
newProject.subDomain = `${newProject.name}.${PROJECT_DOMAIN}`;
+6 -1
View File
@@ -4,11 +4,13 @@ import {
Column,
CreateDateColumn,
UpdateDateColumn,
OneToMany
OneToMany,
Unique
} from 'typeorm';
import { UserOrganization } from './UserOrganization';
@Entity()
@Unique(['slug'])
export class Organization {
@PrimaryGeneratedColumn('uuid')
id!: string;
@@ -16,6 +18,9 @@ export class Organization {
@Column('varchar', { length: 255 })
name!: string;
@Column('varchar')
slug!: string;
@CreateDateColumn()
createdAt!: Date;
+4 -4
View File
@@ -29,8 +29,8 @@ export const createResolvers = async (db: Database, app: OAuthApp, service: Serv
return service.getProjectById(projectId);
},
projectsInOrganization: async (_: any, { organizationId }: {organizationId: string }, context: any) => {
return service.getProjectsInOrganization(context.userId, organizationId);
projectsInOrganization: async (_: any, { organizationSlug }: {organizationSlug: string }, context: any) => {
return service.getProjectsInOrganization(context.userId, organizationSlug);
},
deployments: async (_: any, { projectId }: { projectId: string }) => {
@@ -130,9 +130,9 @@ export const createResolvers = async (db: Database, app: OAuthApp, service: Serv
}
},
addProject: async (_: any, { data }: { data: DeepPartial<Project> }, context: any) => {
addProject: async (_: any, { organizationSlug, data }: { organizationSlug: string, data: DeepPartial<Project> }, context: any) => {
try {
return service.addProject(context.userId, data);
return service.addProject(context.userId, organizationSlug, data);
} catch (err) {
log(err);
}
+3 -3
View File
@@ -41,6 +41,7 @@ type User {
type Organization {
id: String!
name: String!
slug: String!
projects: [Project!]
createdAt: String!
updatedAt: String!
@@ -129,7 +130,6 @@ input AddEnvironmentVariableInput {
}
input AddProjectInput {
organizationId: String!
name: String!
repository: String!
prodBranch: String!
@@ -176,7 +176,7 @@ type Query {
user: User!
organizations: [Organization!]
projects: [Project!]
projectsInOrganization(organizationId: String!): [Project!]
projectsInOrganization(organizationSlug: String!): [Project!]
project(projectId: String!): Project
deployments(projectId: String!): [Deployment!]
environmentVariables(projectId: String!): [EnvironmentVariable!]
@@ -193,7 +193,7 @@ type Mutation {
updateEnvironmentVariable(environmentVariableId: String!, data: UpdateEnvironmentVariableInput!): Boolean!
removeEnvironmentVariable(environmentVariableId: String!): Boolean!
updateDeploymentToProd(deploymentId: String!): Boolean!
addProject(data: AddProjectInput): Project!
addProject(organizationSlug: String!, data: AddProjectInput): Project!
updateProject(projectId: String!, projectDetails: UpdateProjectInput): Boolean!
redeployToProd(deploymentId: String!): Boolean!
deleteProject(projectId: String!): Boolean!
+13 -4
View File
@@ -40,8 +40,8 @@ export class Service {
return dbProject;
}
async getProjectsInOrganization (userId:string, organizationId: string): Promise<Project[]> {
const dbProjects = await this.db.getProjectsInOrganization(userId, organizationId);
async getProjectsInOrganization (userId:string, organizationSlug: string): Promise<Project[]> {
const dbProjects = await this.db.getProjectsInOrganization(userId, organizationSlug);
return dbProjects;
}
@@ -182,8 +182,17 @@ export class Service {
return updateResult;
}
async addProject (userId: string, data: DeepPartial<Project>): Promise<Project | undefined> {
return this.db.addProject(userId, data);
async addProject (userId: string, organizationSlug: string, data: DeepPartial<Project>): Promise<Project | undefined> {
const organization = await this.db.getOrganization({
where: {
slug: organizationSlug
}
});
if (!organization) {
throw new Error('Organization does not exist');
}
return this.db.addProject(userId, organization.id, data);
}
async updateProject (projectId: string, data: DeepPartial<Project>): Promise<boolean> {
+4 -2
View File
@@ -1,8 +1,10 @@
[
{
"name": "Snowball Tools"
"name": "Snowball Tools",
"slug": "snowball-tools"
},
{
"name": "AirFoil"
"name": "AirFoil",
"slug": "airfoil"
}
]