Skip to content

Commit ccfee03

Browse files
committed
feat: infisical, del e2e test
1 parent cf79b43 commit ccfee03

File tree

12 files changed

+114
-157
lines changed

12 files changed

+114
-157
lines changed

.github/workflows/tracker.yml

Lines changed: 0 additions & 46 deletions
This file was deleted.

.infisical.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"workspaceId": "1c57adbc-1b24-48c1-9bd7-0af6dca195b5",
3+
"defaultEnvironment": "dev",
4+
"gitBranchToEnvironmentMapping": null
5+
}

apps/api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"type": "module",
66
"private": true,
77
"scripts": {
8-
"dev": "bun --hot src/index.ts --port 3001",
8+
"dev": "infisical run -- bun --hot src/index.ts --port 3001",
99
"test": "bun test",
1010
"test:watch": "bun test --watch"
1111
},

apps/dashboard/components/layout/organization-selector.tsx

Lines changed: 55 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@ import {
88
SpinnerGapIcon,
99
UserIcon,
1010
} from "@phosphor-icons/react";
11-
import { useEffect, useRef, useState } from "react";
11+
import { useQueryClient } from "@tanstack/react-query";
12+
import { useState } from "react";
1213
import { toast } from "sonner";
1314
import { CreateOrganizationDialog } from "@/components/organizations/create-organization-dialog";
14-
import { useOrganizationsContext } from "@/components/providers/organizations-provider";
15+
import {
16+
AUTH_QUERY_KEYS,
17+
useOrganizationsContext,
18+
} from "@/components/providers/organizations-provider";
1519
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
1620
import { Button } from "@/components/ui/button";
1721
import {
@@ -32,26 +36,26 @@ const getOrganizationInitials = (name: string) =>
3236
.toUpperCase()
3337
.slice(0, 2);
3438

39+
const MENU_ITEM_BASE_CLASSES =
40+
"flex cursor-pointer items-center gap-3 px-4 py-2.5 text-sm transition-colors text-sidebar-foreground/70 hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground";
41+
const MENU_ITEM_ACTIVE_CLASSES =
42+
"bg-sidebar-accent font-medium text-sidebar-accent-foreground";
43+
3544
function filterOrganizations<T extends { name: string; slug?: string | null }>(
3645
orgs: T[] | undefined,
3746
query: string
3847
): T[] {
39-
if (!orgs || orgs.length === 0) {
48+
if (!orgs?.length) {
4049
return [];
4150
}
4251
if (!query) {
4352
return orgs;
4453
}
4554
const q = query.toLowerCase();
46-
const filtered: T[] = [];
47-
for (const org of orgs) {
48-
const nameMatch = org.name.toLowerCase().includes(q);
49-
const slugMatch = org.slug ? org.slug.toLowerCase().includes(q) : false;
50-
if (nameMatch || slugMatch) {
51-
filtered.push(org);
52-
}
53-
}
54-
return filtered;
55+
return orgs.filter(
56+
(org) =>
57+
org.name.toLowerCase().includes(q) || org.slug?.toLowerCase().includes(q)
58+
);
5559
}
5660

5761
type OrganizationSelectorTriggerProps = {
@@ -80,22 +84,20 @@ function OrganizationSelectorTrigger({
8084
>
8185
<div className="flex w-full items-center justify-between">
8286
<div className="flex items-center gap-3">
83-
<div className="rounded">
84-
<Avatar className="h-5 w-5">
85-
<AvatarImage
86-
alt={activeOrganization?.name || "Personal"}
87-
className="rounded"
88-
src={activeOrganization?.logo || undefined}
89-
/>
90-
<AvatarFallback className="bg-transparent font-medium text-xs">
91-
{activeOrganization?.name ? (
92-
getOrganizationInitials(activeOrganization.name)
93-
) : (
94-
<UserIcon className="text-sidebar-ring" weight="duotone" />
95-
)}
96-
</AvatarFallback>
97-
</Avatar>
98-
</div>
87+
<Avatar className="h-5 w-5">
88+
<AvatarImage
89+
alt={activeOrganization?.name || "Personal"}
90+
className="rounded"
91+
src={activeOrganization?.logo || undefined}
92+
/>
93+
<AvatarFallback className="bg-transparent font-medium text-xs">
94+
{activeOrganization?.name ? (
95+
getOrganizationInitials(activeOrganization.name)
96+
) : (
97+
<UserIcon className="text-sidebar-ring" weight="duotone" />
98+
)}
99+
</AvatarFallback>
100+
</Avatar>
99101
<div className="flex min-w-0 flex-1 flex-col items-start">
100102
<span className="truncate text-left font-semibold text-sidebar-accent-foreground text-sm">
101103
{activeOrganization?.name || "Personal"}
@@ -126,46 +128,20 @@ function OrganizationSelectorTrigger({
126128
}
127129

128130
export function OrganizationSelector() {
131+
const queryClient = useQueryClient();
129132
const { organizations, activeOrganization, isLoading } =
130133
useOrganizationsContext();
131134
const [isOpen, setIsOpen] = useState(false);
132135
const [showCreateDialog, setShowCreateDialog] = useState(false);
133136
const [query, setQuery] = useState("");
134137
const [isSwitching, setIsSwitching] = useState(false);
135138

136-
const prevStateRef = useRef<{
137-
isLoading: boolean;
138-
organizationsCount: number;
139-
hasActiveOrg: boolean;
140-
activeOrgName?: string;
141-
} | null>(null);
142-
143-
useEffect(() => {
144-
const currentState = {
145-
isLoading,
146-
organizationsCount: organizations.length,
147-
hasActiveOrg: !!activeOrganization,
148-
activeOrgName: activeOrganization?.name,
149-
};
150-
151-
const prevState = prevStateRef.current;
152-
if (
153-
!prevState ||
154-
prevState.isLoading !== currentState.isLoading ||
155-
prevState.organizationsCount !== currentState.organizationsCount ||
156-
prevState.hasActiveOrg !== currentState.hasActiveOrg ||
157-
prevState.activeOrgName !== currentState.activeOrgName
158-
) {
159-
console.log("[OrganizationSelector] State changed:", currentState);
160-
prevStateRef.current = currentState;
161-
}
162-
}, [isLoading, organizations.length, activeOrganization]);
163-
164139
const handleSelectOrganization = async (organizationId: string | null) => {
165-
if (organizationId === activeOrganization?.id) {
166-
return;
167-
}
168-
if (organizationId === null && !activeOrganization) {
140+
const isAlreadySelected =
141+
organizationId === activeOrganization?.id ||
142+
(organizationId === null && !activeOrganization);
143+
144+
if (isAlreadySelected) {
169145
return;
170146
}
171147

@@ -178,19 +154,20 @@ export function OrganizationSelector() {
178154

179155
if (error) {
180156
toast.error(error.message || "Failed to switch workspace");
181-
} else {
182-
toast.success("Workspace updated");
157+
setIsSwitching(false);
158+
return;
183159
}
184160

185-
setIsSwitching(false);
186-
};
161+
await queryClient.invalidateQueries({
162+
queryKey: AUTH_QUERY_KEYS.activeOrganization,
163+
});
164+
queryClient.invalidateQueries();
187165

188-
const handleCreateOrganization = () => {
189-
setShowCreateDialog(true);
190-
setIsOpen(false);
166+
setIsSwitching(false);
167+
toast.success("Workspace updated");
191168
};
192169

193-
const filteredOrganizations = filterOrganizations(organizations || [], query);
170+
const filteredOrganizations = filterOrganizations(organizations, query);
194171

195172
if (isLoading) {
196173
return (
@@ -245,10 +222,8 @@ export function OrganizationSelector() {
245222
>
246223
<DropdownMenuItem
247224
className={cn(
248-
"flex cursor-pointer items-center gap-3 px-4 py-2.5 text-sm transition-colors",
249-
"text-sidebar-foreground/70 hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground",
250-
!activeOrganization &&
251-
"bg-sidebar-accent font-medium text-sidebar-accent-foreground"
225+
MENU_ITEM_BASE_CLASSES,
226+
!activeOrganization && MENU_ITEM_ACTIVE_CLASSES
252227
)}
253228
onClick={() => handleSelectOrganization(null)}
254229
>
@@ -270,16 +245,15 @@ export function OrganizationSelector() {
270245
)}
271246
</DropdownMenuItem>
272247

273-
{filteredOrganizations && filteredOrganizations.length > 0 && (
248+
{filteredOrganizations.length > 0 && (
274249
<div className="flex flex-col">
275250
<DropdownMenuSeparator className="m-0 bg-sidebar-border p-0" />
276251
{filteredOrganizations.map((org) => (
277252
<DropdownMenuItem
278253
className={cn(
279-
"flex cursor-pointer items-center gap-3 px-4 py-2.5 text-sm transition-colors",
280-
"text-sidebar-foreground/70 hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground",
254+
MENU_ITEM_BASE_CLASSES,
281255
activeOrganization?.id === org.id &&
282-
"bg-sidebar-accent font-medium text-sidebar-accent-foreground"
256+
MENU_ITEM_ACTIVE_CLASSES
283257
)}
284258
key={org.id}
285259
onClick={() => handleSelectOrganization(org.id)}
@@ -311,8 +285,11 @@ export function OrganizationSelector() {
311285

312286
<DropdownMenuSeparator className="m-0 bg-sidebar-border p-0" />
313287
<DropdownMenuItem
314-
className="flex cursor-pointer items-center gap-3 px-4 py-2.5 text-sidebar-foreground/70 text-sm transition-colors hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground"
315-
onClick={handleCreateOrganization}
288+
className={MENU_ITEM_BASE_CLASSES}
289+
onClick={() => {
290+
setShowCreateDialog(true);
291+
setIsOpen(false);
292+
}}
316293
>
317294
<PlusIcon className="h-5 w-5 not-dark:text-primary" />
318295
<span className="font-medium text-sm">Create Organization</span>

apps/dashboard/components/providers/organizations-provider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"use client";
1+
"use client";
22

33
import { authClient } from "@databuddy/auth/client";
44
import { useQuery } from "@tanstack/react-query";

apps/dashboard/hooks/use-organizations.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { authClient } from "@databuddy/auth/client";
22
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
33
import { toast } from "sonner";
4-
import { useOrganizationsContext } from "@/components/providers/organizations-provider";
4+
import {
5+
AUTH_QUERY_KEYS,
6+
useOrganizationsContext,
7+
} from "@/components/providers/organizations-provider";
58
import { orpc } from "@/lib/orpc";
69

710
export type OrganizationRole = "owner" | "admin" | "member";
@@ -65,6 +68,14 @@ const createMutation = <TData, TVariables>(
6568
export function useOrganizations() {
6669
const { organizations, activeOrganization, isLoading } =
6770
useOrganizationsContext();
71+
const queryClient = useQueryClient();
72+
73+
const invalidateOrganizationQueries = () => {
74+
queryClient.invalidateQueries({ queryKey: AUTH_QUERY_KEYS.organizations });
75+
queryClient.invalidateQueries({
76+
queryKey: AUTH_QUERY_KEYS.activeOrganization,
77+
});
78+
};
6879

6980
const createOrganizationMutation = useMutation(
7081
createMutation(
@@ -83,7 +94,8 @@ export function useOrganizations() {
8394
return result;
8495
},
8596
"Organization created successfully",
86-
"Failed to create organization"
97+
"Failed to create organization",
98+
invalidateOrganizationQueries
8799
)
88100
);
89101

@@ -115,13 +127,15 @@ export function useOrganizations() {
115127
return result;
116128
},
117129
"Organization updated successfully",
118-
"Failed to update organization"
130+
"Failed to update organization",
131+
invalidateOrganizationQueries
119132
)
120133
);
121134

122135
const uploadOrganizationLogoMutation = useMutation({
123136
...orpc.organizations.uploadLogo.mutationOptions(),
124137
onSuccess: () => {
138+
invalidateOrganizationQueries();
125139
toast.success("Logo uploaded successfully");
126140
},
127141
onError: (error) => {
@@ -134,6 +148,7 @@ export function useOrganizations() {
134148
const deleteOrganizationLogoMutation = useMutation({
135149
...orpc.organizations.deleteLogo.mutationOptions(),
136150
onSuccess: () => {
151+
invalidateOrganizationQueries();
137152
toast.success("Logo deleted successfully");
138153
},
139154
onError: (error) => {
@@ -156,7 +171,8 @@ export function useOrganizations() {
156171
return result;
157172
},
158173
"Organization deleted successfully",
159-
"Failed to delete organization"
174+
"Failed to delete organization",
175+
invalidateOrganizationQueries
160176
)
161177
);
162178

@@ -186,6 +202,7 @@ export function useOrganizations() {
186202
return setActiveData2;
187203
},
188204
onSuccess: () => {
205+
invalidateOrganizationQueries();
189206
toast.success("Workspace updated");
190207
},
191208
onError: (error: Error) => {
@@ -214,7 +231,8 @@ export function useOrganizations() {
214231
return result;
215232
},
216233
"Left organization successfully",
217-
"Failed to leave organization"
234+
"Failed to leave organization",
235+
invalidateOrganizationQueries
218236
)
219237
);
220238

apps/dashboard/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "0.1.0",
44
"private": true,
55
"scripts": {
6-
"dev": "bun --bun next dev -p 3000",
6+
"dev": "infisical run -- bun --bun next dev -p 3000",
77
"build": "next build",
88
"start": "next start -p 3000",
99
"typecheck": "tsgo --noEmit",
@@ -39,7 +39,6 @@
3939
"ai": "^5.0.68",
4040
"autumn-js": "^0.1.40",
4141
"babel-plugin-react-compiler": "^19.1.0-rc.1-rc-af1b7da-20250421",
42-
"better-auth": "^1.3.27",
4342
"class-variance-authority": "catalog:",
4443
"clsx": "catalog:",
4544
"cmdk": "^1.1.1",

0 commit comments

Comments
 (0)