libs/designer/src/lib/ui/panel/templatePanel/quickViewPanel/quickViewPanel.tsx (189 lines of code) (raw):

import type { AppDispatch, RootState } from '../../../../core/state/templates/store'; import { useDispatch, useSelector } from 'react-redux'; import { Link, Text } from '@fluentui/react-components'; import { Icon, Panel, PanelType } from '@fluentui/react'; import { useIntl } from 'react-intl'; import { useCallback, useMemo, useState } from 'react'; import { TemplateContent, TemplatesPanelFooter, TemplatesPanelHeader } from '@microsoft/designer-ui'; import { getQuickViewTabs } from '../../../../core/templates/utils/helper'; import Markdown from 'react-markdown'; import { useWorkflowTemplate } from '../../../../core/state/templates/templateselectors'; import { Open16Regular } from '@fluentui/react-icons'; import { closePanel, TemplatePanelView } from '../../../../core/state/templates/panelSlice'; import { clearTemplateDetails } from '../../../../core/state/templates/templateSlice'; import { isMultiWorkflowTemplate } from '../../../../core/actions/bjsworkflow/templates'; import { useTemplatesStrings } from '../../../templates/templatesStrings'; export interface QuickViewPanelProps { showCreate: boolean; workflowId: string; clearDetailsOnClose?: boolean; panelWidth?: string; showCloseButton?: boolean; onClose?: () => void; } const layerProps = { hostId: 'msla-layer-host', eventBubblingEnabled: true, }; export const QuickViewPanel = ({ onClose, showCreate, workflowId, panelWidth = '50%', showCloseButton = true, clearDetailsOnClose = true, }: QuickViewPanelProps) => { const dispatch = useDispatch<AppDispatch>(); const intl = useIntl(); const { templateName, templateManifest, workflowAppName, isOpen, currentPanelView, shouldCloseByDefault } = useSelector( (state: RootState) => ({ templateName: state.template.templateName, templateManifest: state.template.manifest, workflowAppName: state.workflow.workflowAppName, isOpen: state.panel.isOpen, currentPanelView: state.panel.currentPanelView, shouldCloseByDefault: !state.templateOptions.viewTemplateDetails, }) ); const workflowTemplate = useWorkflowTemplate(workflowId); const manifest = useMemo(() => workflowTemplate?.manifest, [workflowTemplate]); const panelTabs = getQuickViewTabs( intl, dispatch, workflowId, clearDetailsOnClose, { templateId: templateName ?? '', workflowAppName, isMultiWorkflow: false, showCreate, showCloseButton, }, onClose ); const [selectedTabId, setSelectedTabId] = useState<string>(panelTabs[0]?.id); const dismissPanel = useCallback(() => { dispatch(closePanel()); if (clearDetailsOnClose) { dispatch(clearTemplateDetails()); } onClose?.(); }, [clearDetailsOnClose, dispatch, onClose]); const onRenderHeaderContent = useCallback( () => ( <QuickViewPanelHeader title={manifest?.title ?? ''} summary={manifest?.summary ?? ''} sourceCodeUrl={manifest?.sourceCodeUrl} isMultiWorkflowTemplate={isMultiWorkflowTemplate(templateManifest)} details={templateManifest?.details ?? {}} /> ), [templateManifest, manifest] ); const selectedTabProps = selectedTabId ? panelTabs?.find((tab) => tab.id === selectedTabId) : panelTabs[0]; const onRenderFooterContent = useCallback( () => (selectedTabProps?.footerContent ? <TemplatesPanelFooter {...selectedTabProps?.footerContent} /> : null), [selectedTabProps?.footerContent] ); if (!manifest) { return null; } const onTabSelected = (tabId: string): void => { setSelectedTabId(tabId); }; return ( <Panel styles={{ main: { padding: '0 20px', zIndex: 1000 }, content: { paddingLeft: '0px' } }} isLightDismiss={shouldCloseByDefault} type={PanelType.custom} customWidth={panelWidth} isOpen={isOpen && currentPanelView === TemplatePanelView.QuickView} onDismiss={shouldCloseByDefault ? dismissPanel : undefined} hasCloseButton={shouldCloseByDefault} onRenderHeader={onRenderHeaderContent} onRenderFooterContent={onRenderFooterContent} layerProps={layerProps} isFooterAtBottom={true} > <TemplateContent className="msla-template-quickview-tabs" tabs={panelTabs} selectedTab={selectedTabId} selectTab={onTabSelected} /> </Panel> ); }; export const QuickViewPanelHeader = ({ title, summary, sourceCodeUrl, isMultiWorkflowTemplate = false, details, features, onBackClick, }: { title: string; summary: string; sourceCodeUrl: string | undefined; details: Record<string, string>; isMultiWorkflowTemplate?: boolean; features?: string; onBackClick?: () => void; }) => { const intl = useIntl(); const { resourceStrings } = useTemplatesStrings(); const detailsTags: Record<string, string> = useMemo(() => { const baseDetailsTags: Record<string, string> = isMultiWorkflowTemplate ? {} : { Type: intl.formatMessage({ defaultMessage: 'Type', id: 'tjQdhq', description: 'Solution type of the template', }), }; baseDetailsTags.By = resourceStrings.BY; return baseDetailsTags; }, [isMultiWorkflowTemplate, intl, resourceStrings.BY]); return ( <TemplatesPanelHeader title={title} onBackClick={onBackClick}> <div className="msla-template-quickview-tags"> {Object.keys(detailsTags).map((key: string, index: number, array: any[]) => { return ( <div key={key}> <Text className={index === array.length - 1 ? 'msla-template-last-tag' : ''}> {detailsTags[key]}: {details[key]} </Text> {index !== array.length - 1 ? ( <Icon style={{ padding: '3px 10px 3px 10px', color: '#dedede', fontSize: 10 }} iconName="LocationDot" /> ) : null} </div> ); })} {sourceCodeUrl && ( <Link className="msla-template-quickview-source-code" href={sourceCodeUrl} target="_blank"> {intl.formatMessage({ defaultMessage: 'Source code', id: 'EFQ56R', description: 'Link to the source code of the template', })} <Open16Regular className="msla-templates-tab-source-code-icon" /> </Link> )} </div> <Markdown className="msla-template-markdown" linkTarget="_blank"> {summary} </Markdown> {features && ( <div className="msla-template-quickview-features"> <Text> {intl.formatMessage({ defaultMessage: 'Features', id: 'SZ78Xp', description: 'Title for the features section in the template overview', })} : </Text> <Markdown className="msla-template-markdown" linkTarget="_blank"> {features} </Markdown> </div> )} </TemplatesPanelHeader> ); };