improvement: add search/pagination app connection select

This commit is contained in:
Scott Wilson
2025-06-26 09:21:35 -07:00
parent 3d1f054b87
commit 8ab51aba12
@@ -1,11 +1,12 @@
import { faWrench } from "@fortawesome/free-solid-svg-icons"; import { useMemo } from "react";
import { faInfoCircle, faMagnifyingGlass, faSearch } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal"; import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { Spinner, Tooltip } from "@app/components/v2"; import { EmptyState, Input, Pagination, Spinner, Tooltip } from "@app/components/v2";
import { useSubscription } from "@app/context"; import { useSubscription } from "@app/context";
import { APP_CONNECTION_MAP } from "@app/helpers/appConnections"; import { APP_CONNECTION_MAP } from "@app/helpers/appConnections";
import { usePopUp } from "@app/hooks"; import { usePagination, usePopUp, useResetPageHelper } from "@app/hooks";
import { useAppConnectionOptions } from "@app/hooks/api/appConnections"; import { useAppConnectionOptions } from "@app/hooks/api/appConnections";
import { AppConnection } from "@app/hooks/api/appConnections/enums"; import { AppConnection } from "@app/hooks/api/appConnections/enums";
@@ -19,6 +20,26 @@ export const AppConnectionsSelect = ({ onSelect }: Props) => {
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"] as const); const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"] as const);
const { search, setSearch, setPage, page, perPage, setPerPage, offset } = usePagination("", {
initPerPage: 16
});
const filteredOptions = useMemo(
() =>
appConnectionOptions?.filter(
({ name, app }) =>
name?.toLowerCase().includes(search.trim().toLowerCase()) ||
app.toLowerCase().includes(search.toLowerCase())
) ?? [],
[appConnectionOptions, search]
);
useResetPageHelper({
totalCount: filteredOptions.length,
offset,
setPage
});
if (isPending) { if (isPending) {
return ( return (
<div className="flex h-full flex-col items-center justify-center py-2.5"> <div className="flex h-full flex-col items-center justify-center py-2.5">
@@ -29,9 +50,23 @@ export const AppConnectionsSelect = ({ onSelect }: Props) => {
} }
return ( return (
<div className="grid grid-cols-4 gap-2"> <div className="flex flex-col gap-4">
{appConnectionOptions?.map((option) => { <Input
const { image, name, size = 50, enterprise = false, icon } = APP_CONNECTION_MAP[option.app]; value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search options..."
className="bg-mineshaft-800 placeholder:text-mineshaft-400"
/>
<div className="grid h-[29.5rem] grid-cols-4 content-start gap-2">
{filteredOptions.slice(offset, perPage * page)?.map((option) => {
const {
image,
name,
size = 50,
enterprise = false,
icon
} = APP_CONNECTION_MAP[option.app];
return ( return (
<button <button
@@ -66,20 +101,26 @@ export const AppConnectionsSelect = ({ onSelect }: Props) => {
</button> </button>
); );
})} })}
<UpgradePlanModal {!filteredOptions?.length && (
isOpen={popUp.upgradePlan.isOpen} <EmptyState
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)} className="col-span-full mt-40"
text="You can use every App Connection if you switch to Infisical's Enterprise plan." title="No App Connections match search"
icon={faSearch}
/> />
)}
</div>
{Boolean(filteredOptions.length) && (
<Pagination
startAdornment={
<Tooltip <Tooltip
side="bottom" side="bottom"
className="max-w-sm py-4" className="max-w-sm py-4"
content={ content={
<> <>
<p className="mb-2">Infisical is constantly adding support for more connections.</p> <p className="mb-2">Infisical is constantly adding support for more services.</p>
<p> <p>
{`If you don't see the third-party {`If you don't see the third-party
app you're looking for,`}{" "} service you're looking for,`}{" "}
<a <a
target="_blank" target="_blank"
className="underline hover:text-mineshaft-300" className="underline hover:text-mineshaft-300"
@@ -102,13 +143,27 @@ export const AppConnectionsSelect = ({ onSelect }: Props) => {
</> </>
} }
> >
<div className="group relative flex h-28 flex-col items-center justify-center rounded-md border border-dashed border-mineshaft-600 bg-mineshaft-800 p-4"> <div className="-ml-3 flex items-center gap-1.5 text-mineshaft-400">
<FontAwesomeIcon className="mt-auto text-xl" icon={faWrench} /> <span className="text-xs">
<div className="mt-auto max-w-xs text-center text-sm font-medium text-gray-300 duration-200 group-hover:text-gray-200"> Don&#39;t see the third-party service you&#39;re looking for?
Coming Soon </span>
</div> <FontAwesomeIcon size="xs" icon={faInfoCircle} />
</div> </div>
</Tooltip> </Tooltip>
}
count={filteredOptions.length}
page={page}
perPage={perPage}
onChangePage={setPage}
onChangePerPage={setPerPage}
perPageList={[16]}
/>
)}
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can use every App Connection if you switch to Infisical's Enterprise plan."
/>
</div> </div>
); );
}; };