export function KaravanDesigner()

in karavan-designer/src/designer/KaravanDesigner.tsx [68:262]


export function KaravanDesigner(props: Props) {

    const [setDark, setSelectedStep, reset, badge, message, setPropertyPlaceholders, setBeans, tab, setTab, selectedStep, setSelectedUuids] =
        useDesignerStore((s) =>
            [s.setDark, s.setSelectedStep, s.reset, s.notificationBadge, s.notificationMessage, s.setPropertyPlaceholders, s.setBeans, s.tab, s.setTab, s.selectedStep, s.setSelectedUuids], shallow)
    const [integration, setIntegration, resetFiles] = useIntegrationStore((s) =>
        [s.integration, s.setIntegration, s.resetFiles], shallow)

    useEffect(() => {
        const sub = EventBus.onIntegrationUpdate()?.subscribe((update: IntegrationUpdate) =>
            save(update.integration, update.propertyOnly));
        try {
            resetErrorBoundary();
            InfrastructureAPI.setOnSaveCustomCode(props.onSaveCustomCode);
            InfrastructureAPI.setOnGetCustomCode(props.onGetCustomCode);
            InfrastructureAPI.setOnSave(props.onSave);
            InfrastructureAPI.setOnSavePropertyPlaceholder(props.onSavePropertyPlaceholder);
            InfrastructureAPI.setOnInternalConsumerClick(props.onInternalConsumerClick);
            InfrastructureAPI.setOnCreateNewRoute(props.onCreateNewRoute);

            const i = makeIntegration(props.yaml, props.filename);
            setIntegration(i, false);
            let designerTab = i.kind === 'Kamelet' ? 'kamelet' : props.tab;
            if (designerTab === undefined) {
                const counts = CamelUi.getFlowCounts(i);
                designerTab = (counts.get('routes') || 0) > 0 ? 'routes' : designerTab;
                designerTab = (counts.get('rest') || 0) > 0 ? 'rest' : designerTab;
                designerTab = (counts.get('beans') || 0) > 0 ? 'beans' : designerTab;
            }
            setTab(designerTab || 'routes')
            reset();
            setDark(props.dark);
            setPropertyPlaceholders(props.propertyPlaceholders)
            setBeans(props.beans)
            resetFiles(props.files)
            resolveSelectedStep(i);
        } catch (e: any) {
            console.error(e)
            EventBus.sendAlert(' ' + e?.name, '' + e?.message, 'danger');
        }
        return () => {
            sub?.unsubscribe();
            setSelectedStep(undefined);
            reset();
            resetErrorBoundary();
            setIntegration(Integration.createNew("demo"), false);
        };
    }, []);

    function resolveSelectedStep(i: Integration) {
        try {
            if (selectedStep) {
                const step = CamelDefinitionApiExt.findElementById(i, (selectedStep as any).id)
                if (step) {
                    setSelectedStep(step);
                    setSelectedUuids([step?.uuid])
                }
            } else {
                const r = CamelDefinitionApiExt.getFlowsOfTypes(integration, ['RouteDefinition', 'RouteTemplateDefinition'])?.at(0);
                if (r) {
                    const step = r?.dslName === 'RouteDefinition' ? (r as RouteDefinition).from : (r as RouteTemplateDefinition).route?.from;
                    if (step) {
                        setSelectedStep(step);
                        setSelectedUuids([step?.uuid])
                    }
                }
            }
        } catch (error) {
            console.error(error);
        }
    }

    function makeIntegration(yaml: string, filename: string): Integration {
        try {
            const type = CamelDefinitionYaml.yamlIsIntegration(yaml);
            if (yaml && type !== 'none') {
                const i = CamelDefinitionYaml.yamlToIntegration(props.filename, props.yaml)
                return i;
            } else {
                return Integration.createNew(filename, 'plain');
            }
        } catch (e) {
            console.error(e)
            EventBus.sendAlert("Error parsing YAML", (e as Error).message, 'danger')
            return Integration.createNew(filename, 'plain');
        }
    }

    function save(integration: Integration, propertyOnly: boolean): void {
        const code = getCode(integration);
        props.onSave(props.filename, code, propertyOnly);
    }

    function getCode(integration: Integration): string {
        try {
            const clone = CamelUtil.cloneIntegration(integration);
            return CamelDefinitionYaml.integrationToYaml(clone);
        } catch (e) {
            console.error(e)
            EventBus.sendAlert('Error parsing Yaml', (e as Error).message, 'danger');
            return '';
        }
    }

    function getTab(title: string, tooltip: string, icon: string, showBadge: boolean = false) {
        const counts = CamelUi.getFlowCounts(integration);
        const count = counts.has(icon) && counts.get(icon) ? counts.get(icon) : undefined;
        const showCount = count && count > 0;
        const color = showBadge && badge ? "red" : "initial";
        return (
            <div className="top-menu-item" style={{color: color}}>
                <TabTitleIcon>{getDesignerIcon(icon)}</TabTitleIcon>
                <TabTitleText>{title}</TabTitleText>
                {showCount && <Badge isRead className="count">{counts.get(icon)}</Badge>}
                {showBadge && badge &&
                    <Button variant="link"
                            icon={<BellIcon color="red"/>}
                            style={{visibility: (badge ? 'visible' : 'hidden'), padding: '0', margin: '0'}}
                            onClick={event => EventBus.sendAlert(message[0], message[1], 'danger')}/>
                }
            </div>
        )
    }

    const isKamelet = integration.type === 'kamelet';

    const [state, setState] = useState<ErrorBoundaryState>({ hasError: false, error: null });

    const resetErrorBoundary = () => {
        setState({ hasError: false, error: null });
    };

    // Mimic `getDerivedStateFromError`
    const handleError = (error: Error) => {
        setState({ hasError: true, error });
        setTab('code')
        console.log(props.filename, error)
    }

    useEffect(() => {
        if (state.hasError && state.error) {
            EventBus.sendAlert(state.error.message, state.error?.stack?.toString()?.substring(0, 300) || '', 'danger');
        }
    }, [state]);

    function getMainPart() {
        return (
            <PageSection variant={props.dark ? PageSectionVariants.darker : PageSectionVariants.light} className="page" isFilled padding={{default: 'noPadding'}}>
                <div className={"main-tabs-wrapper"}>
                    <Tabs className="main-tabs"
                          activeKey={tab}
                          onSelect={(event, tabIndex: string | number) => {
                              const tab = tabIndex.toString() as "routes" | "rest" | "beans" | "kamelet" | "code";
                              if (["routes", "rest", "beans", "kamelet", "code"].includes(tab)) {
                                  setTab(tab);
                              } else {
                                  setTab(undefined); // Handle unexpected values
                              }
                              setSelectedStep(undefined);
                          }}
                          style={{width: "100%"}}>
                        {isKamelet && <Tab eventKey='kamelet' title={getTab("Definitions", "Kamelet Definitions", "kamelet")}></Tab>}
                        <Tab eventKey='routes' title={getTab("Routes", "Integration flows", "routes")}></Tab>
                        {!isKamelet && <Tab eventKey='rest' title={getTab("REST", "REST services", "rest")}></Tab>}
                        <Tab eventKey='beans' title={getTab("Beans", "Beans Configuration", "beans")}></Tab>
                        {props.showCodeTab && <Tab eventKey='code' title={getTab("YAML", "YAML Code", "code", true)}></Tab>}
                    </Tabs>
                </div>
                <ErrorBoundaryWrapper onError={handleError}>
                    {tab === 'kamelet' && <KameletDesigner/>}
                    {tab === 'routes' && <RouteDesigner/>}
                    {tab === 'rest' && <RestDesigner/>}
                    {tab === 'beans' && <BeansDesigner/>}
                    {tab === 'code' && <CodeEditor/>}
                </ErrorBoundaryWrapper>
            </PageSection>
        )
    }

    return (
        (tab !== 'code' && tab !== 'kamelet')
        ? <PanelGroup direction="horizontal" style={{backgroundColor: 'white'}}>
            <Panel minSize={10} defaultSize={70}>
                {getMainPart()}
            </Panel>
            <PanelResizeHandle className='resize-handler'/>
            <Panel minSize={10} defaultSize={30}>
                {props.mainRightPanel || <MainPropertiesPanel/>}
            </Panel>
        </PanelGroup>
        : <PanelGroup direction="horizontal" style={{backgroundColor: 'white'}}>
                {getMainPart()}
            </PanelGroup>
    )
}