Skip to content

Commit 27e51c9

Browse files
committed
refactor: move checkLibraryContainsComponent out of ComponentLibraryProvider
1 parent 2e18ce1 commit 27e51c9

File tree

4 files changed

+78
-79
lines changed

4 files changed

+78
-79
lines changed

src/components/shared/Dialogs/ComponentDuplicateDialog.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ const createMockComponentLibraryContext = (
5050
removeFromComponentLibrary: vi.fn(),
5151
setComponentFavorite: vi.fn(),
5252
checkIfUserComponent: vi.fn().mockReturnValue(false),
53-
checkLibraryContainsComponent: vi.fn().mockReturnValue(false),
5453
getComponentLibrary: vi.fn(),
5554
};
5655
};

src/components/shared/FavoriteComponentToggle.tsx

Lines changed: 78 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@ import { Spinner } from "@/components/ui/spinner";
1414
import { useGuaranteedHydrateComponentReference } from "@/hooks/useHydrateComponentReference";
1515
import { cn } from "@/lib/utils";
1616
import { useComponentLibrary } from "@/providers/ComponentLibraryProvider";
17-
import { isFavoriteComponent } from "@/providers/ComponentLibraryProvider/componentLibrary";
17+
import {
18+
flattenFolders,
19+
isFavoriteComponent,
20+
} from "@/providers/ComponentLibraryProvider/componentLibrary";
1821
import { hydrateComponentReference } from "@/services/componentService";
19-
import type { ComponentReference } from "@/utils/componentSpec";
22+
import { type ComponentReference } from "@/utils/componentSpec";
23+
import { MINUTES } from "@/utils/constants";
2024
import { getComponentName } from "@/utils/getComponentName";
2125

2226
import { withSuspenseWrapper } from "./SuspenseWrapper";
@@ -132,41 +136,64 @@ const FavoriteToggleButton = withSuspenseWrapper(
132136
),
133137
);
134138

