- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
214 lines
6.5 KiB
TypeScript
214 lines
6.5 KiB
TypeScript
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}
|
|
/>
|
|
);
|
|
};
|