Skip to main content
Glama
builder-header.tsx6.63 kB
import { QuestionMarkCircledIcon } from '@radix-ui/react-icons'; import { useQueryClient } from '@tanstack/react-query'; import { t } from 'i18next'; import { ChevronDown, Logs } from 'lucide-react'; import { useEffect, useState } from 'react'; import { createSearchParams, useNavigate, useSearchParams, } from 'react-router-dom'; import { LeftSideBarType, RightSideBarType, useBuilderStateContext, } from '@/app/builder/builder-hooks'; import { PageHeader } from '@/components/custom/page-header'; import { useEmbedding } from '@/components/embed-provider'; import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, } from '@/components/ui/breadcrumb'; import { Button } from '@/components/ui/button'; import EditableText from '@/components/ui/editable-text'; import { HomeButton } from '@/components/ui/home-button'; import { flowHooks } from '@/features/flows/lib/flow-hooks'; import { foldersHooks } from '@/features/folders/lib/folders-hooks'; import { useAuthorization } from '@/hooks/authorization-hooks'; import { flagsHooks } from '@/hooks/flags-hooks'; import { getProjectName, projectHooks } from '@/hooks/project-hooks'; import { authenticationSession } from '@/lib/authentication-session'; import { useNewWindow } from '@/lib/navigation-utils'; import { NEW_FLOW_QUERY_PARAM } from '@/lib/utils'; import { ApFlagId, FlowOperationType, FlowVersionState, Permission, supportUrl, UncategorizedFolderId, } from '@activepieces/shared'; import FlowActionMenu from '../../components/flow-actions-menu'; import { BuilderFlowStatusSection } from './flow-status'; export const BuilderHeader = () => { const [queryParams] = useSearchParams(); const navigate = useNavigate(); const queryClient = useQueryClient(); const openNewWindow = useNewWindow(); const { data: showSupport } = flagsHooks.useFlag<boolean>( ApFlagId.SHOW_COMMUNITY, ); const hasPermissionToReadRuns = useAuthorization().checkAccess( Permission.READ_FLOW, ); const [ flow, flowVersion, setLeftSidebar, moveToFolderClientSide, applyOperation, setRightSidebar, ] = useBuilderStateContext((state) => [ state.flow, state.flowVersion, state.setLeftSidebar, state.moveToFolderClientSide, state.applyOperation, state.setRightSidebar, ]); const { embedState } = useEmbedding(); const { project } = projectHooks.useCurrentProject(); const { data: folderData } = foldersHooks.useFolder( flow.folderId ?? UncategorizedFolderId, ); const isLatestVersion = flowVersion.state === FlowVersionState.DRAFT || flowVersion.id === flow.publishedVersionId; const [isEditingFlowName, setIsEditingFlowName] = useState(false); useEffect(() => { setIsEditingFlowName(queryParams.get(NEW_FLOW_QUERY_PARAM) === 'true'); }, []); const goToFlowsPage = () => { navigate({ pathname: authenticationSession.appendProjectRoutePrefix('/flows'), search: createSearchParams({ folderId: folderData?.id ?? UncategorizedFolderId, }).toString(), }); }; const titleContent = ( <Breadcrumb> <BreadcrumbList> {!embedState.disableNavigationInBuilder && ( <> <BreadcrumbItem> <BreadcrumbLink onClick={goToFlowsPage} className="cursor-pointer text-base" > {getProjectName(project)} </BreadcrumbLink> </BreadcrumbItem> <BreadcrumbSeparator /> </> )} {!embedState.hideFlowNameInBuilder && ( <BreadcrumbItem> <BreadcrumbPage> <div className="flex items-center gap-1 text-base"> <EditableText className="hover:cursor-text" value={flowVersion.displayName} readonly={!isLatestVersion} onValueChange={(value) => { applyOperation( { type: FlowOperationType.CHANGE_NAME, request: { displayName: value, }, }, () => { flowHooks.invalidateFlowsQuery(queryClient); }, ); }} isEditing={isEditingFlowName} setIsEditing={setIsEditingFlowName} tooltipContent="" /> <FlowActionMenu onVersionsListClick={() => { setRightSidebar(RightSideBarType.VERSIONS); }} insideBuilder={true} flow={flow} flowVersion={flowVersion} readonly={!isLatestVersion} onDelete={goToFlowsPage} onRename={() => { setIsEditingFlowName(true); }} onMoveTo={(folderId) => moveToFolderClientSide(folderId)} onDuplicate={() => {}} > <Button variant="ghost" className="size-6 flex items-center justify-center" > <ChevronDown className="h-4 w-4 text-muted-foreground" /> </Button> </FlowActionMenu> </div> </BreadcrumbPage> </BreadcrumbItem> )} </BreadcrumbList> </Breadcrumb> ); const rightContent = ( <div className="flex items-center justify-center gap-4"> {showSupport && ( <Button variant="ghost" className="gap-2 px-2" onClick={() => openNewWindow(supportUrl)} > <QuestionMarkCircledIcon className="w-4 h-4"></QuestionMarkCircledIcon> {t('Support')} </Button> )} {hasPermissionToReadRuns && ( <Button variant="ghost" onClick={() => setLeftSidebar(LeftSideBarType.RUNS)} className="gap-2 px-2" > <Logs className="w-4 h-4" /> {t('Runs')} </Button> )} <BuilderFlowStatusSection></BuilderFlowStatusSection> </div> ); const leftContent = embedState.isEmbedded ? <HomeButton /> : null; return ( <PageHeader title={titleContent} rightContent={rightContent} leftContent={leftContent} showBorder={true} className="select-none" hideSidebarTrigger={embedState.isEmbedded} /> ); };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/activepieces/activepieces'

If you have feedback or need assistance with the MCP directory API, please join our Discord server