135-
export const ComponentFavoriteToggle = ({
139+
const useComponentFlags = (component: ComponentReference) => {
140+
const { checkIfUserComponent, componentLibrary } = useComponentLibrary();
141+
142+
const isUserComponent = useMemo(
143+
() => checkIfUserComponent(component),
144+
[checkIfUserComponent, component],
145+
);
146+
147+
const flatComponentList = useMemo(
148+
() => (componentLibrary ? flattenFolders(componentLibrary) : []),
149+
[componentLibrary],
150+
);
151+
152+
const { data: isInLibrary } = useSuspenseQuery({
153+
queryKey: ["component", "flags", component.digest],
154+
queryFn: async () => {
155+
if (!componentLibrary) return false;
156+
157+
for (const c of flatComponentList) {
158+
if (c.name && c.name !== component.name) {
159+
// micro optimization to skip components with different names
160+
continue;
161+
}
162+
163+
const hydratedComponent = await hydrateComponentReference(c);
164+
const digest = c.digest ?? hydratedComponent?.digest;
165+
166+
if (digest === component.digest) {
167+
return true;
168+
}
169+
}
170+
171+
return false;
172+
},
173+
staleTime: 10 * MINUTES,
174+
});
175+
176+
return { isInLibrary, isUserComponent };
177+
};
178+
179+
const ComponentFavoriteToggleInternal = ({
136180
component,
137181
hideDelete = false,
138182
}: ComponentFavoriteToggleProps) => {
139-
const {
140-
addToComponentLibrary,
141-
removeFromComponentLibrary,
142-
checkIfUserComponent,
143-
checkLibraryContainsComponent,
144-
} = useComponentLibrary();
183+
const { addToComponentLibrary, removeFromComponentLibrary } =
184+
useComponentLibrary();
145185

146186
const [isOpen, setIsOpen] = useState(false);
147187

148188
const { spec, url } = component;
149189

150-
const isUserComponent = useMemo(
151-
() => checkIfUserComponent(component),
152-
[component, checkIfUserComponent],
153-
);
154-
155-
const isInLibrary = useMemo(
156-
() => checkLibraryContainsComponent(component),
157-
[component, checkLibraryContainsComponent],
158-
);
190+
const { isInLibrary, isUserComponent } = useComponentFlags(component);
159191

160192
const displayName = useMemo(
161193
() => getComponentName({ spec, url }),
162194
[spec, url],
163195
);
164196

165-
// Delete User Components
166-
const handleDelete = useCallback(async () => {
167-
removeFromComponentLibrary(component);
168-
}, [removeFromComponentLibrary]);
169-
170197
/* Confirmation Dialog handlers */
171198
const openConfirmationDialog = useCallback(() => {
172199
setIsOpen(true);
@@ -180,7 +207,7 @@ export const ComponentFavoriteToggle = ({
180207
const handleConfirm = useCallback(async () => {
181208
setIsOpen(false);
182209

183-
if (!isInLibrary) {
210+
if (!isUserComponent) {
184211
const hydratedComponent = await hydrateComponentReference(component);
185212

186213
if (!hydratedComponent) {
@@ -189,42 +216,56 @@ export const ComponentFavoriteToggle = ({
189216
return;
190217
}
191218

192-
addToComponentLibrary(hydratedComponent);
193-
return;
219+
await addToComponentLibrary(hydratedComponent);
220+
} else {
221+
await removeFromComponentLibrary(component);
194222
}
223+
}, [
224+
component,
225+
isUserComponent,
226+
addToComponentLibrary,
227+
removeFromComponentLibrary,
228+
]);
195229

196-
handleDelete();
197-
}, [component, isInLibrary, addToComponentLibrary, handleDelete]);
198-
199-
const showDeleteButton = isInLibrary && isUserComponent && !hideDelete;
230+
const showDeleteButton = !isInLibrary && isUserComponent && !hideDelete;
200231

201232
return (
202233
<>
203-
{!isInLibrary && <AddToLibraryButton onClick={openConfirmationDialog} />}
204-
205-
{isInLibrary && !isUserComponent && (
206-
<FavoriteToggleButton component={component} />
234+
{!isInLibrary && !isUserComponent && (
235+
<AddToLibraryButton onClick={openConfirmationDialog} />
207236
)}
208237

238+
{isInLibrary && <FavoriteToggleButton component={component} />}
239+
209240
{showDeleteButton && (
210241
<DeleteFromLibraryButton onClick={openConfirmationDialog} />
211242
)}
212243

213244
<ConfirmationDialog
214245
isOpen={isOpen}
215246
title={
216-
!isInLibrary
247+
!isUserComponent
217248
? "Add to Component Library?"
218249
: "Delete custom component?"
219250
}
220251
description={
221-
!isInLibrary
252+
!isUserComponent
222253
? `This will add "${displayName}" to your Component Library for use in your pipelines.`
223-
: `"${displayName}" is a custom user component. Unstarring it will remove it from your library. This action cannot be undone.`
254+
: `"${displayName}" is a custom user component. This will remove it from your library. This action cannot be undone.`
224255
}
225256
onConfirm={handleConfirm}
226257
onCancel={handleCancel}
227258
/>
228259
</>
229260
);
230261
};
262+
263+
export const ComponentFavoriteToggle = withSuspenseWrapper(
264+
ComponentFavoriteToggleInternal,
265+
() => <Spinner size={10} />,
266+
() => (
267+
<IconStateButton disabled>
268+
<Icon name="Star" />
269+
</IconStateButton>
270+
),
271+
);

src/providers/ComponentLibraryProvider/ComponentLibraryProvider.test.tsx

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -536,29 +536,6 @@ describe("ComponentLibraryProvider - Component Management", () => {
536536
result.current.checkIfUserComponent(standardComponent);
537537
expect(isUserComponent).toBe(false);
538538
});
539-
540-
it("should correctly check if library contains component", async () => {
541-
const libraryComponent: ComponentReference = {
542-
name: "library-component",
543-
digest: "library-digest",
544-
spec: mockComponentSpec,
545-
};
546-
547-
mockFlattenFolders.mockReturnValue([libraryComponent]);
548-
mockFilterToUniqueByDigest.mockReturnValue([libraryComponent]);
549-
550-
const { result } = renderHook(() => useComponentLibrary(), {
551-
wrapper: createWrapper,
552-
});
553-
554-
await waitFor(() => {
555-
expect(result.current.isLoading).toBe(false);
556-
});
557-
558-
const containsComponent =
559-
result.current.checkLibraryContainsComponent(libraryComponent);
560-
expect(containsComponent).toBe(true);
561-
});
562539
});
563540

564541
describe("Component Favoriting", () => {

src/providers/ComponentLibraryProvider/ComponentLibraryProvider.tsx

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ type ComponentLibraryContextType = {
9696
favorited: boolean,
9797
) => void;
9898
checkIfUserComponent: (component: ComponentReference) => boolean;
99-
checkLibraryContainsComponent: (component: ComponentReference) => boolean;
10099

101100
getComponentLibrary: (libraryName: AvailableComponentLibraries) => Library;
102101
};
@@ -347,21 +346,6 @@ export const ComponentLibraryProvider = ({
347346
[userComponentsFolder],
348347
);
349348

350-
const checkLibraryContainsComponent = useCallback(
351-
(component: ComponentReference) => {
352-
if (!componentLibrary) return false;
353-
354-
if (checkIfUserComponent(component)) return true;
355-
356-
const uniqueComponents = filterToUniqueByDigest(
357-
flattenFolders(componentLibrary),
358-
);
359-
360-
return uniqueComponents.some((c) => c.digest === component.digest);
361-
},
362-
[componentLibrary, checkIfUserComponent],
363-
);
364-
365349
/**
366350
* Local component library search
367351
*/
@@ -639,7 +623,6 @@ export const ComponentLibraryProvider = ({
639623
removeFromComponentLibrary,
640624
setComponentFavorite,
641625
checkIfUserComponent,
642-
checkLibraryContainsComponent,
643626
}),
644627
[
645628
componentLibrary,
@@ -656,7 +639,6 @@ export const ComponentLibraryProvider = ({
656639
removeFromComponentLibrary,
657640
setComponentFavorite,
658641
checkIfUserComponent,
659-
checkLibraryContainsComponent,
660642
],
661643
);
662644

0 commit comments

Comments
 (0)