Compare commits
1 Commits
feat/colle
...
revamp/hea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1dcfc684ef |
@@ -1,5 +0,0 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "TeamCollection" ADD COLUMN "data" JSONB;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "UserCollection" ADD COLUMN "data" JSONB;
|
||||
@@ -43,7 +43,6 @@ model TeamInvitation {
|
||||
model TeamCollection {
|
||||
id String @id @default(cuid())
|
||||
parentID String?
|
||||
data Json?
|
||||
parent TeamCollection? @relation("TeamCollectionChildParent", fields: [parentID], references: [id])
|
||||
children TeamCollection[] @relation("TeamCollectionChildParent")
|
||||
requests TeamRequest[]
|
||||
@@ -75,8 +74,7 @@ model Shortcode {
|
||||
creatorUid String?
|
||||
User User? @relation(fields: [creatorUid], references: [uid])
|
||||
createdOn DateTime @default(now())
|
||||
updatedOn DateTime @default(now()) @updatedAt
|
||||
|
||||
updatedOn DateTime @updatedAt @default(now())
|
||||
@@unique(fields: [id, creatorUid], name: "creator_uid_shortcode_unique")
|
||||
}
|
||||
|
||||
@@ -197,7 +195,6 @@ model UserCollection {
|
||||
userUid String
|
||||
user User @relation(fields: [userUid], references: [uid], onDelete: Cascade)
|
||||
title String
|
||||
data Json?
|
||||
orderIndex Int
|
||||
type ReqType
|
||||
createdOn DateTime @default(now()) @db.Timestamp(3)
|
||||
|
||||
@@ -254,13 +254,6 @@ export const TEAM_COLL_INVALID_JSON = 'team_coll/invalid_json';
|
||||
*/
|
||||
export const TEAM_NOT_OWNER = 'team_coll/team_not_owner' as const;
|
||||
|
||||
/**
|
||||
* The Team Collection data is not valid
|
||||
* (TeamCollectionService)
|
||||
*/
|
||||
export const TEAM_COLL_DATA_INVALID =
|
||||
'team_coll/team_coll_data_invalid' as const;
|
||||
|
||||
/**
|
||||
* Tried to perform an action on a request that doesn't accept their member role level
|
||||
* (GqlRequestTeamMemberGuard)
|
||||
@@ -592,13 +585,6 @@ export const USER_COLL_REORDERING_FAILED =
|
||||
export const USER_COLL_SAME_NEXT_COLL =
|
||||
'user_coll/user_collection_and_next_user_collection_are_same' as const;
|
||||
|
||||
/**
|
||||
* The User Collection data is not valid
|
||||
* (UserCollectionService)
|
||||
*/
|
||||
export const USER_COLL_DATA_INVALID =
|
||||
'user_coll/user_coll_data_invalid' as const;
|
||||
|
||||
/**
|
||||
* The User Collection does not belong to the logged-in user
|
||||
* (UserCollectionService)
|
||||
|
||||
@@ -21,8 +21,8 @@ import {
|
||||
} from 'src/team-request/team-request.model';
|
||||
import { TeamInvitation } from 'src/team-invitation/team-invitation.model';
|
||||
import { InvitedUser } from '../admin/invited-user.model';
|
||||
import { UserCollection } from '@prisma/client';
|
||||
import {
|
||||
UserCollection,
|
||||
UserCollectionRemovedData,
|
||||
UserCollectionReorderData,
|
||||
} from 'src/user-collection/user-collections.model';
|
||||
|
||||
@@ -14,13 +14,6 @@ export class CreateRootTeamCollectionArgs {
|
||||
|
||||
@Field({ name: 'title', description: 'Title of the new collection' })
|
||||
title: string;
|
||||
|
||||
@Field({
|
||||
name: 'data',
|
||||
description: 'JSON string representing the collection data',
|
||||
nullable: true,
|
||||
})
|
||||
data: string;
|
||||
}
|
||||
|
||||
@ArgsType()
|
||||
@@ -33,13 +26,6 @@ export class CreateChildTeamCollectionArgs {
|
||||
|
||||
@Field({ name: 'childTitle', description: 'Title of the new collection' })
|
||||
childTitle: string;
|
||||
|
||||
@Field({
|
||||
name: 'data',
|
||||
description: 'JSON string representing the collection data',
|
||||
nullable: true,
|
||||
})
|
||||
data: string;
|
||||
}
|
||||
|
||||
@ArgsType()
|
||||
@@ -47,14 +33,12 @@ export class RenameTeamCollectionArgs {
|
||||
@Field(() => ID, {
|
||||
name: 'collectionID',
|
||||
description: 'ID of the collection',
|
||||
deprecationReason: 'Switch to updateTeamCollection mutation instead',
|
||||
})
|
||||
collectionID: string;
|
||||
|
||||
@Field({
|
||||
name: 'newTitle',
|
||||
description: 'The updated title of the collection',
|
||||
deprecationReason: 'Switch to updateTeamCollection mutation instead',
|
||||
})
|
||||
newTitle: string;
|
||||
}
|
||||
@@ -114,26 +98,3 @@ export class ReplaceTeamCollectionArgs {
|
||||
})
|
||||
parentCollectionID?: string;
|
||||
}
|
||||
|
||||
@ArgsType()
|
||||
export class UpdateTeamCollectionArgs {
|
||||
@Field(() => ID, {
|
||||
name: 'collectionID',
|
||||
description: 'ID of the collection',
|
||||
})
|
||||
collectionID: string;
|
||||
|
||||
@Field({
|
||||
name: 'newTitle',
|
||||
description: 'The updated title of the collection',
|
||||
nullable: true,
|
||||
})
|
||||
newTitle: string;
|
||||
|
||||
@Field({
|
||||
name: 'data',
|
||||
description: 'JSON string representing the collection data',
|
||||
nullable: true,
|
||||
})
|
||||
data: string;
|
||||
}
|
||||
|
||||
@@ -12,17 +12,12 @@ export class TeamCollection {
|
||||
})
|
||||
title: string;
|
||||
|
||||
@Field({
|
||||
description: 'JSON string representing the collection data',
|
||||
nullable: true,
|
||||
})
|
||||
data: string;
|
||||
|
||||
@Field(() => ID, {
|
||||
description: 'ID of the collection',
|
||||
nullable: true,
|
||||
})
|
||||
parentID: string;
|
||||
teamID: string;
|
||||
}
|
||||
|
||||
@ObjectType()
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
MoveTeamCollectionArgs,
|
||||
RenameTeamCollectionArgs,
|
||||
ReplaceTeamCollectionArgs,
|
||||
UpdateTeamCollectionArgs,
|
||||
UpdateTeamCollectionOrderArgs,
|
||||
} from './input-type.args';
|
||||
import * as E from 'fp-ts/Either';
|
||||
@@ -142,14 +141,7 @@ export class TeamCollectionResolver {
|
||||
);
|
||||
|
||||
if (E.isLeft(teamCollections)) throwErr(teamCollections.left);
|
||||
return <TeamCollection>{
|
||||
id: teamCollections.right.id,
|
||||
title: teamCollections.right.title,
|
||||
parentID: teamCollections.right.parentID,
|
||||
data: !teamCollections.right.data
|
||||
? null
|
||||
: JSON.stringify(teamCollections.right.data),
|
||||
};
|
||||
return teamCollections.right;
|
||||
}
|
||||
|
||||
// Mutations
|
||||
@@ -163,7 +155,6 @@ export class TeamCollectionResolver {
|
||||
const teamCollection = await this.teamCollectionService.createCollection(
|
||||
args.teamID,
|
||||
args.title,
|
||||
args.data,
|
||||
null,
|
||||
);
|
||||
|
||||
@@ -239,7 +230,6 @@ export class TeamCollectionResolver {
|
||||
const teamCollection = await this.teamCollectionService.createCollection(
|
||||
team.right.id,
|
||||
args.childTitle,
|
||||
args.data,
|
||||
args.collectionID,
|
||||
);
|
||||
|
||||
@@ -249,7 +239,6 @@ export class TeamCollectionResolver {
|
||||
|
||||
@Mutation(() => TeamCollection, {
|
||||
description: 'Rename a collection',
|
||||
deprecationReason: 'Switch to updateTeamCollection mutation instead',
|
||||
})
|
||||
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
||||
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
||||
@@ -314,23 +303,6 @@ export class TeamCollectionResolver {
|
||||
return request.right;
|
||||
}
|
||||
|
||||
@Mutation(() => TeamCollection, {
|
||||
description: 'Update Team Collection details',
|
||||
})
|
||||
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
||||
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
||||
async updateTeamCollection(@Args() args: UpdateTeamCollectionArgs) {
|
||||
const updatedTeamCollection =
|
||||
await this.teamCollectionService.updateTeamCollection(
|
||||
args.collectionID,
|
||||
args.data,
|
||||
args.newTitle,
|
||||
);
|
||||
|
||||
if (E.isLeft(updatedTeamCollection)) throwErr(updatedTeamCollection.left);
|
||||
return updatedTeamCollection.right;
|
||||
}
|
||||
|
||||
// Subscriptions
|
||||
|
||||
@Subscription(() => TeamCollection, {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Team, TeamCollection as DBTeamCollection } from '@prisma/client';
|
||||
import { mockDeep, mockReset } from 'jest-mock-extended';
|
||||
import {
|
||||
TEAM_COLL_DATA_INVALID,
|
||||
TEAM_COLL_DEST_SAME,
|
||||
TEAM_COLL_INVALID_JSON,
|
||||
TEAM_COLL_IS_PARENT_COLL,
|
||||
@@ -18,7 +17,6 @@ import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import { PubSubService } from 'src/pubsub/pubsub.service';
|
||||
import { AuthUser } from 'src/types/AuthUser';
|
||||
import { TeamCollectionService } from './team-collection.service';
|
||||
import { TeamCollection } from './team-collection.model';
|
||||
|
||||
const mockPrisma = mockDeep<PrismaService>();
|
||||
const mockPubSub = mockDeep<PubSubService>();
|
||||
@@ -53,60 +51,35 @@ const rootTeamCollection: DBTeamCollection = {
|
||||
id: '123',
|
||||
orderIndex: 1,
|
||||
parentID: null,
|
||||
data: {},
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
};
|
||||
|
||||
const rootTeamCollectionsCasted: TeamCollection = {
|
||||
id: rootTeamCollection.id,
|
||||
title: rootTeamCollection.title,
|
||||
parentID: rootTeamCollection.parentID,
|
||||
data: JSON.stringify(rootTeamCollection.data),
|
||||
};
|
||||
|
||||
const rootTeamCollection_2: DBTeamCollection = {
|
||||
id: 'erv',
|
||||
orderIndex: 2,
|
||||
parentID: null,
|
||||
data: {},
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
};
|
||||
|
||||
const rootTeamCollection_2Casted: TeamCollection = {
|
||||
id: 'erv',
|
||||
parentID: null,
|
||||
data: JSON.stringify(rootTeamCollection_2.data),
|
||||
title: 'Root Collection 1',
|
||||
};
|
||||
|
||||
const childTeamCollection: DBTeamCollection = {
|
||||
id: 'rfe',
|
||||
orderIndex: 1,
|
||||
parentID: rootTeamCollection.id,
|
||||
data: {},
|
||||
title: 'Child Collection 1',
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
};
|
||||
|
||||
const childTeamCollectionCasted: TeamCollection = {
|
||||
id: 'rfe',
|
||||
parentID: rootTeamCollection.id,
|
||||
data: JSON.stringify(childTeamCollection.data),
|
||||
title: 'Child Collection 1',
|
||||
};
|
||||
|
||||
const childTeamCollection_2: DBTeamCollection = {
|
||||
id: 'bgdz',
|
||||
orderIndex: 1,
|
||||
data: {},
|
||||
parentID: rootTeamCollection_2.id,
|
||||
title: 'Child Collection 1',
|
||||
teamID: team.id,
|
||||
@@ -114,20 +87,11 @@ const childTeamCollection_2: DBTeamCollection = {
|
||||
updatedOn: currentTime,
|
||||
};
|
||||
|
||||
const childTeamCollection_2Casted: TeamCollection = {
|
||||
id: 'bgdz',
|
||||
data: JSON.stringify(childTeamCollection_2.data),
|
||||
parentID: rootTeamCollection_2.id,
|
||||
title: 'Child Collection 1',
|
||||
};
|
||||
|
||||
const rootTeamCollectionList: DBTeamCollection[] = [
|
||||
{
|
||||
id: 'fdv',
|
||||
orderIndex: 1,
|
||||
parentID: null,
|
||||
data: {},
|
||||
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
@@ -138,8 +102,6 @@ const rootTeamCollectionList: DBTeamCollection[] = [
|
||||
orderIndex: 2,
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: {},
|
||||
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
@@ -149,8 +111,6 @@ const rootTeamCollectionList: DBTeamCollection[] = [
|
||||
orderIndex: 3,
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: {},
|
||||
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
@@ -159,8 +119,6 @@ const rootTeamCollectionList: DBTeamCollection[] = [
|
||||
id: 'bre3',
|
||||
orderIndex: 4,
|
||||
parentID: null,
|
||||
data: {},
|
||||
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
@@ -171,8 +129,6 @@ const rootTeamCollectionList: DBTeamCollection[] = [
|
||||
orderIndex: 5,
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: {},
|
||||
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
@@ -183,8 +139,6 @@ const rootTeamCollectionList: DBTeamCollection[] = [
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
data: {},
|
||||
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
},
|
||||
@@ -194,8 +148,6 @@ const rootTeamCollectionList: DBTeamCollection[] = [
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
data: {},
|
||||
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
},
|
||||
@@ -204,7 +156,6 @@ const rootTeamCollectionList: DBTeamCollection[] = [
|
||||
orderIndex: 8,
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: {},
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
@@ -214,7 +165,6 @@ const rootTeamCollectionList: DBTeamCollection[] = [
|
||||
orderIndex: 9,
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: {},
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
@@ -225,83 +175,17 @@ const rootTeamCollectionList: DBTeamCollection[] = [
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
data: {},
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
},
|
||||
];
|
||||
|
||||
const rootTeamCollectionListCasted: TeamCollection[] = [
|
||||
{
|
||||
id: 'fdv',
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: JSON.stringify(rootTeamCollection.data),
|
||||
},
|
||||
{
|
||||
id: 'fbbg',
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: JSON.stringify(rootTeamCollection.data),
|
||||
},
|
||||
{
|
||||
id: 'fgbfg',
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: JSON.stringify(rootTeamCollection.data),
|
||||
},
|
||||
{
|
||||
id: 'bre3',
|
||||
parentID: null,
|
||||
data: JSON.stringify(rootTeamCollection.data),
|
||||
title: 'Root Collection 1',
|
||||
},
|
||||
{
|
||||
id: 'hghgf',
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: JSON.stringify(rootTeamCollection.data),
|
||||
},
|
||||
{
|
||||
id: '123',
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: JSON.stringify(rootTeamCollection.data),
|
||||
},
|
||||
{
|
||||
id: '54tyh',
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: JSON.stringify(rootTeamCollection.data),
|
||||
},
|
||||
{
|
||||
id: '234re',
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: JSON.stringify(rootTeamCollection.data),
|
||||
},
|
||||
{
|
||||
id: '34rtg',
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: JSON.stringify(rootTeamCollection.data),
|
||||
},
|
||||
{
|
||||
id: '45tgh',
|
||||
parentID: null,
|
||||
title: 'Root Collection 1',
|
||||
data: JSON.stringify(rootTeamCollection.data),
|
||||
},
|
||||
];
|
||||
|
||||
const childTeamCollectionList: DBTeamCollection[] = [
|
||||
{
|
||||
id: '123',
|
||||
orderIndex: 1,
|
||||
parentID: rootTeamCollection.id,
|
||||
title: 'Root Collection 1',
|
||||
data: {},
|
||||
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
@@ -311,8 +195,6 @@ const childTeamCollectionList: DBTeamCollection[] = [
|
||||
orderIndex: 2,
|
||||
parentID: rootTeamCollection.id,
|
||||
title: 'Root Collection 1',
|
||||
data: {},
|
||||
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
@@ -322,8 +204,6 @@ const childTeamCollectionList: DBTeamCollection[] = [
|
||||
orderIndex: 3,
|
||||
parentID: rootTeamCollection.id,
|
||||
title: 'Root Collection 1',
|
||||
data: {},
|
||||
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
updatedOn: currentTime,
|
||||
@@ -332,8 +212,6 @@ const childTeamCollectionList: DBTeamCollection[] = [
|
||||
id: '567',
|
||||
orderIndex: 4,
|
||||
parentID: rootTeamCollection.id,
|
||||
data: {},
|
||||
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
@@ -343,8 +221,6 @@ const childTeamCollectionList: DBTeamCollection[] = [
|
||||
id: '123',
|
||||
orderIndex: 5,
|
||||
parentID: rootTeamCollection.id,
|
||||
data: {},
|
||||
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
@@ -354,8 +230,6 @@ const childTeamCollectionList: DBTeamCollection[] = [
|
||||
id: '678',
|
||||
orderIndex: 6,
|
||||
parentID: rootTeamCollection.id,
|
||||
data: {},
|
||||
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
@@ -365,8 +239,6 @@ const childTeamCollectionList: DBTeamCollection[] = [
|
||||
id: '789',
|
||||
orderIndex: 7,
|
||||
parentID: rootTeamCollection.id,
|
||||
data: {},
|
||||
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
@@ -376,8 +248,6 @@ const childTeamCollectionList: DBTeamCollection[] = [
|
||||
id: '890',
|
||||
orderIndex: 8,
|
||||
parentID: rootTeamCollection.id,
|
||||
data: {},
|
||||
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
@@ -387,7 +257,6 @@ const childTeamCollectionList: DBTeamCollection[] = [
|
||||
id: '012',
|
||||
orderIndex: 9,
|
||||
parentID: rootTeamCollection.id,
|
||||
data: {},
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
@@ -397,8 +266,6 @@ const childTeamCollectionList: DBTeamCollection[] = [
|
||||
id: '0bhu',
|
||||
orderIndex: 10,
|
||||
parentID: rootTeamCollection.id,
|
||||
data: {},
|
||||
|
||||
title: 'Root Collection 1',
|
||||
teamID: team.id,
|
||||
createdOn: currentTime,
|
||||
@@ -406,75 +273,6 @@ const childTeamCollectionList: DBTeamCollection[] = [
|
||||
},
|
||||
];
|
||||
|
||||
const childTeamCollectionListCasted: TeamCollection[] = [
|
||||
{
|
||||
id: '123',
|
||||
parentID: rootTeamCollection.id,
|
||||
title: 'Root Collection 1',
|
||||
data: JSON.stringify({}),
|
||||
},
|
||||
{
|
||||
id: '345',
|
||||
parentID: rootTeamCollection.id,
|
||||
title: 'Root Collection 1',
|
||||
data: JSON.stringify({}),
|
||||
},
|
||||
{
|
||||
id: '456',
|
||||
parentID: rootTeamCollection.id,
|
||||
title: 'Root Collection 1',
|
||||
data: JSON.stringify({}),
|
||||
},
|
||||
{
|
||||
id: '567',
|
||||
parentID: rootTeamCollection.id,
|
||||
data: JSON.stringify({}),
|
||||
|
||||
title: 'Root Collection 1',
|
||||
},
|
||||
{
|
||||
id: '123',
|
||||
parentID: rootTeamCollection.id,
|
||||
data: JSON.stringify({}),
|
||||
|
||||
title: 'Root Collection 1',
|
||||
},
|
||||
{
|
||||
id: '678',
|
||||
parentID: rootTeamCollection.id,
|
||||
data: JSON.stringify({}),
|
||||
|
||||
title: 'Root Collection 1',
|
||||
},
|
||||
{
|
||||
id: '789',
|
||||
parentID: rootTeamCollection.id,
|
||||
data: JSON.stringify({}),
|
||||
|
||||
title: 'Root Collection 1',
|
||||
},
|
||||
{
|
||||
id: '890',
|
||||
parentID: rootTeamCollection.id,
|
||||
data: JSON.stringify({}),
|
||||
|
||||
title: 'Root Collection 1',
|
||||
},
|
||||
{
|
||||
id: '012',
|
||||
parentID: rootTeamCollection.id,
|
||||
data: JSON.stringify({}),
|
||||
title: 'Root Collection 1',
|
||||
},
|
||||
{
|
||||
id: '0bhu',
|
||||
parentID: rootTeamCollection.id,
|
||||
data: JSON.stringify({}),
|
||||
|
||||
title: 'Root Collection 1',
|
||||
},
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
mockReset(mockPrisma);
|
||||
mockPubSub.publish.mockClear();
|
||||
@@ -513,7 +311,7 @@ describe('getParentOfCollection', () => {
|
||||
const result = await teamCollectionService.getParentOfCollection(
|
||||
childTeamCollection.id,
|
||||
);
|
||||
expect(result).toEqual(rootTeamCollectionsCasted);
|
||||
expect(result).toEqual(rootTeamCollection);
|
||||
});
|
||||
|
||||
test('should return null successfully for a root collection with valid collectionID', async () => {
|
||||
@@ -549,7 +347,7 @@ describe('getChildrenOfCollection', () => {
|
||||
null,
|
||||
10,
|
||||
);
|
||||
expect(result).toEqual(childTeamCollectionListCasted);
|
||||
expect(result).toEqual(childTeamCollectionList);
|
||||
});
|
||||
|
||||
test('should return a list of 3 child collections successfully with cursor being equal to the 7th item in the list', async () => {
|
||||
@@ -565,9 +363,9 @@ describe('getChildrenOfCollection', () => {
|
||||
10,
|
||||
);
|
||||
expect(result).toEqual([
|
||||
{ ...childTeamCollectionListCasted[7] },
|
||||
{ ...childTeamCollectionListCasted[8] },
|
||||
{ ...childTeamCollectionListCasted[9] },
|
||||
{ ...childTeamCollectionList[7] },
|
||||
{ ...childTeamCollectionList[8] },
|
||||
{ ...childTeamCollectionList[9] },
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -594,7 +392,7 @@ describe('getTeamRootCollections', () => {
|
||||
null,
|
||||
10,
|
||||
);
|
||||
expect(result).toEqual(rootTeamCollectionListCasted);
|
||||
expect(result).toEqual(rootTeamCollectionList);
|
||||
});
|
||||
|
||||
test('should return a list of 3 root collections successfully with cursor being equal to the 7th item in the list', async () => {
|
||||
@@ -610,9 +408,9 @@ describe('getTeamRootCollections', () => {
|
||||
10,
|
||||
);
|
||||
expect(result).toEqual([
|
||||
{ ...rootTeamCollectionListCasted[7] },
|
||||
{ ...rootTeamCollectionListCasted[8] },
|
||||
{ ...rootTeamCollectionListCasted[9] },
|
||||
{ ...rootTeamCollectionList[7] },
|
||||
{ ...rootTeamCollectionList[8] },
|
||||
{ ...rootTeamCollectionList[9] },
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -666,7 +464,6 @@ describe('createCollection', () => {
|
||||
const result = await teamCollectionService.createCollection(
|
||||
rootTeamCollection.teamID,
|
||||
'ab',
|
||||
JSON.stringify(rootTeamCollection.data),
|
||||
rootTeamCollection.id,
|
||||
);
|
||||
expect(result).toEqualLeft(TEAM_COLL_SHORT_TITLE);
|
||||
@@ -681,27 +478,11 @@ describe('createCollection', () => {
|
||||
const result = await teamCollectionService.createCollection(
|
||||
rootTeamCollection.teamID,
|
||||
'abcd',
|
||||
JSON.stringify(rootTeamCollection.data),
|
||||
rootTeamCollection.id,
|
||||
);
|
||||
expect(result).toEqualLeft(TEAM_NOT_OWNER);
|
||||
});
|
||||
|
||||
test('should throw TEAM_COLL_DATA_INVALID when parent TeamCollection does not belong to the team', async () => {
|
||||
// isOwnerCheck
|
||||
mockPrisma.teamCollection.findFirstOrThrow.mockResolvedValueOnce(
|
||||
rootTeamCollection,
|
||||
);
|
||||
|
||||
const result = await teamCollectionService.createCollection(
|
||||
rootTeamCollection.teamID,
|
||||
'abcd',
|
||||
'{',
|
||||
rootTeamCollection.id,
|
||||
);
|
||||
expect(result).toEqualLeft(TEAM_COLL_DATA_INVALID);
|
||||
});
|
||||
|
||||
test('should successfully create a new root TeamCollection with valid inputs', async () => {
|
||||
// isOwnerCheck
|
||||
mockPrisma.teamCollection.findFirstOrThrow.mockResolvedValueOnce(
|
||||
@@ -715,10 +496,9 @@ describe('createCollection', () => {
|
||||
const result = await teamCollectionService.createCollection(
|
||||
rootTeamCollection.teamID,
|
||||
'abcdefg',
|
||||
JSON.stringify(rootTeamCollection.data),
|
||||
rootTeamCollection.id,
|
||||
);
|
||||
expect(result).toEqualRight(rootTeamCollectionsCasted);
|
||||
expect(result).toEqualRight(rootTeamCollection);
|
||||
});
|
||||
|
||||
test('should successfully create a new child TeamCollection with valid inputs', async () => {
|
||||
@@ -734,10 +514,9 @@ describe('createCollection', () => {
|
||||
const result = await teamCollectionService.createCollection(
|
||||
childTeamCollection.teamID,
|
||||
childTeamCollection.title,
|
||||
JSON.stringify(rootTeamCollection.data),
|
||||
rootTeamCollection.id,
|
||||
);
|
||||
expect(result).toEqualRight(childTeamCollectionCasted);
|
||||
expect(result).toEqualRight(childTeamCollection);
|
||||
});
|
||||
|
||||
test('should send pubsub message to "team_coll/<teamID>/coll_added" if child TeamCollection is created successfully', async () => {
|
||||
@@ -753,13 +532,11 @@ describe('createCollection', () => {
|
||||
const result = await teamCollectionService.createCollection(
|
||||
childTeamCollection.teamID,
|
||||
childTeamCollection.title,
|
||||
JSON.stringify(rootTeamCollection.data),
|
||||
|
||||
rootTeamCollection.id,
|
||||
);
|
||||
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
||||
`team_coll/${childTeamCollection.teamID}/coll_added`,
|
||||
childTeamCollectionCasted,
|
||||
childTeamCollection,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -776,13 +553,11 @@ describe('createCollection', () => {
|
||||
const result = await teamCollectionService.createCollection(
|
||||
rootTeamCollection.teamID,
|
||||
'abcdefg',
|
||||
JSON.stringify(rootTeamCollection.data),
|
||||
|
||||
rootTeamCollection.id,
|
||||
);
|
||||
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
||||
`team_coll/${rootTeamCollection.teamID}/coll_added`,
|
||||
rootTeamCollectionsCasted,
|
||||
rootTeamCollection,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -812,7 +587,7 @@ describe('renameCollection', () => {
|
||||
'NewTitle',
|
||||
);
|
||||
expect(result).toEqualRight({
|
||||
...rootTeamCollectionsCasted,
|
||||
...rootTeamCollection,
|
||||
title: 'NewTitle',
|
||||
});
|
||||
});
|
||||
@@ -850,7 +625,7 @@ describe('renameCollection', () => {
|
||||
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
||||
`team_coll/${rootTeamCollection.teamID}/coll_updated`,
|
||||
{
|
||||
...rootTeamCollectionsCasted,
|
||||
...rootTeamCollection,
|
||||
title: 'NewTitle',
|
||||
},
|
||||
);
|
||||
@@ -1057,8 +832,9 @@ describe('moveCollection', () => {
|
||||
null,
|
||||
);
|
||||
expect(result).toEqualRight({
|
||||
...childTeamCollectionCasted,
|
||||
...childTeamCollection,
|
||||
parentID: null,
|
||||
orderIndex: 2,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1114,8 +890,9 @@ describe('moveCollection', () => {
|
||||
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
||||
`team_coll/${childTeamCollection.teamID}/coll_moved`,
|
||||
{
|
||||
...childTeamCollectionCasted,
|
||||
...childTeamCollection,
|
||||
parentID: null,
|
||||
orderIndex: 2,
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -1154,8 +931,9 @@ describe('moveCollection', () => {
|
||||
childTeamCollection_2.id,
|
||||
);
|
||||
expect(result).toEqualRight({
|
||||
...rootTeamCollectionsCasted,
|
||||
parentID: childTeamCollection_2Casted.id,
|
||||
...rootTeamCollection,
|
||||
parentID: childTeamCollection_2.id,
|
||||
orderIndex: 1,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1195,8 +973,9 @@ describe('moveCollection', () => {
|
||||
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
||||
`team_coll/${childTeamCollection_2.teamID}/coll_moved`,
|
||||
{
|
||||
...rootTeamCollectionsCasted,
|
||||
parentID: childTeamCollection_2Casted.id,
|
||||
...rootTeamCollection,
|
||||
parentID: childTeamCollection_2.id,
|
||||
orderIndex: 1,
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -1235,8 +1014,9 @@ describe('moveCollection', () => {
|
||||
childTeamCollection_2.id,
|
||||
);
|
||||
expect(result).toEqualRight({
|
||||
...childTeamCollectionCasted,
|
||||
parentID: childTeamCollection_2Casted.id,
|
||||
...childTeamCollection,
|
||||
parentID: childTeamCollection_2.id,
|
||||
orderIndex: 1,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1276,8 +1056,9 @@ describe('moveCollection', () => {
|
||||
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
||||
`team_coll/${childTeamCollection.teamID}/coll_moved`,
|
||||
{
|
||||
...childTeamCollectionCasted,
|
||||
parentID: childTeamCollection_2Casted.id,
|
||||
...childTeamCollection,
|
||||
parentID: childTeamCollection_2.id,
|
||||
orderIndex: 1,
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -1373,7 +1154,7 @@ describe('updateCollectionOrder', () => {
|
||||
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
||||
`team_coll/${childTeamCollectionList[4].teamID}/coll_order_updated`,
|
||||
{
|
||||
collection: rootTeamCollectionListCasted[4],
|
||||
collection: rootTeamCollectionList[4],
|
||||
nextCollection: null,
|
||||
},
|
||||
);
|
||||
@@ -1454,8 +1235,8 @@ describe('updateCollectionOrder', () => {
|
||||
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
||||
`team_coll/${childTeamCollectionList[2].teamID}/coll_order_updated`,
|
||||
{
|
||||
collection: childTeamCollectionListCasted[4],
|
||||
nextCollection: childTeamCollectionListCasted[2],
|
||||
collection: childTeamCollectionList[4],
|
||||
nextCollection: childTeamCollectionList[2],
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -1521,7 +1302,7 @@ describe('importCollectionsFromJSON', () => {
|
||||
);
|
||||
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
||||
`team_coll/${rootTeamCollection.teamID}/coll_added`,
|
||||
rootTeamCollectionsCasted,
|
||||
rootTeamCollection,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1640,7 +1421,7 @@ describe('replaceCollectionsWithJSON', () => {
|
||||
);
|
||||
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
||||
`team_coll/${rootTeamCollection.teamID}/coll_added`,
|
||||
rootTeamCollectionsCasted,
|
||||
rootTeamCollection,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1677,64 +1458,4 @@ describe('totalCollectionsInTeam', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateTeamCollection', () => {
|
||||
test('should throw TEAM_COLL_SHORT_TITLE if title is invalid', async () => {
|
||||
const result = await teamCollectionService.updateTeamCollection(
|
||||
rootTeamCollection.id,
|
||||
JSON.stringify(rootTeamCollection.data),
|
||||
'de',
|
||||
);
|
||||
expect(result).toEqualLeft(TEAM_COLL_SHORT_TITLE);
|
||||
});
|
||||
|
||||
test('should throw TEAM_COLL_DATA_INVALID is collection data is invalid', async () => {
|
||||
const result = await teamCollectionService.updateTeamCollection(
|
||||
rootTeamCollection.id,
|
||||
'{',
|
||||
rootTeamCollection.title,
|
||||
);
|
||||
expect(result).toEqualLeft(TEAM_COLL_DATA_INVALID);
|
||||
});
|
||||
|
||||
test('should throw TEAM_COLL_NOT_FOUND is collectionID is invalid', async () => {
|
||||
mockPrisma.teamCollection.update.mockRejectedValueOnce('RecordNotFound');
|
||||
|
||||
const result = await teamCollectionService.updateTeamCollection(
|
||||
'invalid_id',
|
||||
JSON.stringify(rootTeamCollection.data),
|
||||
rootTeamCollection.title,
|
||||
);
|
||||
expect(result).toEqualLeft(TEAM_COLL_NOT_FOUND);
|
||||
});
|
||||
|
||||
test('should successfully update a collection', async () => {
|
||||
mockPrisma.teamCollection.update.mockResolvedValueOnce(rootTeamCollection);
|
||||
|
||||
const result = await teamCollectionService.updateTeamCollection(
|
||||
rootTeamCollection.id,
|
||||
JSON.stringify({ foo: 'bar' }),
|
||||
'new_title',
|
||||
);
|
||||
expect(result).toEqualRight({
|
||||
data: JSON.stringify({ foo: 'bar' }),
|
||||
title: 'new_title',
|
||||
...rootTeamCollectionsCasted,
|
||||
});
|
||||
});
|
||||
|
||||
test('should send pubsub message to "team_coll/<teamID>/coll_updated" if TeamCollection is updated successfully', async () => {
|
||||
mockPrisma.teamCollection.update.mockResolvedValueOnce(rootTeamCollection);
|
||||
|
||||
const result = await teamCollectionService.updateTeamCollection(
|
||||
rootTeamCollection.id,
|
||||
JSON.stringify(rootTeamCollection.data),
|
||||
rootTeamCollection.title,
|
||||
);
|
||||
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
||||
`team_coll/${rootTeamCollection.teamID}/coll_updated`,
|
||||
rootTeamCollectionsCasted,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
//ToDo: write test cases for exportCollectionsToJSON
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
TEAM_COLL_IS_PARENT_COLL,
|
||||
TEAM_COL_SAME_NEXT_COLL,
|
||||
TEAM_COL_REORDERING_FAILED,
|
||||
TEAM_COLL_DATA_INVALID,
|
||||
} from '../errors';
|
||||
import { PubSubService } from '../pubsub/pubsub.service';
|
||||
import { isValidLength } from 'src/utils';
|
||||
@@ -70,7 +69,6 @@ export class TeamCollectionService {
|
||||
this.generatePrismaQueryObjForFBCollFolder(f, teamID, index + 1),
|
||||
),
|
||||
},
|
||||
data: folder.data ?? undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -120,7 +118,6 @@ export class TeamCollectionService {
|
||||
name: collection.right.title,
|
||||
folders: childrenCollectionObjects,
|
||||
requests: requests.map((x) => x.request),
|
||||
data: JSON.stringify(collection.right.data),
|
||||
};
|
||||
|
||||
return E.right(result);
|
||||
@@ -201,11 +198,8 @@ export class TeamCollectionService {
|
||||
),
|
||||
);
|
||||
|
||||
teamCollections.forEach((collection) =>
|
||||
this.pubsub.publish(
|
||||
`team_coll/${destTeamID}/coll_added`,
|
||||
this.cast(collection),
|
||||
),
|
||||
teamCollections.forEach((x) =>
|
||||
this.pubsub.publish(`team_coll/${destTeamID}/coll_added`, x),
|
||||
);
|
||||
|
||||
return E.right(true);
|
||||
@@ -274,11 +268,8 @@ export class TeamCollectionService {
|
||||
),
|
||||
);
|
||||
|
||||
teamCollections.forEach((collections) =>
|
||||
this.pubsub.publish(
|
||||
`team_coll/${destTeamID}/coll_added`,
|
||||
this.cast(collections),
|
||||
),
|
||||
teamCollections.forEach((x) =>
|
||||
this.pubsub.publish(`team_coll/${destTeamID}/coll_added`, x),
|
||||
);
|
||||
|
||||
return E.right(true);
|
||||
@@ -286,17 +277,11 @@ export class TeamCollectionService {
|
||||
|
||||
/**
|
||||
* Typecast a database TeamCollection to a TeamCollection model
|
||||
*
|
||||
* @param teamCollection database TeamCollection
|
||||
* @returns TeamCollection model
|
||||
*/
|
||||
private cast(teamCollection: DBTeamCollection): TeamCollection {
|
||||
return <TeamCollection>{
|
||||
id: teamCollection.id,
|
||||
title: teamCollection.title,
|
||||
parentID: teamCollection.parentID,
|
||||
data: !teamCollection.data ? null : JSON.stringify(teamCollection.data),
|
||||
};
|
||||
return <TeamCollection>{ ...teamCollection };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,7 +324,7 @@ export class TeamCollectionService {
|
||||
});
|
||||
if (!teamCollection) return null;
|
||||
|
||||
return !teamCollection.parent ? null : this.cast(teamCollection.parent);
|
||||
return teamCollection.parent;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -350,12 +335,12 @@ export class TeamCollectionService {
|
||||
* @param take Number of items we want returned
|
||||
* @returns A list of child collections
|
||||
*/
|
||||
async getChildrenOfCollection(
|
||||
getChildrenOfCollection(
|
||||
collectionID: string,
|
||||
cursor: string | null,
|
||||
take: number,
|
||||
) {
|
||||
const res = await this.prisma.teamCollection.findMany({
|
||||
return this.prisma.teamCollection.findMany({
|
||||
where: {
|
||||
parentID: collectionID,
|
||||
},
|
||||
@@ -366,12 +351,6 @@ export class TeamCollectionService {
|
||||
skip: cursor ? 1 : 0,
|
||||
cursor: cursor ? { id: cursor } : undefined,
|
||||
});
|
||||
|
||||
const childCollections = res.map((teamCollection) =>
|
||||
this.cast(teamCollection),
|
||||
);
|
||||
|
||||
return childCollections;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -387,7 +366,7 @@ export class TeamCollectionService {
|
||||
cursor: string | null,
|
||||
take: number,
|
||||
) {
|
||||
const res = await this.prisma.teamCollection.findMany({
|
||||
return this.prisma.teamCollection.findMany({
|
||||
where: {
|
||||
teamID,
|
||||
parentID: null,
|
||||
@@ -399,12 +378,6 @@ export class TeamCollectionService {
|
||||
skip: cursor ? 1 : 0,
|
||||
cursor: cursor ? { id: cursor } : undefined,
|
||||
});
|
||||
|
||||
const teamCollections = res.map((teamCollection) =>
|
||||
this.cast(teamCollection),
|
||||
);
|
||||
|
||||
return teamCollections;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -497,7 +470,6 @@ export class TeamCollectionService {
|
||||
async createCollection(
|
||||
teamID: string,
|
||||
title: string,
|
||||
data: string | null = null,
|
||||
parentTeamCollectionID: string | null,
|
||||
) {
|
||||
const isTitleValid = isValidLength(title, this.TITLE_LENGTH);
|
||||
@@ -509,13 +481,6 @@ export class TeamCollectionService {
|
||||
if (O.isNone(isOwner)) return E.left(TEAM_NOT_OWNER);
|
||||
}
|
||||
|
||||
if (data === '') return E.left(TEAM_COLL_DATA_INVALID);
|
||||
if (data) {
|
||||
const jsonReq = stringToJson(data);
|
||||
if (E.isLeft(jsonReq)) return E.left(TEAM_COLL_DATA_INVALID);
|
||||
data = jsonReq.right;
|
||||
}
|
||||
|
||||
const isParent = parentTeamCollectionID
|
||||
? {
|
||||
connect: {
|
||||
@@ -533,23 +498,18 @@ export class TeamCollectionService {
|
||||
},
|
||||
},
|
||||
parent: isParent,
|
||||
data: data ?? undefined,
|
||||
orderIndex: !parentTeamCollectionID
|
||||
? (await this.getRootCollectionsCount(teamID)) + 1
|
||||
: (await this.getChildCollectionsCount(parentTeamCollectionID)) + 1,
|
||||
},
|
||||
});
|
||||
|
||||
this.pubsub.publish(
|
||||
`team_coll/${teamID}/coll_added`,
|
||||
this.cast(teamCollection),
|
||||
);
|
||||
this.pubsub.publish(`team_coll/${teamID}/coll_added`, teamCollection);
|
||||
|
||||
return E.right(this.cast(teamCollection));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use updateTeamCollection method instead
|
||||
* Update the title of a TeamCollection
|
||||
*
|
||||
* @param collectionID The Collection ID
|
||||
@@ -572,10 +532,10 @@ export class TeamCollectionService {
|
||||
|
||||
this.pubsub.publish(
|
||||
`team_coll/${updatedTeamCollection.teamID}/coll_updated`,
|
||||
this.cast(updatedTeamCollection),
|
||||
updatedTeamCollection,
|
||||
);
|
||||
|
||||
return E.right(this.cast(updatedTeamCollection));
|
||||
return E.right(updatedTeamCollection);
|
||||
} catch (error) {
|
||||
return E.left(TEAM_COLL_NOT_FOUND);
|
||||
}
|
||||
@@ -734,8 +694,8 @@ export class TeamCollectionService {
|
||||
* @returns An Option of boolean, is parent or not
|
||||
*/
|
||||
private async isParent(
|
||||
collection: DBTeamCollection,
|
||||
destCollection: DBTeamCollection,
|
||||
collection: TeamCollection,
|
||||
destCollection: TeamCollection,
|
||||
): Promise<O.Option<boolean>> {
|
||||
//* Recursively check if collection is a parent by going up the tree of child-parent collections until we reach a root collection i.e parentID === null
|
||||
//* Valid condition, isParent returns false
|
||||
@@ -1011,49 +971,4 @@ export class TeamCollectionService {
|
||||
const teamCollectionsCount = this.prisma.teamCollection.count();
|
||||
return teamCollectionsCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Team Collection details
|
||||
*
|
||||
* @param collectionID Collection ID
|
||||
* @param collectionData new header data in a JSONified string form
|
||||
* @param newTitle New title of the collection
|
||||
* @returns Updated TeamCollection
|
||||
*/
|
||||
async updateTeamCollection(
|
||||
collectionID: string,
|
||||
collectionData: string = null,
|
||||
newTitle: string = null,
|
||||
) {
|
||||
try {
|
||||
if (newTitle != null) {
|
||||
const isTitleValid = isValidLength(newTitle, this.TITLE_LENGTH);
|
||||
if (!isTitleValid) return E.left(TEAM_COLL_SHORT_TITLE);
|
||||
}
|
||||
|
||||
if (collectionData === '') return E.left(TEAM_COLL_DATA_INVALID);
|
||||
if (collectionData) {
|
||||
const jsonReq = stringToJson(collectionData);
|
||||
if (E.isLeft(jsonReq)) return E.left(TEAM_COLL_DATA_INVALID);
|
||||
collectionData = jsonReq.right;
|
||||
}
|
||||
|
||||
const updatedTeamCollection = await this.prisma.teamCollection.update({
|
||||
where: { id: collectionID },
|
||||
data: {
|
||||
data: collectionData ?? undefined,
|
||||
title: newTitle ?? undefined,
|
||||
},
|
||||
});
|
||||
|
||||
this.pubsub.publish(
|
||||
`team_coll/${updatedTeamCollection.teamID}/coll_updated`,
|
||||
this.cast(updatedTeamCollection),
|
||||
);
|
||||
|
||||
return E.right(this.cast(updatedTeamCollection));
|
||||
} catch (e) {
|
||||
return E.left(TEAM_COLL_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@ const teamCollection: DbTeamCollection = {
|
||||
id: 'team-coll-1',
|
||||
parentID: null,
|
||||
teamID: team.id,
|
||||
data: {},
|
||||
title: 'Team Collection 1',
|
||||
orderIndex: 1,
|
||||
createdOn: new Date(),
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// This interface defines how data will be received from the app when we are importing Hoppscotch collections
|
||||
export interface CollectionFolder {
|
||||
id?: string;
|
||||
folders: CollectionFolder[];
|
||||
requests: any[];
|
||||
name: string;
|
||||
data?: string;
|
||||
}
|
||||
|
||||
@@ -6,13 +6,6 @@ import { PaginationArgs } from 'src/types/input-types.args';
|
||||
export class CreateRootUserCollectionArgs {
|
||||
@Field({ name: 'title', description: 'Title of the new user collection' })
|
||||
title: string;
|
||||
|
||||
@Field({
|
||||
name: 'data',
|
||||
description: 'JSON string representing the collection data',
|
||||
nullable: true,
|
||||
})
|
||||
data: string;
|
||||
}
|
||||
@ArgsType()
|
||||
export class CreateChildUserCollectionArgs {
|
||||
@@ -24,13 +17,6 @@ export class CreateChildUserCollectionArgs {
|
||||
description: 'ID of the parent to the new user collection',
|
||||
})
|
||||
parentUserCollectionID: string;
|
||||
|
||||
@Field({
|
||||
name: 'data',
|
||||
description: 'JSON string representing the collection data',
|
||||
nullable: true,
|
||||
})
|
||||
data: string;
|
||||
}
|
||||
|
||||
@ArgsType()
|
||||
@@ -109,26 +95,3 @@ export class ImportUserCollectionsFromJSONArgs {
|
||||
})
|
||||
parentCollectionID?: string;
|
||||
}
|
||||
|
||||
@ArgsType()
|
||||
export class UpdateUserCollectionsArgs {
|
||||
@Field(() => ID, {
|
||||
name: 'userCollectionID',
|
||||
description: 'ID of the user collection',
|
||||
})
|
||||
userCollectionID: string;
|
||||
|
||||
@Field({
|
||||
name: 'newTitle',
|
||||
description: 'The updated title of the user collection',
|
||||
nullable: true,
|
||||
})
|
||||
newTitle: string;
|
||||
|
||||
@Field({
|
||||
name: 'data',
|
||||
description: 'JSON string representing the collection data',
|
||||
nullable: true,
|
||||
})
|
||||
data: string;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import {
|
||||
MoveUserCollectionArgs,
|
||||
RenameUserCollectionsArgs,
|
||||
UpdateUserCollectionArgs,
|
||||
UpdateUserCollectionsArgs,
|
||||
} from './input-type.args';
|
||||
import { ReqType } from 'src/types/RequestTypes';
|
||||
import * as E from 'fp-ts/Either';
|
||||
@@ -143,13 +142,7 @@ export class UserCollectionResolver {
|
||||
);
|
||||
|
||||
if (E.isLeft(userCollection)) throwErr(userCollection.left);
|
||||
return <UserCollection>{
|
||||
...userCollection.right,
|
||||
userID: userCollection.right.userUid,
|
||||
data: !userCollection.right.data
|
||||
? null
|
||||
: JSON.stringify(userCollection.right.data),
|
||||
};
|
||||
return userCollection.right;
|
||||
}
|
||||
|
||||
@Query(() => UserCollectionExportJSONData, {
|
||||
@@ -198,7 +191,6 @@ export class UserCollectionResolver {
|
||||
await this.userCollectionService.createUserCollection(
|
||||
user,
|
||||
args.title,
|
||||
args.data,
|
||||
null,
|
||||
ReqType.REST,
|
||||
);
|
||||
@@ -220,7 +212,6 @@ export class UserCollectionResolver {
|
||||
await this.userCollectionService.createUserCollection(
|
||||
user,
|
||||
args.title,
|
||||
args.data,
|
||||
null,
|
||||
ReqType.GQL,
|
||||
);
|
||||
@@ -241,7 +232,6 @@ export class UserCollectionResolver {
|
||||
await this.userCollectionService.createUserCollection(
|
||||
user,
|
||||
args.title,
|
||||
args.data,
|
||||
args.parentUserCollectionID,
|
||||
ReqType.GQL,
|
||||
);
|
||||
@@ -262,7 +252,6 @@ export class UserCollectionResolver {
|
||||
await this.userCollectionService.createUserCollection(
|
||||
user,
|
||||
args.title,
|
||||
args.data,
|
||||
args.parentUserCollectionID,
|
||||
ReqType.REST,
|
||||
);
|
||||
@@ -370,26 +359,6 @@ export class UserCollectionResolver {
|
||||
return importedCollection.right;
|
||||
}
|
||||
|
||||
@Mutation(() => UserCollection, {
|
||||
description: 'Update a UserCollection',
|
||||
})
|
||||
@UseGuards(GqlAuthGuard)
|
||||
async updateUserCollection(
|
||||
@GqlUser() user: AuthUser,
|
||||
@Args() args: UpdateUserCollectionsArgs,
|
||||
) {
|
||||
const updatedUserCollection =
|
||||
await this.userCollectionService.updateUserCollection(
|
||||
args.newTitle,
|
||||
args.data,
|
||||
args.userCollectionID,
|
||||
user.uid,
|
||||
);
|
||||
|
||||
if (E.isLeft(updatedUserCollection)) throwErr(updatedUserCollection.left);
|
||||
return updatedUserCollection.right;
|
||||
}
|
||||
|
||||
// Subscriptions
|
||||
@Subscription(() => UserCollection, {
|
||||
description: 'Listen for User Collection Creation',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,6 @@ import {
|
||||
USER_NOT_FOUND,
|
||||
USER_NOT_OWNER,
|
||||
USER_COLL_INVALID_JSON,
|
||||
USER_COLL_DATA_INVALID,
|
||||
} from 'src/errors';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import { AuthUser } from 'src/types/AuthUser';
|
||||
@@ -44,12 +43,8 @@ export class UserCollectionService {
|
||||
*/
|
||||
private cast(collection: UserCollection) {
|
||||
return <UserCollectionModel>{
|
||||
id: collection.id,
|
||||
title: collection.title,
|
||||
type: collection.type,
|
||||
parentID: collection.parentID,
|
||||
...collection,
|
||||
userID: collection.userUid,
|
||||
data: !collection.data ? null : JSON.stringify(collection.data),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -151,7 +146,7 @@ export class UserCollectionService {
|
||||
},
|
||||
});
|
||||
|
||||
return !parent ? null : this.cast(parent);
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,7 +164,7 @@ export class UserCollectionService {
|
||||
take: number,
|
||||
type: ReqType,
|
||||
) {
|
||||
const res = await this.prisma.userCollection.findMany({
|
||||
return this.prisma.userCollection.findMany({
|
||||
where: {
|
||||
parentID: collectionID,
|
||||
type: type,
|
||||
@@ -181,12 +176,6 @@ export class UserCollectionService {
|
||||
skip: cursor ? 1 : 0,
|
||||
cursor: cursor ? { id: cursor } : undefined,
|
||||
});
|
||||
|
||||
const childCollections = res.map((childCollection) =>
|
||||
this.cast(childCollection),
|
||||
);
|
||||
|
||||
return childCollections;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,20 +211,12 @@ export class UserCollectionService {
|
||||
async createUserCollection(
|
||||
user: AuthUser,
|
||||
title: string,
|
||||
data: string | null = null,
|
||||
parentUserCollectionID: string | null,
|
||||
type: ReqType,
|
||||
) {
|
||||
const isTitleValid = isValidLength(title, this.TITLE_LENGTH);
|
||||
if (!isTitleValid) return E.left(USER_COLL_SHORT_TITLE);
|
||||
|
||||
if (data === '') return E.left(USER_COLL_DATA_INVALID);
|
||||
if (data) {
|
||||
const jsonReq = stringToJson(data);
|
||||
if (E.isLeft(jsonReq)) return E.left(USER_COLL_DATA_INVALID);
|
||||
data = jsonReq.right;
|
||||
}
|
||||
|
||||
// If creating a child collection
|
||||
if (parentUserCollectionID !== null) {
|
||||
const parentCollection = await this.getUserCollection(
|
||||
@@ -270,19 +251,15 @@ export class UserCollectionService {
|
||||
},
|
||||
},
|
||||
parent: isParent,
|
||||
data: data ?? undefined,
|
||||
orderIndex: !parentUserCollectionID
|
||||
? (await this.getRootCollectionsCount(user.uid)) + 1
|
||||
: (await this.getChildCollectionsCount(parentUserCollectionID)) + 1,
|
||||
},
|
||||
});
|
||||
|
||||
await this.pubsub.publish(
|
||||
`user_coll/${user.uid}/created`,
|
||||
this.cast(userCollection),
|
||||
);
|
||||
await this.pubsub.publish(`user_coll/${user.uid}/created`, userCollection);
|
||||
|
||||
return E.right(this.cast(userCollection));
|
||||
return E.right(userCollection);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,7 +276,7 @@ export class UserCollectionService {
|
||||
take: number,
|
||||
type: ReqType,
|
||||
) {
|
||||
const res = await this.prisma.userCollection.findMany({
|
||||
return this.prisma.userCollection.findMany({
|
||||
where: {
|
||||
userUid: user.uid,
|
||||
parentID: null,
|
||||
@@ -312,12 +289,6 @@ export class UserCollectionService {
|
||||
skip: cursor ? 1 : 0,
|
||||
cursor: cursor ? { id: cursor } : undefined,
|
||||
});
|
||||
|
||||
const userCollections = res.map((childCollection) =>
|
||||
this.cast(childCollection),
|
||||
);
|
||||
|
||||
return userCollections;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,7 +307,7 @@ export class UserCollectionService {
|
||||
take: number,
|
||||
type: ReqType,
|
||||
) {
|
||||
const res = await this.prisma.userCollection.findMany({
|
||||
return this.prisma.userCollection.findMany({
|
||||
where: {
|
||||
userUid: user.uid,
|
||||
parentID: userCollectionID,
|
||||
@@ -346,16 +317,9 @@ export class UserCollectionService {
|
||||
skip: cursor ? 1 : 0,
|
||||
cursor: cursor ? { id: cursor } : undefined,
|
||||
});
|
||||
|
||||
const childCollections = res.map((childCollection) =>
|
||||
this.cast(childCollection),
|
||||
);
|
||||
|
||||
return childCollections;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use updateUserCollection method instead
|
||||
* Update the title of a UserCollection
|
||||
*
|
||||
* @param newTitle The new title of collection
|
||||
@@ -387,10 +351,10 @@ export class UserCollectionService {
|
||||
|
||||
this.pubsub.publish(
|
||||
`user_coll/${updatedUserCollection.userUid}/updated`,
|
||||
this.cast(updatedUserCollection),
|
||||
updatedUserCollection,
|
||||
);
|
||||
|
||||
return E.right(this.cast(updatedUserCollection));
|
||||
return E.right(updatedUserCollection);
|
||||
} catch (error) {
|
||||
return E.left(USER_COLL_NOT_FOUND);
|
||||
}
|
||||
@@ -627,10 +591,10 @@ export class UserCollectionService {
|
||||
|
||||
this.pubsub.publish(
|
||||
`user_coll/${collection.right.userUid}/moved`,
|
||||
this.cast(updatedCollection.right),
|
||||
updatedCollection.right,
|
||||
);
|
||||
|
||||
return E.right(this.cast(updatedCollection.right));
|
||||
return E.right(updatedCollection.right);
|
||||
}
|
||||
|
||||
// destCollectionID != null i.e move into another collection
|
||||
@@ -678,10 +642,10 @@ export class UserCollectionService {
|
||||
|
||||
this.pubsub.publish(
|
||||
`user_coll/${collection.right.userUid}/moved`,
|
||||
this.cast(updatedCollection.right),
|
||||
updatedCollection.right,
|
||||
);
|
||||
|
||||
return E.right(this.cast(updatedCollection.right));
|
||||
return E.right(updatedCollection.right);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -882,7 +846,6 @@ export class UserCollectionService {
|
||||
...(x.request as Record<string, unknown>), // type casting x.request of type Prisma.JSONValue to an object to enable spread
|
||||
};
|
||||
}),
|
||||
data: JSON.stringify(collection.right.data),
|
||||
};
|
||||
|
||||
return E.right(result);
|
||||
@@ -955,7 +918,6 @@ export class UserCollectionService {
|
||||
...(x.request as Record<string, unknown>), // type casting x.request of type Prisma.JSONValue to an object to enable spread
|
||||
};
|
||||
}),
|
||||
data: JSON.stringify(parentCollection.right.data),
|
||||
}),
|
||||
collectionType: parentCollection.right.type,
|
||||
});
|
||||
@@ -1009,7 +971,6 @@ export class UserCollectionService {
|
||||
this.generatePrismaQueryObj(f, userID, index + 1, reqType),
|
||||
),
|
||||
},
|
||||
data: folder.data ?? undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1079,63 +1040,10 @@ export class UserCollectionService {
|
||||
),
|
||||
);
|
||||
|
||||
userCollections.forEach((collection) =>
|
||||
this.pubsub.publish(`user_coll/${userID}/created`, this.cast(collection)),
|
||||
userCollections.forEach((x) =>
|
||||
this.pubsub.publish(`user_coll/${userID}/created`, x),
|
||||
);
|
||||
|
||||
return E.right(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a UserCollection
|
||||
*
|
||||
* @param newTitle The new title of collection
|
||||
* @param userCollectionID The Collection Id
|
||||
* @param userID The User UID
|
||||
* @returns An Either of the updated UserCollection
|
||||
*/
|
||||
async updateUserCollection(
|
||||
newTitle: string = null,
|
||||
collectionData: string | null = null,
|
||||
userCollectionID: string,
|
||||
userID: string,
|
||||
) {
|
||||
if (collectionData === '') return E.left(USER_COLL_DATA_INVALID);
|
||||
|
||||
if (collectionData) {
|
||||
const jsonReq = stringToJson(collectionData);
|
||||
if (E.isLeft(jsonReq)) return E.left(USER_COLL_DATA_INVALID);
|
||||
collectionData = jsonReq.right;
|
||||
}
|
||||
|
||||
if (newTitle != null) {
|
||||
const isTitleValid = isValidLength(newTitle, this.TITLE_LENGTH);
|
||||
if (!isTitleValid) return E.left(USER_COLL_SHORT_TITLE);
|
||||
}
|
||||
|
||||
// Check to see is the collection belongs to the user
|
||||
const isOwner = await this.isOwnerCheck(userCollectionID, userID);
|
||||
if (O.isNone(isOwner)) return E.left(USER_NOT_OWNER);
|
||||
|
||||
try {
|
||||
const updatedUserCollection = await this.prisma.userCollection.update({
|
||||
where: {
|
||||
id: userCollectionID,
|
||||
},
|
||||
data: {
|
||||
data: collectionData ?? undefined,
|
||||
title: newTitle ?? undefined,
|
||||
},
|
||||
});
|
||||
|
||||
this.pubsub.publish(
|
||||
`user_coll/${updatedUserCollection.userUid}/updated`,
|
||||
this.cast(updatedUserCollection),
|
||||
);
|
||||
|
||||
return E.right(this.cast(updatedUserCollection));
|
||||
} catch (error) {
|
||||
return E.left(USER_COLL_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,12 +13,6 @@ export class UserCollection {
|
||||
})
|
||||
title: string;
|
||||
|
||||
@Field({
|
||||
description: 'JSON string representing the collection data',
|
||||
nullable: true,
|
||||
})
|
||||
data: string;
|
||||
|
||||
@Field(() => ReqType, {
|
||||
description: 'Type of the user collection',
|
||||
})
|
||||
|
||||
@@ -332,9 +332,13 @@
|
||||
"url": "URL"
|
||||
},
|
||||
"header": {
|
||||
"install_pwa": "Install app",
|
||||
"install_pwa": "Add to Home Screen",
|
||||
"login": "Login",
|
||||
"save_workspace": "Save My Workspace"
|
||||
"save_workspace": "Save My Workspace",
|
||||
"download_app": "Download app",
|
||||
"menu": "Menu",
|
||||
"go_back": "Go back",
|
||||
"go_forward": "Go forward"
|
||||
},
|
||||
"helpers": {
|
||||
"authorization": "The authorization header will be automatically generated when you send the request.",
|
||||
|
||||
@@ -2,25 +2,49 @@
|
||||
<div>
|
||||
<header
|
||||
ref="headerRef"
|
||||
class="flex flex-1 flex-shrink-0 items-center justify-between space-x-2 overflow-x-auto overflow-y-hidden px-2 py-2"
|
||||
class="grid grid-cols-5 grid-rows-1 gap-2 overflow-x-auto overflow-y-hidden p-2"
|
||||
@mousedown.prevent="platform.ui?.appHeader?.onHeaderAreaClick?.()"
|
||||
>
|
||||
<div
|
||||
class="inline-flex flex-1 items-center justify-start space-x-2"
|
||||
class="col-span-2 flex items-center justify-between space-x-2"
|
||||
:style="{
|
||||
paddingTop: platform.ui?.appHeader?.paddingTop?.value,
|
||||
paddingLeft: platform.ui?.appHeader?.paddingLeft?.value,
|
||||
}"
|
||||
>
|
||||
<HoppButtonSecondary
|
||||
class="!font-bold uppercase tracking-wide !text-secondaryDark hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||
:label="t('app.name')"
|
||||
to="/"
|
||||
/>
|
||||
<div class="flex">
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('header.menu')"
|
||||
:icon="IconMenu"
|
||||
class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||
/>
|
||||
<HoppButtonSecondary
|
||||
class="!font-bold uppercase tracking-wide !text-secondaryDark hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||
:label="t('app.name')"
|
||||
to="/"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('header.go_back')"
|
||||
:icon="IconArrowLeft"
|
||||
class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||
@click="router.back()"
|
||||
/>
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('header.go_forward')"
|
||||
:icon="IconArrowRight"
|
||||
class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||
@click="router.forward()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline-flex flex-1 items-center justify-center space-x-2">
|
||||
<div class="col-span-1 flex items-center justify-between space-x-2">
|
||||
<button
|
||||
class="flex max-w-[15rem] flex-1 cursor-text items-center justify-between self-stretch rounded border border-dividerDark bg-primaryDark px-2 py-1 text-secondaryLight transition hover:border-dividerDark hover:bg-primaryLight hover:text-secondary focus-visible:border-dividerDark focus-visible:bg-primaryLight focus-visible:text-secondary"
|
||||
class="flex h-full flex-1 cursor-text items-center justify-between rounded border border-dividerDark bg-primaryDark px-2 text-secondaryLight transition hover:border-dividerDark hover:bg-primaryLight hover:text-secondary focus-visible:border-dividerDark focus-visible:bg-primaryLight focus-visible:text-secondary"
|
||||
@click="invokeAction('modals.search.toggle')"
|
||||
>
|
||||
<span class="inline-flex flex-1 items-center">
|
||||
@@ -32,189 +56,221 @@
|
||||
<kbd class="shortcut-key">K</kbd>
|
||||
</span>
|
||||
</button>
|
||||
<HoppButtonSecondary
|
||||
v-if="showInstallButton"
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('header.install_pwa')"
|
||||
:icon="IconDownload"
|
||||
class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||
@click="installPWA()"
|
||||
/>
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip', allowHTML: true }"
|
||||
:title="`${
|
||||
mdAndLarger ? t('support.title') : t('app.options')
|
||||
} <kbd>?</kbd>`"
|
||||
:icon="IconLifeBuoy"
|
||||
class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||
@click="invokeAction('modals.support.toggle')"
|
||||
/>
|
||||
</div>
|
||||
<div class="inline-flex flex-1 items-center justify-end space-x-2">
|
||||
<div
|
||||
v-if="currentUser === null"
|
||||
class="inline-flex items-center space-x-2"
|
||||
>
|
||||
<div class="col-span-2 flex items-center justify-between space-x-2">
|
||||
<div class="flex">
|
||||
<HoppButtonSecondary
|
||||
:icon="IconUploadCloud"
|
||||
:label="t('header.save_workspace')"
|
||||
class="py-1.75 !focus-visible:text-green-600 !hover:text-green-600 hidden border border-green-600/25 bg-green-500/[.15] !text-green-500 hover:border-green-800/50 hover:bg-green-400/10 focus-visible:border-green-800/50 focus-visible:bg-green-400/10 md:flex"
|
||||
@click="invokeAction('modals.login.toggle')"
|
||||
v-tippy="{ theme: 'tooltip', allowHTML: true }"
|
||||
:title="`${
|
||||
mdAndLarger ? t('support.title') : t('app.options')
|
||||
} <kbd>?</kbd>`"
|
||||
:icon="IconLifeBuoy"
|
||||
class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||
@click="invokeAction('modals.support.toggle')"
|
||||
/>
|
||||
<HoppButtonPrimary
|
||||
:label="t('header.login')"
|
||||
@click="invokeAction('modals.login.toggle')"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="inline-flex items-center space-x-2">
|
||||
<TeamsMemberStack
|
||||
v-if="
|
||||
workspace.type === 'team' &&
|
||||
selectedTeam &&
|
||||
selectedTeam.teamMembers.length > 1
|
||||
"
|
||||
:team-members="selectedTeam.teamMembers"
|
||||
show-count
|
||||
class="mx-2"
|
||||
@handle-click="handleTeamEdit()"
|
||||
/>
|
||||
<div
|
||||
class="flex divide-x divide-green-600/25 rounded border border-green-600/25 bg-green-500/[.15] focus-within:divide-green-800/50 focus-within:border-green-800/50 focus-within:bg-green-400/10 hover:divide-green-800/50 hover:border-green-800/50 hover:bg-green-400/10"
|
||||
>
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('team.invite_tooltip')"
|
||||
:icon="IconUserPlus"
|
||||
class="py-1.75 !focus-visible:text-green-600 !hover:text-green-600 !text-green-500"
|
||||
@click="handleInvite()"
|
||||
/>
|
||||
<HoppButtonSecondary
|
||||
v-if="
|
||||
workspace.type === 'team' &&
|
||||
selectedTeam &&
|
||||
selectedTeam?.myRole === 'OWNER'
|
||||
"
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('team.edit')"
|
||||
:icon="IconSettings"
|
||||
class="py-1.75 !focus-visible:text-green-600 !hover:text-green-600 !text-green-500"
|
||||
@click="handleTeamEdit()"
|
||||
/>
|
||||
</div>
|
||||
<tippy
|
||||
interactive
|
||||
trigger="click"
|
||||
theme="popover"
|
||||
:on-shown="() => accountActions.focus()"
|
||||
>
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('workspace.change')"
|
||||
:label="mdAndLarger ? workspaceName : ``"
|
||||
:icon="workspace.type === 'personal' ? IconUser : IconUsers"
|
||||
class="select-wrapper !focus-visible:text-blue-600 !hover:text-blue-600 rounded border border-blue-600/25 bg-blue-500/[.15] py-[0.4375rem] pr-8 !text-blue-500 hover:border-blue-800/50 hover:bg-blue-400/10 focus-visible:border-blue-800/50 focus-visible:bg-blue-400/10"
|
||||
/>
|
||||
<template #content="{ hide }">
|
||||
<div
|
||||
ref="accountActions"
|
||||
class="flex flex-col focus:outline-none"
|
||||
tabindex="0"
|
||||
@keyup.escape="hide()"
|
||||
@click="hide()"
|
||||
>
|
||||
<WorkspaceSelector />
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
<span class="px-2">
|
||||
<span>
|
||||
<tippy
|
||||
interactive
|
||||
trigger="click"
|
||||
theme="popover"
|
||||
:on-shown="() => tippyActions.focus()"
|
||||
:on-shown="() => downloadActions.focus()"
|
||||
>
|
||||
<HoppSmartPicture
|
||||
v-if="currentUser.photoURL"
|
||||
v-tippy="{
|
||||
theme: 'tooltip',
|
||||
}"
|
||||
:url="currentUser.photoURL"
|
||||
:alt="
|
||||
currentUser.displayName ||
|
||||
t('profile.default_hopp_displayname')
|
||||
"
|
||||
:title="
|
||||
currentUser.displayName ||
|
||||
currentUser.email ||
|
||||
t('profile.default_hopp_displayname')
|
||||
"
|
||||
indicator
|
||||
:indicator-styles="
|
||||
network.isOnline ? 'bg-green-500' : 'bg-red-500'
|
||||
"
|
||||
/>
|
||||
<HoppSmartPicture
|
||||
v-else
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="
|
||||
currentUser.displayName ||
|
||||
currentUser.email ||
|
||||
t('profile.default_hopp_displayname')
|
||||
"
|
||||
:initial="currentUser.displayName || currentUser.email"
|
||||
indicator
|
||||
:indicator-styles="
|
||||
network.isOnline ? 'bg-green-500' : 'bg-red-500'
|
||||
"
|
||||
:title="t('header.download_app')"
|
||||
:icon="IconDownload"
|
||||
class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
|
||||
/>
|
||||
<template #content="{ hide }">
|
||||
<div
|
||||
ref="tippyActions"
|
||||
ref="downloadActions"
|
||||
class="flex flex-col focus:outline-none"
|
||||
tabindex="0"
|
||||
@keyup.p="profile.$el.click()"
|
||||
@keyup.s="settings.$el.click()"
|
||||
@keyup.l="logout.$el.click()"
|
||||
@keyup.escape="hide()"
|
||||
@click="hide()"
|
||||
>
|
||||
<div class="flex flex-col px-2 text-tiny">
|
||||
<span class="inline-flex truncate font-semibold">
|
||||
{{
|
||||
currentUser.displayName ||
|
||||
t("profile.default_hopp_displayname")
|
||||
}}
|
||||
</span>
|
||||
<span class="inline-flex truncate text-secondaryLight">
|
||||
{{ currentUser.email }}
|
||||
</span>
|
||||
</div>
|
||||
<hr />
|
||||
<HoppSmartItem
|
||||
ref="profile"
|
||||
to="/profile"
|
||||
:icon="IconUser"
|
||||
:label="t('navigation.profile')"
|
||||
:shortcut="['P']"
|
||||
@click="hide()"
|
||||
:label="t('header.download_app')"
|
||||
:icon="IconDownload"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
ref="settings"
|
||||
to="/settings"
|
||||
:icon="IconSettings"
|
||||
:label="t('navigation.settings')"
|
||||
:shortcut="['S']"
|
||||
@click="hide()"
|
||||
/>
|
||||
<FirebaseLogout
|
||||
ref="logout"
|
||||
:shortcut="['L']"
|
||||
@confirm-logout="hide()"
|
||||
v-if="showInstallButton"
|
||||
:label="t('header.install_pwa')"
|
||||
:icon="IconPlusSquare"
|
||||
@click="installPWA()"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div
|
||||
v-if="currentUser === null"
|
||||
class="inline-flex items-center space-x-2"
|
||||
>
|
||||
<HoppButtonSecondary
|
||||
:icon="IconUploadCloud"
|
||||
:label="t('header.save_workspace')"
|
||||
class="!focus-visible:text-emerald-600 !hover:text-emerald-600 hidden h-8 border border-emerald-600/25 bg-emerald-500/10 !text-emerald-500 hover:border-emerald-600/20 hover:bg-emerald-600/20 focus-visible:border-emerald-600/20 focus-visible:bg-emerald-600/20 md:flex"
|
||||
@click="invokeAction('modals.login.toggle')"
|
||||
/>
|
||||
<HoppButtonPrimary
|
||||
:label="t('header.login')"
|
||||
class="h-8"
|
||||
@click="invokeAction('modals.login.toggle')"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="inline-flex items-center space-x-2">
|
||||
<TeamsMemberStack
|
||||
v-if="
|
||||
workspace.type === 'team' &&
|
||||
selectedTeam &&
|
||||
selectedTeam.teamMembers.length > 1
|
||||
"
|
||||
:team-members="selectedTeam.teamMembers"
|
||||
show-count
|
||||
class="mx-2"
|
||||
@handle-click="handleTeamEdit()"
|
||||
/>
|
||||
<div
|
||||
class="flex h-8 divide-x divide-emerald-600/25 rounded border border-emerald-600/25 bg-emerald-500/10 focus-within:divide-emerald-600/20 focus-within:border-emerald-600/20 focus-within:bg-emerald-600/20 hover:divide-emerald-600/20 hover:border-emerald-600/20 hover:bg-emerald-600/20"
|
||||
>
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('team.invite_tooltip')"
|
||||
:icon="IconUserPlus"
|
||||
class="!focus-visible:text-emerald-600 !hover:text-emerald-600 !text-emerald-500"
|
||||
@click="handleInvite()"
|
||||
/>
|
||||
<HoppButtonSecondary
|
||||
v-if="
|
||||
workspace.type === 'team' &&
|
||||
selectedTeam &&
|
||||
selectedTeam?.myRole === 'OWNER'
|
||||
"
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('team.edit')"
|
||||
:icon="IconSettings"
|
||||
class="!focus-visible:text-emerald-600 !hover:text-emerald-600 !text-emerald-500"
|
||||
@click="handleTeamEdit()"
|
||||
/>
|
||||
</div>
|
||||
<tippy
|
||||
interactive
|
||||
trigger="click"
|
||||
theme="popover"
|
||||
:on-shown="() => accountActions.focus()"
|
||||
>
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('workspace.change')"
|
||||
:label="mdAndLarger ? workspaceName : ``"
|
||||
:icon="workspace.type === 'personal' ? IconUser : IconUsers"
|
||||
class="select-wrapper !focus-visible:text-blue-600 !hover:text-blue-600 h-8 rounded border border-blue-600/25 bg-blue-500/10 pr-8 !text-blue-500 hover:border-blue-600/20 hover:bg-blue-600/20 focus-visible:border-blue-600/20 focus-visible:bg-blue-600/20"
|
||||
/>
|
||||
<template #content="{ hide }">
|
||||
<div
|
||||
ref="accountActions"
|
||||
class="flex flex-col focus:outline-none"
|
||||
tabindex="0"
|
||||
@keyup.escape="hide()"
|
||||
@click="hide()"
|
||||
>
|
||||
<WorkspaceSelector />
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
<span class="px-2">
|
||||
<tippy
|
||||
interactive
|
||||
trigger="click"
|
||||
theme="popover"
|
||||
:on-shown="() => tippyActions.focus()"
|
||||
>
|
||||
<HoppSmartPicture
|
||||
v-if="currentUser.photoURL"
|
||||
v-tippy="{
|
||||
theme: 'tooltip',
|
||||
}"
|
||||
:url="currentUser.photoURL"
|
||||
:alt="
|
||||
currentUser.displayName ||
|
||||
t('profile.default_hopp_displayname')
|
||||
"
|
||||
:title="
|
||||
currentUser.displayName ||
|
||||
currentUser.email ||
|
||||
t('profile.default_hopp_displayname')
|
||||
"
|
||||
indicator
|
||||
:indicator-styles="
|
||||
network.isOnline ? 'bg-emerald-500' : 'bg-red-500'
|
||||
"
|
||||
/>
|
||||
<HoppSmartPicture
|
||||
v-else
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="
|
||||
currentUser.displayName ||
|
||||
currentUser.email ||
|
||||
t('profile.default_hopp_displayname')
|
||||
"
|
||||
:initial="currentUser.displayName || currentUser.email"
|
||||
indicator
|
||||
:indicator-styles="
|
||||
network.isOnline ? 'bg-emerald-500' : 'bg-red-500'
|
||||
"
|
||||
/>
|
||||
<template #content="{ hide }">
|
||||
<div
|
||||
ref="tippyActions"
|
||||
class="flex flex-col focus:outline-none"
|
||||
tabindex="0"
|
||||
@keyup.p="profile.$el.click()"
|
||||
@keyup.s="settings.$el.click()"
|
||||
@keyup.l="logout.$el.click()"
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<div class="flex flex-col px-2 text-tiny">
|
||||
<span class="inline-flex truncate font-semibold">
|
||||
{{
|
||||
currentUser.displayName ||
|
||||
t("profile.default_hopp_displayname")
|
||||
}}
|
||||
</span>
|
||||
<span class="inline-flex truncate text-secondaryLight">
|
||||
{{ currentUser.email }}
|
||||
</span>
|
||||
</div>
|
||||
<hr />
|
||||
<HoppSmartItem
|
||||
ref="profile"
|
||||
to="/profile"
|
||||
:icon="IconUser"
|
||||
:label="t('navigation.profile')"
|
||||
:shortcut="['P']"
|
||||
@click="hide()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
ref="settings"
|
||||
to="/settings"
|
||||
:icon="IconSettings"
|
||||
:label="t('navigation.settings')"
|
||||
:shortcut="['S']"
|
||||
@click="hide()"
|
||||
/>
|
||||
<FirebaseLogout
|
||||
ref="logout"
|
||||
:shortcut="['L']"
|
||||
@confirm-logout="hide()"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<AppBanner v-if="bannerContent" :banner="bannerContent" />
|
||||
@@ -233,7 +289,6 @@
|
||||
@invite-team="inviteTeam(editingTeamName, editingTeamID)"
|
||||
@refetch-teams="refetchTeams"
|
||||
/>
|
||||
|
||||
<HoppSmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="t('confirm.remove_team')"
|
||||
@@ -263,6 +318,10 @@ import IconUploadCloud from "~icons/lucide/upload-cloud"
|
||||
import IconUser from "~icons/lucide/user"
|
||||
import IconUserPlus from "~icons/lucide/user-plus"
|
||||
import IconUsers from "~icons/lucide/users"
|
||||
import IconPlusSquare from "~icons/lucide/plus-square"
|
||||
import IconArrowLeft from "~icons/lucide/arrow-left"
|
||||
import IconArrowRight from "~icons/lucide/arrow-right"
|
||||
import IconMenu from "~icons/lucide/align-left"
|
||||
import { pipe } from "fp-ts/function"
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
import { deleteTeam as backendDeleteTeam } from "~/helpers/backend/mutations/Team"
|
||||
@@ -271,9 +330,11 @@ import {
|
||||
BannerContent,
|
||||
BANNER_PRIORITY_HIGH,
|
||||
} from "~/services/banner.service"
|
||||
import { useRouter } from "vue-router"
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
const router = useRouter()
|
||||
|
||||
/**
|
||||
* Once the PWA code is initialized, this holds a method
|
||||
@@ -445,6 +506,7 @@ const profile = ref<any | null>(null)
|
||||
const settings = ref<any | null>(null)
|
||||
const logout = ref<any | null>(null)
|
||||
const accountActions = ref<any | null>(null)
|
||||
const downloadActions = ref<any | null>(null)
|
||||
|
||||
defineActionHandler("modals.team.edit", handleTeamEdit)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user