@ant-design/icons#FullscreenOutlined TypeScript Examples

The following examples show how to use @ant-design/icons#FullscreenOutlined. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.tsx    From covid_dashboard with MIT License 6 votes vote down vote up
render() {
        return <div className='search-box'>
            {this.state.items.length > 0 && <div className="search-result" style={{width: this.state.size === 'small' ? 300 : 450}}>
                <div className="search-control">
                    <div className="control-btn" onClick={() => this.setState({size: this.state.size === 'small' ? 'large' : 'small'})}>{this.state.size === 'small' ? <FullscreenOutlined/> : <FullscreenExitOutlined/>}</div>
                    <div className="control-btn" onClick={() => this.setState({items: []})}><CloseCircleOutlined/></div>
                </div>
                <div className="search-items" style={{maxHeight: this.state.size === 'small' ? 350 : 500}}>
                {this.state.items.map(item => {
                    return <div key={item._id} className="search-item" onClick={() => this.onClickEvent(item)}>
                        <div className="event-type" style={{background: getEventColor(item.type)}}>{_.capitalize(item.type)}</div>
                        <div className="event-time">{item.time}</div>
                        <div className="event-title">{item.title}</div>
                    </div>
                })}
                </div>
            </div>}
            <div className="search-input">
                <Input.Search placeholder={this.props.intl.formatMessage({id: "search.placeholder"})} onChange={(e) => this.search(e.target.value)} onSearch={(text) => this.search(text)} loading={this.state.loading}/><span className='close' onClick={() => this.props.onClose && this.props.onClose()}><CloseCircleOutlined/></span>
            </div>
        </div>
    }
Example #2
Source File: BuildingPanelCommon.tsx    From condo with MIT License 6 votes vote down vote up
BuildingChooseSections: React.FC<IBuildingChooseSectionsProps> = (props) => {
    const intl = useIntl()
    const RequestFullscreenMessage = intl.formatMessage({ id: 'FullscreenRequest' })
    const ExitFullscreenMessage = intl.formatMessage({ id: 'FullscreenExit' })

    const {
        toggleFullscreen,
        isFullscreen,
        mode = 'view',
        children,
    } = props

    return (

        <Row
            css={FullscreenFooter}
            gutter={FULLSCREEN_FOOTER_GUTTER}
        >
            <Col>
                {mode === 'view' ? (
                    <Button
                        style={FULLSCREEN_BUTTON_STYLE}
                        type={'sberDefaultGradient'}
                        secondary
                        icon={isFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
                        size={'large'}
                        onClick={toggleFullscreen}
                    >
                        {isFullscreen
                            ? ExitFullscreenMessage
                            : RequestFullscreenMessage}
                    </Button>
                ) : children}
            </Col>
        </Row>

    )
}
Example #3
Source File: Tile.tsx    From ant-extensions with MIT License 5 votes vote down vote up
Tile: React.FC<ITileConfig> = React.memo((item) => {
  const { isEditing, editWidget, renderWidget, findWidget } = useContext(Context);
  const style = useMemo(
    () => ({
      color: item.color || "inherit"
    }),
    [item.color]
  );

  const [expanded, setExpanded] = useState(false);

  const widget = useMemo(() => findWidget(item.widgetId), [findWidget, item.widgetId]);

  return (
    <Item item={item} expanded={!isEditing && expanded}>
      <div className="ant-ext-pm__tileHead">
        <span style={style}>{item.iconCls && <i className={item.iconCls} />}</span>
        <label style={style}>{item.title}</label>
        <div>
          {item.info && (
            <Tooltip
              overlay={<pre dangerouslySetInnerHTML={{ __html: item.info }} />}
              overlayClassName="ant-ext-pm__tileInfo"
            >
              <button>
                <InfoCircleOutlined />
              </button>
            </Tooltip>
          )}
          {!isEditing && item.expandable && (
            <button className="ant-ext-pm__tileExpander" onClick={() => setExpanded(!expanded)}>
              {expanded ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
            </button>
          )}
          {isEditing && (
            <button onClick={() => editWidget(item.widgetId)}>
              <EditOutlined />
            </button>
          )}
        </div>
      </div>
      <div className="ant-ext-pm__tileBody">
        {!isEditing && renderWidget(item.widgetId)}
        {isEditing && widget && (
          <div style={{ placeSelf: "center", textAlign: "center" }}>
            {widget.icon}
            <div>{widget.title}</div>
          </div>
        )}
      </div>
    </Item>
  );
})
Example #4
Source File: Header.tsx    From react_admin with MIT License 4 votes vote down vote up
Headers: React.FC<Iprops> = (props) => {
  const { collapsed } = props;
  const [fullScreen, setFullScreen] = useState(false); // 当前是否是全屏状态
  // 进入全屏
  const requestFullScreen = useCallback(() => {
    const element: HTMLElement & Element = document.documentElement;
    // 判断各种浏览器,找到正确的方法
    const requestMethod =
      element.requestFullscreen || // W3C
      element.webkitRequestFullscreen || // Chrome等
      element.mozRequestFullScreen || // FireFox
      element.msRequestFullscreen; // IE11
    if (requestMethod) {
      requestMethod.call(element);
    }
    setFullScreen(true);
  }, []);

  // 退出登录
  const onMenuClick = useCallback(
    (e) => {
      // 退出按钮被点击
      if (e.key === "logout") {
        props.onLogout();
      }
    },
    [props]
  );

  // 退出全屏
  const exitFullScreen = useCallback(() => {
    // 判断各种浏览器,找到正确的方法
    const element: Document & Element = document;
    const exitMethod =
      element.exitFullscreen || // W3C
      element.mozCancelFullScreen || // firefox
      element.webkitExitFullscreen || // Chrome等
      element.msExitFullscreen; // IE11

    if (exitMethod) {
      exitMethod.call(document);
    }
    setFullScreen(false);
  }, []);
  const toggle = () => {
    props.setColl(!collapsed);
  };
  return (
    <Header className="site-layout-background header" style={{ padding: 0 }}>
      <Tooltip title={props.collapsed ? "展开菜单" : "收起菜单"}>
        {React.createElement(
          collapsed ? MenuUnfoldOutlined : MenuFoldOutlined,
          {
            className: "trigger",
            onClick: toggle,
          }
        )}
      </Tooltip>
      <div className="rightBox">
        <Tooltip placement="bottom" title={fullScreen ? "退出全屏" : "全屏"}>
          <div className="full all_center">
            {fullScreen ? (
              <FullscreenExitOutlined
                className="icon"
                onClick={exitFullScreen}
              />
            ) : (
              <FullscreenOutlined
                className="icon"
                onClick={requestFullScreen}
              />
            )}
          </div>
        </Tooltip>
        <Dropdown
          overlay={
            <Menu className="menu" selectedKeys={[]} onClick={onMenuClick}>
              <Menu.Item key="user">
                <Link to="/home/user/admin">
                  <UserOutlined />
                  个人中心
                </Link>
              </Menu.Item>
              <Menu.Item key="message">
                <Link to="/home/user/level">
                  <MessageOutlined />
                  个人设置
                </Link>
              </Menu.Item>
              <Menu.Divider />
              <Menu.Item key="logout">
                <LogoutOutlined />
                退出登录
              </Menu.Item>
            </Menu>
          }
          placement="bottomRight"
        >
          <div className="userhead all_center">
            <SmileOutlined />
            <span className="username">admin</span>
          </div>
        </Dropdown>
      </div>
    </Header>
  );
}
Example #5
Source File: DashboardHeader.tsx    From posthog-foss with MIT License 4 votes vote down vote up
export function DashboardHeader(): JSX.Element {
    const { dashboard, dashboardMode, lastDashboardModeSource } = useValues(dashboardLogic)
    const { addNewDashboard, triggerDashboardUpdate, setDashboardMode, addGraph, saveNewTag, deleteTag } =
        useActions(dashboardLogic)
    const { dashboardTags } = useValues(dashboardsLogic)
    const { nameSortedDashboards, dashboardsLoading, dashboardLoading } = useValues(dashboardsModel)
    const { pinDashboard, unpinDashboard, deleteDashboard, duplicateDashboard } = useActions(dashboardsModel)
    const { user } = useValues(userLogic)
    const [newName, setNewName] = useState(dashboard?.name || null) // Used to update the input immediately, debouncing API calls

    const nameInputRef = useRef<Input | null>(null)
    const descriptionInputRef = useRef<HTMLInputElement | null>(null)

    if (!dashboard) {
        return <div />
    }

    const actionsDefault = (
        <>
            <Dropdown
                trigger={['click']}
                overlay={
                    <Menu>
                        {dashboard.created_by && (
                            <>
                                <Menu.Item disabled>
                                    Created by {dashboard.created_by.first_name || dashboard.created_by.email || '-'} on{' '}
                                    {dayjs(dashboard.created_at).format(
                                        dayjs(dashboard.created_at).year() === dayjs().year()
                                            ? 'MMMM Do'
                                            : 'MMMM Do YYYY'
                                    )}
                                </Menu.Item>
                                <Menu.Divider />
                            </>
                        )}
                        <Menu.Item
                            icon={<EditOutlined />}
                            onClick={() => setDashboardMode(DashboardMode.Edit, DashboardEventSource.MoreDropdown)}
                        >
                            Edit mode (E)
                        </Menu.Item>
                        <Menu.Item
                            icon={<FullscreenOutlined />}
                            onClick={() =>
                                setDashboardMode(DashboardMode.Fullscreen, DashboardEventSource.MoreDropdown)
                            }
                        >
                            Full screen mode (F)
                        </Menu.Item>
                        {dashboard.pinned ? (
                            <Menu.Item
                                icon={<PushpinFilled />}
                                onClick={() => unpinDashboard(dashboard.id, DashboardEventSource.MoreDropdown)}
                            >
                                Unpin dashboard
                            </Menu.Item>
                        ) : (
                            <Menu.Item
                                icon={<PushpinOutlined />}
                                onClick={() => pinDashboard(dashboard.id, DashboardEventSource.MoreDropdown)}
                            >
                                Pin dashboard
                            </Menu.Item>
                        )}

                        <Menu.Divider />
                        <Menu.Item
                            icon={<CopyOutlined />}
                            onClick={() => duplicateDashboard({ id: dashboard.id, name: dashboard.name, show: true })}
                        >
                            Duplicate dashboard
                        </Menu.Item>
                        <Menu.Item
                            icon={<DeleteOutlined />}
                            onClick={() => deleteDashboard({ id: dashboard.id, redirect: true })}
                            danger
                        >
                            Delete dashboard
                        </Menu.Item>
                    </Menu>
                }
                placement="bottomRight"
            >
                <Button type="link" className="btn-lg-2x" data-attr="dashboard-more" icon={<EllipsisOutlined />} />
            </Dropdown>
            <Button
                type="link"
                data-attr="dashboard-edit-mode"
                icon={<EditOutlined />}
                onClick={() => setDashboardMode(DashboardMode.Edit, DashboardEventSource.DashboardHeader)}
            />
            <HotkeyButton
                onClick={() => addGraph()}
                data-attr="dashboard-add-graph-header"
                icon={<PlusOutlined />}
                hotkey="n"
                className="hide-lte-md"
            >
                New insight
            </HotkeyButton>
            <HotkeyButton
                type="primary"
                onClick={() => setDashboardMode(DashboardMode.Sharing, DashboardEventSource.DashboardHeader)}
                data-attr="dashboard-share-button"
                icon={<ShareAltOutlined />}
                hotkey="k"
            >
                Send or share
            </HotkeyButton>
        </>
    )

    const actionsPresentationMode = (
        <Button
            onClick={() => setDashboardMode(null, DashboardEventSource.DashboardHeader)}
            data-attr="dashboard-exit-presentation-mode"
            icon={<FullscreenExitOutlined />}
        >
            Exit full screen mode
        </Button>
    )

    const actionsEditMode = (
        <Button
            data-attr="dashboard-edit-mode-save"
            type="primary"
            onClick={() => setDashboardMode(null, DashboardEventSource.DashboardHeader)}
            tabIndex={10}
        >
            Finish editing
        </Button>
    )

    useEffect(() => {
        if (dashboardMode === DashboardMode.Edit) {
            if (lastDashboardModeSource === DashboardEventSource.AddDescription) {
                setTimeout(() => descriptionInputRef.current?.focus(), 10)
            } else if (!isMobile()) {
                setTimeout(() => nameInputRef.current?.focus(), 10)
            }
        }
    }, [dashboardMode])

    return (
        <>
            <div className={`dashboard-header${dashboardMode === DashboardMode.Fullscreen ? ' full-screen' : ''}`}>
                {dashboardMode === DashboardMode.Fullscreen && (
                    <FullScreen onExit={() => setDashboardMode(null, DashboardEventSource.Browser)} />
                )}
                <ShareModal
                    onCancel={() => setDashboardMode(null, DashboardEventSource.Browser)}
                    visible={dashboardMode === DashboardMode.Sharing}
                />
                {dashboardsLoading ? (
                    <Loading />
                ) : (
                    <>
                        {dashboardMode === DashboardMode.Edit ? (
                            <Input
                                placeholder="Dashboard name (e.g. Weekly KPIs)"
                                value={newName || ''}
                                size="large"
                                style={{ maxWidth: 400 }}
                                onChange={(e) => {
                                    setNewName(e.target.value) // To update the input immediately
                                    triggerDashboardUpdate({ name: e.target.value }) // This is breakpointed (i.e. debounced) to avoid multiple API calls
                                }}
                                onKeyDown={(e) => {
                                    if (e.key === 'Enter') {
                                        setDashboardMode(null, DashboardEventSource.InputEnter)
                                    }
                                }}
                                ref={nameInputRef}
                                tabIndex={0}
                            />
                        ) : (
                            <div className="dashboard-select">
                                <Select
                                    value={(dashboard?.id || undefined) as number | 'new' | undefined}
                                    onChange={(id) => {
                                        if (id === 'new') {
                                            addNewDashboard()
                                        } else {
                                            router.actions.push(urls.dashboard(id))
                                            eventUsageLogic.actions.reportDashboardDropdownNavigation()
                                        }
                                    }}
                                    bordered={false}
                                    dropdownMatchSelectWidth={false}
                                >
                                    {nameSortedDashboards.map((dash: DashboardType) => (
                                        <Select.Option key={dash.id} value={dash.id}>
                                            {dash.name || <span style={{ color: 'var(--muted)' }}>Untitled</span>}
                                            {dash.is_shared && (
                                                <Tooltip title="This dashboard is publicly shared">
                                                    <ShareAltOutlined style={{ marginLeft: 4, float: 'right' }} />
                                                </Tooltip>
                                            )}
                                        </Select.Option>
                                    ))}
                                    <Select.Option value="new">+ New Dashboard</Select.Option>
                                </Select>
                            </div>
                        )}

                        <div className="dashboard-meta">
                            {dashboardMode === DashboardMode.Edit
                                ? actionsEditMode
                                : dashboardMode === DashboardMode.Fullscreen
                                ? actionsPresentationMode
                                : actionsDefault}
                        </div>
                    </>
                )}
            </div>
            {user?.organization?.available_features?.includes(AvailableFeature.DASHBOARD_COLLABORATION) && (
                <>
                    <div className="mb" data-attr="dashboard-tags">
                        <ObjectTags
                            tags={dashboard.tags}
                            onTagSave={saveNewTag}
                            onTagDelete={deleteTag}
                            saving={dashboardLoading}
                            tagsAvailable={dashboardTags.filter((tag) => !dashboard.tags.includes(tag))}
                        />
                    </div>
                    <Description
                        item={dashboard}
                        setItemMode={setDashboardMode}
                        itemMode={dashboardMode}
                        triggerItemUpdate={triggerDashboardUpdate}
                        descriptionInputRef={descriptionInputRef}
                    />
                </>
            )}
        </>
    )
}
Example #6
Source File: Icon.tsx    From html2sketch with MIT License 4 votes vote down vote up
IconSymbol: FC = () => {
  return (
    <Row>
      {/*<CaretUpOutlined*/}
      {/*  className="icon"*/}
      {/*  symbolName={'1.General/2.Icons/1.CaretUpOutlined'}*/}
      {/*/>*/}
      {/*  className="icon"*/}
      {/*  symbolName={'1.General/2.Icons/2.MailOutlined'}*/}
      {/*/>*/}
      {/*<StepBackwardOutlined*/}
      {/*  className="icon"*/}
      {/*  symbolName={'1.General/2.Icons/2.StepBackwardOutlined'}*/}
      {/*/>*/}
      {/*<StepForwardOutlined*/}
      {/*  className="icon"*/}
      {/*  symbolName={'1.General/2.Icons/2.StepBackwardOutlined'}*/}
      {/*/>*/}
      <StepForwardOutlined />
      <ShrinkOutlined />
      <ArrowsAltOutlined />
      <DownOutlined />
      <UpOutlined />
      <LeftOutlined />
      <RightOutlined />
      <CaretUpOutlined />
      <CaretDownOutlined />
      <CaretLeftOutlined />
      <CaretRightOutlined />
      <VerticalAlignTopOutlined />
      <RollbackOutlined />
      <FastBackwardOutlined />
      <FastForwardOutlined />
      <DoubleRightOutlined />
      <DoubleLeftOutlined />
      <VerticalLeftOutlined />
      <VerticalRightOutlined />
      <VerticalAlignMiddleOutlined />
      <VerticalAlignBottomOutlined />
      <ForwardOutlined />
      <BackwardOutlined />
      <EnterOutlined />
      <RetweetOutlined />
      <SwapOutlined />
      <SwapLeftOutlined />
      <SwapRightOutlined />
      <ArrowUpOutlined />
      <ArrowDownOutlined />
      <ArrowLeftOutlined />
      <ArrowRightOutlined />
      <LoginOutlined />
      <LogoutOutlined />
      <MenuFoldOutlined />
      <MenuUnfoldOutlined />
      <BorderBottomOutlined />
      <BorderHorizontalOutlined />
      <BorderInnerOutlined />
      <BorderOuterOutlined />
      <BorderLeftOutlined />
      <BorderRightOutlined />
      <BorderTopOutlined />
      <BorderVerticleOutlined />
      <PicCenterOutlined />
      <PicLeftOutlined />
      <PicRightOutlined />
      <RadiusBottomleftOutlined />
      <RadiusBottomrightOutlined />
      <RadiusUpleftOutlined />
      <RadiusUprightOutlined />
      <FullscreenOutlined />
      <FullscreenExitOutlined />
      <QuestionOutlined />
      <PauseOutlined />
      <MinusOutlined />
      <PauseCircleOutlined />
      <InfoOutlined />
      <CloseOutlined />
      <ExclamationOutlined />
      <CheckOutlined />
      <WarningOutlined />
      <IssuesCloseOutlined />
      <StopOutlined />
      <EditOutlined />
      <CopyOutlined />
      <ScissorOutlined />
      <DeleteOutlined />
      <SnippetsOutlined />
      <DiffOutlined />
      <HighlightOutlined />
      <AlignCenterOutlined />
      <AlignLeftOutlined />
      <AlignRightOutlined />
      <BgColorsOutlined />
      <BoldOutlined />
      <ItalicOutlined />
      <UnderlineOutlined />
      <StrikethroughOutlined />
      <RedoOutlined />
      <UndoOutlined />
      <ZoomInOutlined />
      <ZoomOutOutlined />
      <FontColorsOutlined />
      <FontSizeOutlined />
      <LineHeightOutlined />
      <SortAscendingOutlined />
      <SortDescendingOutlined />
      <DragOutlined />
      <OrderedListOutlined />
      <UnorderedListOutlined />
      <RadiusSettingOutlined />
      <ColumnWidthOutlined />
      <ColumnHeightOutlined />
      <AreaChartOutlined />
      <PieChartOutlined />
      <BarChartOutlined />
      <DotChartOutlined />
      <LineChartOutlined />
      <RadarChartOutlined />
      <HeatMapOutlined />
      <FallOutlined />
      <RiseOutlined />
      <StockOutlined />
      <BoxPlotOutlined />
      <FundOutlined />
      <SlidersOutlined />
      <AndroidOutlined />
      <AppleOutlined />
      <WindowsOutlined />
      <IeOutlined />
      <ChromeOutlined />
      <GithubOutlined />
      <AliwangwangOutlined />
      <DingdingOutlined />
      <WeiboSquareOutlined />
      <WeiboCircleOutlined />
      <TaobaoCircleOutlined />
      <Html5Outlined />
      <WeiboOutlined />
      <TwitterOutlined />
      <WechatOutlined />
      <AlipayCircleOutlined />
      <TaobaoOutlined />
      <SkypeOutlined />
      <FacebookOutlined />
      <CodepenOutlined />
      <CodeSandboxOutlined />
      <AmazonOutlined />
      <GoogleOutlined />
      <AlipayOutlined />
      <AntDesignOutlined />
      <AntCloudOutlined />
      <ZhihuOutlined />
      <SlackOutlined />
      <SlackSquareOutlined />
      <BehanceSquareOutlined />
      <DribbbleOutlined />
      <DribbbleSquareOutlined />
      <InstagramOutlined />
      <YuqueOutlined />
      <AlibabaOutlined />
      <YahooOutlined />
      <RedditOutlined />
      <SketchOutlined />
      <AccountBookOutlined />
      <AlertOutlined />
      <ApartmentOutlined />
      <ApiOutlined />
      <QqOutlined />
      <MediumWorkmarkOutlined />
      <GitlabOutlined />
      <MediumOutlined />
      <GooglePlusOutlined />
      <AppstoreAddOutlined />
      <AppstoreOutlined />
      <AudioOutlined />
      <AudioMutedOutlined />
      <AuditOutlined />
      <BankOutlined />
      <BarcodeOutlined />
      <BarsOutlined />
      <BellOutlined />
      <BlockOutlined />
      <BookOutlined />
      <BorderOutlined />
      <BranchesOutlined />
      <BuildOutlined />
      <BulbOutlined />
      <CalculatorOutlined />
      <CalendarOutlined />
      <CameraOutlined />
      <CarOutlined />
      <CarryOutOutlined />
      <CiCircleOutlined />
      <CiOutlined />
      <CloudOutlined />
      <ClearOutlined />
      <ClusterOutlined />
      <CodeOutlined />
      <CoffeeOutlined />
      <CompassOutlined />
      <CompressOutlined />
      <ContactsOutlined />
      <ContainerOutlined />
      <ControlOutlined />
      <CopyrightCircleOutlined />
      <CopyrightOutlined />
      <CreditCardOutlined />
      <CrownOutlined />
      <CustomerServiceOutlined />
      <DashboardOutlined />
      <DatabaseOutlined />
      <DeleteColumnOutlined />
      <DeleteRowOutlined />
      <DisconnectOutlined />
      <DislikeOutlined />
      <DollarCircleOutlined />
      <DollarOutlined />
      <DownloadOutlined />
      <EllipsisOutlined />
      <EnvironmentOutlined />
      <EuroCircleOutlined />
      <EuroOutlined />
      <ExceptionOutlined />
      <ExpandAltOutlined />
      <ExpandOutlined />
      <ExperimentOutlined />
      <ExportOutlined />
      <EyeOutlined />
      <FieldBinaryOutlined />
      <FieldNumberOutlined />
      <FieldStringOutlined />
      <DesktopOutlined />
      <DingtalkOutlined />
      <FileAddOutlined />
      <FileDoneOutlined />
      <FileExcelOutlined />
      <FileExclamationOutlined />
      <FileOutlined />
      <FileImageOutlined />
      <FileJpgOutlined />
      <FileMarkdownOutlined />
      <FilePdfOutlined />
      <FilePptOutlined />
      <FileProtectOutlined />
      <FileSearchOutlined />
      <FileSyncOutlined />
      <FileTextOutlined />
      <FileUnknownOutlined />
      <FileWordOutlined />
      <FilterOutlined />
      <FireOutlined />
      <FlagOutlined />
      <FolderAddOutlined />
      <FolderOutlined />
      <FolderOpenOutlined />
      <ForkOutlined />
      <FormatPainterOutlined />
      <FrownOutlined />
      <FunctionOutlined />
      <FunnelPlotOutlined />
      <GatewayOutlined />
      <GifOutlined />
      <GiftOutlined />
      <GlobalOutlined />
      <GoldOutlined />
      <GroupOutlined />
      <HddOutlined />
      <HeartOutlined />
      <HistoryOutlined />
      <HomeOutlined />
      <HourglassOutlined />
      <IdcardOutlined />
      <ImportOutlined />
      <InboxOutlined />
      <InsertRowAboveOutlined />
      <InsertRowBelowOutlined />
      <InsertRowLeftOutlined />
      <InsertRowRightOutlined />
      <InsuranceOutlined />
      <InteractionOutlined />
      <KeyOutlined />
      <LaptopOutlined />
      <LayoutOutlined />
      <LikeOutlined />
      <LineOutlined />
      <LinkOutlined />
      <Loading3QuartersOutlined />
      <LoadingOutlined />
      <LockOutlined />
      <MailOutlined />
      <ManOutlined />
      <MedicineBoxOutlined />
      <MehOutlined />
      <MenuOutlined />
      <MergeCellsOutlined />
      <MessageOutlined />
      <MobileOutlined />
      <MoneyCollectOutlined />
      <MonitorOutlined />
      <MoreOutlined />
      <NodeCollapseOutlined />
      <NodeExpandOutlined />
      <NodeIndexOutlined />
      <NotificationOutlined />
      <NumberOutlined />
      <PaperClipOutlined />
      <PartitionOutlined />
      <PayCircleOutlined />
      <PercentageOutlined />
      <PhoneOutlined />
      <PictureOutlined />
      <PoundCircleOutlined />
      <PoundOutlined />
      <PoweroffOutlined />
      <PrinterOutlined />
      <ProfileOutlined />
      <ProjectOutlined />
      <PropertySafetyOutlined />
      <PullRequestOutlined />
      <PushpinOutlined />
      <QrcodeOutlined />
      <ReadOutlined />
      <ReconciliationOutlined />
      <RedEnvelopeOutlined />
      <ReloadOutlined />
      <RestOutlined />
      <RobotOutlined />
      <RocketOutlined />
      <SafetyCertificateOutlined />
      <SafetyOutlined />
      <ScanOutlined />
      <ScheduleOutlined />
      <SearchOutlined />
      <SecurityScanOutlined />
      <SelectOutlined />
      <SendOutlined />
      <SettingOutlined />
      <ShakeOutlined />
      <ShareAltOutlined />
      <ShopOutlined />
      <ShoppingCartOutlined />
      <ShoppingOutlined />
      <SisternodeOutlined />
      <SkinOutlined />
      <SmileOutlined />
      <SolutionOutlined />
      <SoundOutlined />
      <SplitCellsOutlined />
      <StarOutlined />
      <SubnodeOutlined />
      <SyncOutlined />
      <TableOutlined />
      <TabletOutlined />
      <TagOutlined />
      <TagsOutlined />
      <TeamOutlined />
      <ThunderboltOutlined />
      <ToTopOutlined />
      <ToolOutlined />
      <TrademarkCircleOutlined />
      <TrademarkOutlined />
      <TransactionOutlined />
      <TrophyOutlined />
      <UngroupOutlined />
      <UnlockOutlined />
      <UploadOutlined />
      <UsbOutlined />
      <UserAddOutlined />
      <UserDeleteOutlined />
      <UserOutlined />
      <UserSwitchOutlined />
      <UsergroupAddOutlined />
      <UsergroupDeleteOutlined />
      <VideoCameraOutlined />
      <WalletOutlined />
      <WifiOutlined />
      <BorderlessTableOutlined />
      <WomanOutlined />
      <BehanceOutlined />
      <DropboxOutlined />
      <DeploymentUnitOutlined />
      <UpCircleOutlined />
      <DownCircleOutlined />
      <LeftCircleOutlined />
      <RightCircleOutlined />
      <UpSquareOutlined />
      <DownSquareOutlined />
      <LeftSquareOutlined />
      <RightSquareOutlined />
      <PlayCircleOutlined />
      <QuestionCircleOutlined />
      <PlusCircleOutlined />
      <PlusSquareOutlined />
      <MinusSquareOutlined />
      <MinusCircleOutlined />
      <InfoCircleOutlined />
      <ExclamationCircleOutlined />
      <CloseCircleOutlined />
      <CloseSquareOutlined />
      <CheckCircleOutlined />
      <CheckSquareOutlined />
      <ClockCircleOutlined />
      <FormOutlined />
      <DashOutlined />
      <SmallDashOutlined />
      <YoutubeOutlined />
      <CodepenCircleOutlined />
      <AliyunOutlined />
      <PlusOutlined />
      <LinkedinOutlined />
      <AimOutlined />
      <BugOutlined />
      <CloudDownloadOutlined />
      <CloudServerOutlined />
      <CloudSyncOutlined />
      <CloudUploadOutlined />
      <CommentOutlined />
      <ConsoleSqlOutlined />
      <EyeInvisibleOutlined />
      <FileGifOutlined />
      <DeliveredProcedureOutlined />
      <FieldTimeOutlined />
      <FileZipOutlined />
      <FolderViewOutlined />
      <FundProjectionScreenOutlined />
      <FundViewOutlined />
      <MacCommandOutlined />
      <PlaySquareOutlined />
      <OneToOneOutlined />
      <RotateLeftOutlined />
      <RotateRightOutlined />
      <SaveOutlined />
      <SwitcherOutlined />
      <TranslationOutlined />
      <VerifiedOutlined />
      <VideoCameraAddOutlined />
      <WhatsAppOutlined />

      {/*</Col>*/}
    </Row>
  );
}
Example #7
Source File: BuilderToolbar.spec.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
describe("BuilderToolbar", () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  it("should work", async () => {
    mockUseBuilderUIContext.mockReturnValue({
      onCurrentRouteClick: mockCurrentRouteClick,
      onBuildAndPush: mockBuildAndPush,
      onPreview: mockPreview,
      dataType: BuilderDataType.ROUTE_OF_BRICKS,
    });
    mockUseBuilderNode.mockReturnValue({
      id: "R-01",
      type: "bricks",
      path: "/",
    });
    const wrapper = shallow(<BuilderToolbar />);
    expect(wrapper.find(".tabLink").length).toBe(6);
    wrapper.find(".tabLink[data-testid='view-route']").simulate("click");
    expect(mockCurrentRouteClick).toBeCalledWith({
      id: "R-01",
      type: "bricks",
      path: "/",
    });
    wrapper.find(".tabLink[data-testid='build-and-push']").simulate("click");
    expect(mockBuildAndPush).toBeCalled();
    wrapper.find(".tabLink[data-testid='preview']").simulate("click");
    expect(mockPreview).toBeCalled();
  });

  it("should work with custom template", async () => {
    mockUseBuilderUIContext.mockReturnValue({
      onCurrentTemplateClick: mockCurrentTemplateClick,
      onCurrentSnippetClick: mockCurrentSnippetClick,
      onCurrentRouteClick: mockCurrentRouteClick,
      onBuildAndPush: mockBuildAndPush,
      onPreview: mockPreview,
      dataType: BuilderDataType.CUSTOM_TEMPLATE,
    });
    mockUseBuilderNode.mockReturnValue({
      id: "T-01",
      type: "custom-template",
      templateId: "tpl-test",
    });
    const wrapper = shallow(<BuilderToolbar />);
    expect(wrapper.find(".tabLink").length).toBe(6);
    expect(
      wrapper.find(".tabLink").filter("[data-testid='view-template']").length
    ).toBe(1);
    wrapper
      .find(".tabLink")
      .filter("[data-testid='view-template']")
      .simulate("click");
    expect(mockCurrentTemplateClick).toBeCalled();
  });

  it("should work with snippet", async () => {
    mockUseBuilderUIContext.mockReturnValue({
      onCurrentTemplateClick: mockCurrentTemplateClick,
      onCurrentSnippetClick: mockCurrentSnippetClick,
      onCurrentRouteClick: mockCurrentRouteClick,
      onBuildAndPush: mockBuildAndPush,
      onPreview: mockPreview,
      dataType: BuilderDataType.SNIPPET,
    });
    mockUseBuilderNode.mockReturnValue({
      id: "S-01",
      type: "snippet",
      snippetId: "snippet-test",
    });
    const wrapper = shallow(<BuilderToolbar />);
    expect(wrapper.find(".tabLink").length).toBe(6);
    expect(
      wrapper.find(".tabLink").filter("[data-testid='view-snippet']").length
    ).toBe(1);
    wrapper
      .find(".tabLink")
      .filter("[data-testid='view-snippet']")
      .simulate("click");
    expect(mockCurrentSnippetClick).toBeCalled();
  });

  it("should enter fullscreen", () => {
    let fullscreen = false;
    const setFullscreen = jest.fn((update) => {
      fullscreen = update(fullscreen);
    });
    mockUseBuilderUIContext.mockImplementation(() => ({
      fullscreen,
      setFullscreen,
    }));
    const wrapper = shallow(<BuilderToolbar />);
    expect(wrapper.find(FullscreenOutlined).length).toBe(1);
    expect(wrapper.find(FullscreenExitOutlined).length).toBe(0);
    wrapper.find(".tabLink[data-testid='toggle-fullscreen']").invoke("onClick")(
      null
    );
    expect(setFullscreen).toBeCalled();
    expect(fullscreen).toBe(true);
  });

  it("should invoke onWorkbenchClose", () => {
    const onWorkbenchClose = jest.fn();
    mockUseBuilderUIContext.mockImplementation(() => ({
      onWorkbenchClose,
    }));
    const wrapper = shallow(<BuilderToolbar />);
    wrapper.find(".tabLink[data-testid='workbench-close']").invoke("onClick")(
      null
    );
    expect(onWorkbenchClose).toBeCalled();
  });

  it("should show layer viewer ", () => {
    (getRuntime as jest.Mock).mockReturnValueOnce({
      getFeatureFlags: jest
        .fn()
        .mockReturnValue({ "next-builder-layer-view": true }),
    });

    const wrapper = shallow(<BuilderToolbar />);
    expect(wrapper.find(LibraryDropdown).length).toEqual(3);
    wrapper.find(LibraryDropdown).at(0).invoke("onVisbleChange")(true);
    wrapper.find(LibraryDropdown).at(1).invoke("onVisbleChange")(true);
    wrapper.find(LibraryDropdown).at(2).invoke("onVisbleChange")(true);
    const tooltipWrapper = wrapper.find(LibraryDropdown).at(0).shallow();
    expect(tooltipWrapper.find(Tooltip).at(0).prop("overlayStyle")).toEqual({
      display: "none",
    });
  });

  it("should show the hidden wrapper switch", () => {
    mockUseBuilderUIContext.mockReturnValue({
      onCurrentRouteClick: mockCurrentRouteClick,
      onBuildAndPush: mockBuildAndPush,
      onPreview: mockPreview,
      dataType: BuilderDataType.ROUTE_OF_BRICKS,
      hiddenWrapper: true,
      setHiddenWrapper: mockSetHiddenWrapper,
    });
    mockUseBuilderNode.mockReturnValue({
      id: "R-01",
      type: "bricks",
      path: "/",
    });
    mockUseBuilderData.mockReturnValue({
      wrapperNode: {
        $$uid: 1,
      },
    } as any);
    const wrapper = shallow(<BuilderToolbar />);
    expect(wrapper.find(Switch).length).toBe(1);
    wrapper.find(Switch).prop("onChange")(true, {} as MouseEvent);
    expect(mockSetHiddenWrapper).toBeCalled();
  });
});
Example #8
Source File: BuilderToolbar.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
export function BuilderToolbar(): React.ReactElement {
  const { t } = useTranslation(NS_NEXT_BUILDER);
  const enableLayerView = React.useMemo(
    () => getRuntime().getFeatureFlags()["next-builder-layer-view"],
    []
  );

  const [libsDropdownVisible, setLibsDropdownVisible] = useState<{
    [key in typeof LayerType[keyof typeof LayerType]]: boolean;
  }>({
    [LayerType.LAYOUT]: false,
    [LayerType.WIDGET]: false,
    [LayerType.BRICK]: false,
  });

  const { wrapperNode } = useBuilderData();

  const {
    onCurrentRouteClick,
    onCurrentTemplateClick,
    onCurrentSnippetClick,
    onBuildAndPush,
    onPreview,
    dataType,
    fullscreen,
    setFullscreen,
    onWorkbenchClose,
    hiddenWrapper,
    setHiddenWrapper,
  } = useBuilderUIContext();

  const rootNode = useBuilderNode({ isRoot: true });

  const handleRouteClick = (): void => {
    onCurrentRouteClick?.(rootNode as BuilderRouteNode);
  };

  const handleTemplateClick = (): void => {
    onCurrentTemplateClick?.(rootNode as BuilderCustomTemplateNode);
  };

  const handleSnippetClick = (): void => {
    onCurrentSnippetClick?.(rootNode as BuilderSnippetNode);
  };

  const handlePreview = (): void => {
    onPreview?.();
  };

  const handleBuildAndPush = (): void => {
    onBuildAndPush?.();
  };

  const handleToggleFullscreen = React.useCallback(() => {
    setFullscreen((prev) => !prev);
  }, [setFullscreen]);

  const handleClose = (): void => {
    onWorkbenchClose?.();
  };

  const divider = useMemo(
    () => <Divider type="vertical" style={{ height: 25 }} />,
    []
  );

  return (
    <div className={styles.toolbarContainer}>
      <div className={styles.toolbarLeft}>
        {dataType === BuilderDataType.SNIPPET ? (
          <Tooltip title={t(K.VIEW_SNIPPET)} placement="bottomLeft">
            <a
              className={shareStyles.tabLink}
              role="button"
              onClick={handleSnippetClick}
              data-testid="view-snippet"
            >
              <BlockOutlined />
            </a>
          </Tooltip>
        ) : dataType === BuilderDataType.CUSTOM_TEMPLATE ? (
          <Tooltip title={t(K.VIEW_TEMPLATE)} placement="bottomLeft">
            <a
              className={shareStyles.tabLink}
              role="button"
              onClick={handleTemplateClick}
              data-testid="view-template"
            >
              <BlockOutlined />
            </a>
          </Tooltip>
        ) : (
          <Tooltip title={t(K.VIEW_ROUTE)} placement="bottomLeft">
            <a
              className={shareStyles.tabLink}
              role="button"
              onClick={handleRouteClick}
              data-testid="view-route"
            >
              <BranchesOutlined />
            </a>
          </Tooltip>
        )}
        <RootNodeSelect />
      </div>
      <div className={styles.toolbarRight}>
        {wrapperNode ? (
          <Switch
            checkedChildren="显示布局"
            unCheckedChildren="隐藏布局"
            checked={hiddenWrapper}
            onChange={setHiddenWrapper}
            size="small"
            style={{
              marginRight: 10,
              top: -1,
            }}
          />
        ) : null}
        {enableLayerView && (
          <>
            <LibraryDropdown
              menuItems={layoutMenus}
              type={LayerType.LAYOUT}
              onVisbleChange={(visible) =>
                setLibsDropdownVisible({
                  ...libsDropdownVisible,
                  [LayerType.LAYOUT]: visible,
                })
              }
            >
              <Tooltip
                title={t(K.LAYOUT_LIBRARY)}
                placement="bottomRight"
                overlayStyle={{
                  // Hide tooltip when dropdown is open.
                  display: libsDropdownVisible[LayerType.LAYOUT]
                    ? "none"
                    : undefined,
                }}
              >
                <Button
                  type="link"
                  size="small"
                  className={shareStyles.tabLink}
                  style={{ marginRight: "10px" }}
                >
                  <LayoutOutlined />
                </Button>
              </Tooltip>
            </LibraryDropdown>

            <LibraryDropdown
              menuItems={widgetMenus}
              type={LayerType.WIDGET}
              onVisbleChange={(visible) =>
                setLibsDropdownVisible({
                  ...libsDropdownVisible,
                  [LayerType.WIDGET]: visible,
                })
              }
            >
              <Tooltip
                title={t(K.WIDGET_LIBRARY)}
                placement="bottomRight"
                overlayStyle={{
                  display: libsDropdownVisible[LayerType.WIDGET]
                    ? "none"
                    : undefined,
                }}
              >
                <Button
                  type="link"
                  size="small"
                  className={shareStyles.tabLink}
                  style={{ marginRight: "10px" }}
                >
                  <GoldOutlined />
                </Button>
              </Tooltip>
            </LibraryDropdown>
          </>
        )}
        <LibraryDropdown
          menuItems={brickMenus}
          type={LayerType.BRICK}
          onVisbleChange={(visible) =>
            setLibsDropdownVisible({
              ...libsDropdownVisible,
              [LayerType.BRICK]: visible,
            })
          }
        >
          <Tooltip
            title={t(K.BRICK_LIBRARY)}
            placement="bottomRight"
            overlayStyle={{
              display: libsDropdownVisible[LayerType.BRICK]
                ? "none"
                : undefined,
            }}
          >
            <Button
              type="link"
              size="small"
              style={{ marginRight: "10px" }}
              className={shareStyles.tabLink}
            >
              <PlusOutlined />
            </Button>
          </Tooltip>
        </LibraryDropdown>
        {divider}
        <Tooltip title={t(K.BUILD_AND_PUSH_TOOLTIP)} placement="bottomRight">
          <a
            className={shareStyles.tabLink}
            role="button"
            onClick={handleBuildAndPush}
            data-testid="build-and-push"
          >
            <ApiOutlined />
          </a>
        </Tooltip>
        <Tooltip title={t(K.PREVIEW)} placement="bottomRight">
          <a
            className={shareStyles.tabLink}
            role="button"
            onClick={handlePreview}
            data-testid="preview"
          >
            <CaretRightOutlined />
          </a>
        </Tooltip>
        {divider}
        <SettingDropdown />
        {!fullscreen && (
          <Tooltip
            title={t(fullscreen ? K.EXIT_FULLSCREEN : K.ENTER_FULLSCREEN)}
            placement="bottomRight"
          >
            <a
              className={shareStyles.tabLink}
              role="button"
              onClick={handleToggleFullscreen}
              data-testid="toggle-fullscreen"
            >
              {fullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
            </a>
          </Tooltip>
        )}
        <Tooltip title={t(K.CLOSE)} placement="bottomRight">
          <a
            className={shareStyles.tabLink}
            role="button"
            onClick={handleClose}
            data-testid="workbench-close"
          >
            <CloseOutlined />
          </a>
        </Tooltip>
      </div>
    </div>
  );
}
Example #9
Source File: WidgetActionDropdown.tsx    From datart with Apache License 2.0 4 votes vote down vote up
WidgetActionDropdown: React.FC<WidgetActionDropdownProps> = memo(
  ({ widget }) => {
    const { editing: boardEditing } = useContext(BoardContext);

    const widgetAction = useWidgetAction();
    const dataChart = useContext(WidgetChartContext)!;
    const t = useI18NPrefix(`viz.widget.action`);
    const menuClick = useCallback(
      ({ key }) => {
        widgetAction(key, widget);
      },
      [widgetAction, widget],
    );
    const getAllList = useCallback(() => {
      const allWidgetActionList: WidgetActionListItem<widgetActionType>[] = [
        {
          key: 'refresh',
          label: t('refresh'),
          icon: <SyncOutlined />,
        },
        {
          key: 'fullScreen',
          label: t('fullScreen'),
          icon: <FullscreenOutlined />,
        },
        {
          key: 'edit',
          label: t('edit'),
          icon: <EditOutlined />,
        },
        {
          key: 'delete',
          label: t('delete'),
          icon: <DeleteOutlined />,
          danger: true,
        },

        {
          key: 'info',
          label: t('info'),
          icon: <InfoOutlined />,
        },
        {
          key: 'lock',
          label: t('lock'),
          icon: <LockOutlined />,
        },

        {
          key: 'makeLinkage',
          label: t('makeLinkage'),
          icon: <LinkOutlined />,
          divider: true,
        },
        {
          key: 'closeLinkage',
          label: t('closeLinkage'),
          icon: <CloseCircleOutlined />,
          danger: true,
        },
        {
          key: 'makeJump',
          label: t('makeJump'),
          icon: <BranchesOutlined />,
          divider: true,
        },
        {
          key: 'closeJump',
          label: t('closeJump'),
          icon: <CloseCircleOutlined />,
          danger: true,
        },
      ];
      return allWidgetActionList;
    }, [t]);
    const actionList = useMemo(() => {
      return (
        getWidgetActionList({
          allList: getAllList(),
          widget,
          boardEditing,
          chartGraphId: dataChart?.config?.chartGraphId,
        }) || []
      );
    }, [boardEditing, dataChart?.config?.chartGraphId, getAllList, widget]);
    const dropdownList = useMemo(() => {
      const menuItems = actionList.map(item => {
        return (
          <React.Fragment key={item.key}>
            {item.divider && <Menu.Divider />}
            <Menu.Item
              danger={item.danger}
              icon={item.icon}
              disabled={item.disabled}
              key={item.key}
            >
              {item.label}
            </Menu.Item>
          </React.Fragment>
        );
      });

      return <Menu onClick={menuClick}>{menuItems}</Menu>;
    }, [actionList, menuClick]);
    if (actionList.length === 0) {
      return null;
    }
    return (
      <Dropdown
        className="widget-tool-dropdown"
        overlay={dropdownList}
        placement="bottomCenter"
        trigger={['click']}
        arrow
      >
        <Button icon={<EllipsisOutlined />} type="link" />
      </Dropdown>
    );
  },
)
Example #10
Source File: useExtraBtn.tsx    From amiya with MIT License 4 votes vote down vote up
export default function useExtraBtn(
  tableRef: any,
  searchRef: any,
  tableFields: Array<AyTableField>,
  setTableFields: Dispatch<React.SetStateAction<AyTableField[]>>,
  props: AySearchTableProps
) {
  // 合并配置
  const config = Object.assign({}, defaultConfig, props)
  const {
    extraVisible,
    extraRefreshVisible,
    extraSizeVisible,
    extraSizeDefaultValue,
    extraSettingVisible,
    extraFullscreenVisible
  } = config
  /** 表格尺寸 */
  const [size, setSize] = useState<SizeType>(extraSizeDefaultValue)
  /** 表格全屏 */
  const [isEnter, setIsEnter] = useState<boolean>(false)

  const fieldsEdit = useFieldsEdit(tableFields, setTableFields)

  const handleRefresh = () => {
    tableRef.current.refresh()
  }

  const handleSizeChange = (e: any) => {
    setSize(e.key)
  }

  useEffect(() => {
    // body 的 style 防止滚动
    if (isEnter) {
      document.body.style.overflow = 'hidden'
    } else {
      document.body.style.overflow = ''
    }
    searchRef.current && searchRef.current.resize()
  }, [isEnter])

  const extraBtns = extraVisible ? (
    <div className="ay-search-table-extra-btns" key="ay-search-table-extra-btns">
      <Space size="middle">
        {extraRefreshVisible ? (
          <Tooltip title={locale.extra.refresh}>
            <ReloadOutlined onClick={handleRefresh} />
          </Tooltip>
        ) : null}

        {extraSizeVisible ? (
          <Tooltip title={locale.extra.density}>
            <Dropdown
              overlay={
                <Menu style={{ width: 100 }} selectedKeys={[size + '']} onClick={handleSizeChange}>
                  <Menu.Item key="large">{locale.extra.densityLarger}</Menu.Item>
                  <Menu.Item key="middle">{locale.extra.densityMiddle}</Menu.Item>
                  <Menu.Item key="small">{locale.extra.densitySmall}</Menu.Item>
                </Menu>
              }
            >
              <ColumnHeightOutlined />
            </Dropdown>
          </Tooltip>
        ) : null}

        {extraSettingVisible ? fieldsEdit : null}

        {extraFullscreenVisible ? (
          isEnter ? (
            <Tooltip title={locale.extra.exitFullScreen} key={locale.extra.exitFullScreen}>
              <FullscreenExitOutlined className="ay-search-table-fullscrenn-enter" onClick={() => setIsEnter(false)} />
            </Tooltip>
          ) : (
            <Tooltip title={locale.extra.fullScreen} key={locale.extra.fullScreen}>
              <FullscreenOutlined className="ay-search-table-fullscrenn-out" onClick={() => setIsEnter(true)} />
            </Tooltip>
          )
        ) : null}
      </Space>
    </div>
  ) : null

  return {
    extraBtns,
    isEnter,
    setIsEnter,
    size
  }
}
Example #11
Source File: YakExecutor.tsx    From yakit with GNU Affero General Public License v3.0 4 votes vote down vote up
YakExecutor: React.FC<YakExecutorProp> = (props) => {
    const [codePath, setCodePath] = useState<string>("")
    const [loading, setLoading] = useState<boolean>(false)
    const [fileList, setFileList] = useState<tabCodeProps[]>([])
    const [tabList, setTabList] = useState<tabCodeProps[]>([])
    const [activeTab, setActiveTab] = useState<string>("")
    const [unTitleCount, setUnTitleCount] = useState(1)

    const [hintShow, setHintShow] = useState<boolean>(false)
    const [hintFile, setHintFile] = useState<string>("")
    const [hintIndex, setHintIndex] = useState<number>(0)

    const [renameHint, setRenameHint] = useState<boolean>(false)
    const [renameIndex, setRenameIndex] = useState<number>(-1)
    const [renameFlag, setRenameFlag] = useState<boolean>(false)
    const [renameCache, setRenameCache] = useState<string>("")

    const [fullScreen, setFullScreen] = useState<boolean>(false)

    const [errors, setErrors] = useState<string[]>([])
    const [executing, setExecuting] = useState(false)
    const [outputEncoding, setOutputEncoding] = useState<"utf8" | "latin1">("utf8")
    const xtermAsideRef = useRef(null)
    const xtermRef = useRef(null)
    const timer = useRef<any>(null)

    const [extraParams, setExtraParams] = useState("")

    // trigger for updating
    const [triggerForUpdatingHistory, setTriggerForUpdatingHistory] = useState<any>(0)

    const addFileTab = useMemoizedFn((res: any) => {
        const {name, code} = res

        const tab: tabCodeProps = {
            tab: `${name}.yak`,
            code: code,
            suffix: "yak",
            isFile: false
        }
        setActiveTab(`${tabList.length}`)
        setTabList(tabList.concat([tab]))
        setUnTitleCount(unTitleCount + 1)
    })

    useEffect(() => {
        ipcRenderer.on("fetch-send-to-yak-running", (e, res: any) => addFileTab(res))
        return () => ipcRenderer.removeAllListeners("fetch-send-to-yak-running")
    }, [])

    // 自动保存
    const autoSave = useMemoizedFn(() => {
        for (let tabInfo of tabList) {
            if (tabInfo.isFile) {
                ipcRenderer.invoke("write-file", {
                    route: tabInfo.route,
                    data: tabInfo.code
                })
            }
        }
    })
    // 保存近期文件内的15个
    const saveFiliList = useMemoizedFn(() => {
        let files = cloneDeep(fileList).reverse()
        files.splice(14)
        files = files.reverse()
        ipcRenderer.invoke("set-value", RecentFileList, files)
    })

    // 获取和保存近期打开文件信息,同时展示打开默认内容
    useEffect(() => {
        let time: any = null
        let timer: any = null
        setLoading(true)
        ipcRenderer
            .invoke("get-value", RecentFileList)
            .then((value: any) => {
                if ((value || []).length !== 0) {
                    setFileList(value)
                } else {
                    const tab: tabCodeProps = {
                        tab: `Untitle-${unTitleCount}.yak`,
                        code: "# input your yak code\nprintln(`Hello Yak World!`)",
                        suffix: "yak",
                        isFile: false
                    }
                    setActiveTab(`${tabList.length}`)
                    setTabList([tab])
                    setUnTitleCount(unTitleCount + 1)
                }
            })
            .catch(() => {})
            .finally(() => {
                setTimeout(() => setLoading(false), 300)
                time = setInterval(() => {
                    autoSave()
                }, 2000)
                timer = setInterval(() => {
                    saveFiliList()
                }, 5000)
            })

        return () => {
            saveFiliList()
            if (time) clearInterval(time)
            if (timer) clearInterval(timer)
        }
    }, [])

    // 全局监听重命名事件是否被打断
    useEffect(() => {
        document.onmousedown = (e) => {
            // @ts-ignore
            if (e.path[0].id !== "rename-input" && renameFlag) {
                renameCode(renameIndex)
                setRenameFlag(false)
            }
        }
    }, [renameFlag])

    // 打开文件
    const addFile = useMemoizedFn((file: any) => {
        const isExists = fileList.filter((item) => item.tab === file.name && item.route === file.path).length === 1

        if (isExists) {
            for (let index in tabList) {
                const item = tabList[index]
                if (item.tab === file.name && item.route === file.path) {
                    setActiveTab(`${index}`)
                    return false
                }
            }
        }
        ipcRenderer
            .invoke("fetch-file-content", file.path)
            .then((res) => {
                const tab: tabCodeProps = {
                    tab: file.name,
                    code: res,
                    suffix: file.name.split(".").pop() === "yak" ? "yak" : "http",
                    isFile: true,
                    route: file.path,
                    extraParams: file.extraParams
                }
                setActiveTab(`${tabList.length}`)
                if (!isExists) setFileList(fileList.concat([tab]))
                setTabList(tabList.concat([tab]))
            })
            .catch(() => {
                failed("无法获取该文件内容,请检查后后重试!")
                const files = cloneDeep(fileList)
                for (let i in files) if (files[i].route === file.path) files.splice(i, 1)
                setFileList(files)
            })
        return false
    })
    // 新建文件
    const newFile = useMemoizedFn(() => {
        const tab: tabCodeProps = {
            tab: `Untitle-${unTitleCount}.yak`,
            code: "# input your yak code\nprintln(`Hello Yak World!`)",
            suffix: "yak",
            isFile: false
        }
        setActiveTab(`${tabList.length}`)
        setTabList(tabList.concat([tab]))
        setUnTitleCount(unTitleCount + 1)
    })
    //修改文件
    const modifyCode = useMemoizedFn((value: string, index: number) => {
        const tabs = cloneDeep(tabList)
        tabs[index].code = value
        setTabList(tabs)
    })
    // 保存文件
    const saveCode = useMemoizedFn((info: tabCodeProps, index: number) => {
        if (info.isFile) {
            ipcRenderer.invoke("write-file", {
                route: info.route,
                data: info.code
            })
        } else {
            ipcRenderer.invoke("show-save-dialog", `${codePath}${codePath ? '/' : ''}${info.tab}`).then((res) => {
                if (res.canceled) return

                const path = res.filePath
                const name = res.name
                ipcRenderer
                    .invoke("write-file", {
                        route: res.filePath,
                        data: info.code
                    })
                    .then(() => {
                        const suffix = name.split(".").pop()

                        var tabs = cloneDeep(tabList)
                        var active = null
                        tabs = tabs.filter((item) => item.route !== path)
                        tabs = tabs.map((item, index) => {
                            if (!item.route && item.tab === info.tab) {
                                active = index
                                item.tab = name
                                item.isFile = true
                                item.suffix = suffix === "yak" ? suffix : "http"
                                item.route = path
                                return item
                            }
                            return item
                        })
                        if (active !== null) setActiveTab(`${active}`)
                        setTabList(tabs)
                        const file: tabCodeProps = {
                            tab: name,
                            code: info.code,
                            isFile: true,
                            suffix: suffix === "yak" ? suffix : "http",
                            route: res.filePath,
                            extraParams: info.extraParams
                        }
                        for (let item of fileList) {
                            if (item.route === file.route) {
                                return
                            }
                        }
                        setFileList(fileList.concat([file]))
                    })
            })
        }
    })
    //关闭文件
    const closeCode = useMemoizedFn((index, isFileList: boolean) => {
        const tabInfo = isFileList ? fileList[+index] : tabList[+index]
        if (isFileList) {
            for (let i in tabList) {
                if (tabList[i].tab === tabInfo.tab && tabList[i].route === tabInfo.route) {
                    const tabs = cloneDeep(tabList)
                    tabs.splice(i, 1)
                    setTabList(tabs)
                    setActiveTab(tabs.length >= 1 ? `0` : "")
                }
            }
            const files = cloneDeep(fileList)
            files.splice(+index, 1)
            setFileList(files)
        } else {
            setActiveTab(index)

            if (!tabInfo.isFile) {
                setHintFile(tabInfo.tab)
                setHintIndex(index)
                setHintShow(true)
            } else {
                const tabs = cloneDeep(tabList)
                tabs.splice(+index, 1)
                setTabList(tabs)
                setActiveTab(tabs.length >= 1 ? `0` : "")
            }
        }
    })
    // 关闭虚拟文件不保存
    const ownCloseCode = useMemoizedFn(() => {
        const tabs = cloneDeep(tabList)
        tabs.splice(hintIndex, 1)
        setTabList(tabs)
        setHintShow(false)
        setActiveTab(tabs.length >= 1 ? `0` : "")
    })
    // 删除文件
    const delCode = useMemoizedFn((index) => {
        const fileInfo = fileList[index]

        ipcRenderer
            .invoke("delelte-code-file", fileInfo.route)
            .then(() => {
                for (let i in tabList) {
                    if (tabList[i].tab === fileInfo.tab && tabList[i].route === fileInfo.route) {
                        const tabs = cloneDeep(tabList)
                        tabs.splice(i, 1)
                        setTabList(tabs)
                        setActiveTab(tabs.length >= 1 ? `0` : "")
                    }
                }
                const arr = cloneDeep(fileList)
                arr.splice(index === undefined ? hintIndex : index, 1)
                setFileList(arr)
            })
            .catch(() => {
                failed("文件删除失败!")
            })
    })
    //重命名操作
    const renameCode = useMemoizedFn((index: number) => {
        const tabInfo = fileList[index]

        if (renameCache === tabInfo.tab) return
        if (!renameCache) return

        if (!tabInfo.route) return
        const flagStr = tabInfo.route?.indexOf("/") > -1 ? "/" : "\\"
        const routes = tabInfo.route?.split(flagStr)
        routes?.pop()
        ipcRenderer
            .invoke("is-exists-file", routes?.concat([renameCache]).join(flagStr))
            .then(() => {
                const newRoute = routes?.concat([renameCache]).join(flagStr)
                if (!tabInfo.route || !newRoute) return
                renameFile(index, renameCache, tabInfo.route, newRoute)
            })
            .catch(() => {
                setRenameHint(true)
            })
    })
    // 重命名文件
    const renameFile = useMemoizedFn(
        (index: number, rename: string, oldRoute: string, newRoute: string, callback?: () => void) => {
            ipcRenderer.invoke("rename-file", {old: oldRoute, new: newRoute}).then(() => {
                const suffix = rename.split(".").pop()

                var files = cloneDeep(fileList)
                var tabs = cloneDeep(tabList)
                var active = null
                files = files.filter((item) => item.route !== newRoute)
                tabs = tabs.filter((item) => item.route !== newRoute)

                files = files.map((item) => {
                    if (item.route === oldRoute) {
                        item.tab = rename
                        item.suffix = suffix === "yak" ? suffix : "http"
                        item.route = newRoute
                        return item
                    }
                    return item
                })
                tabs = tabs.map((item, index) => {
                    if (item.route === oldRoute) {
                        active = index
                        item.tab = rename
                        item.suffix = suffix === "yak" ? suffix : "http"
                        item.route = newRoute
                        return item
                    }
                    return item
                })
                if (active !== null) setActiveTab(`${active}`)
                setFileList(files)
                setTabList(tabs)

                if (callback) callback()
            })
        }
    )

    const fileFunction = (kind: string, index: string, isFileList: boolean) => {
        const tabCodeInfo = isFileList ? fileList[index] : tabList[index]

        switch (kind) {
            case "own":
                closeCode(index, isFileList)
                return
            case "other":
                const tabInfo: tabCodeProps = cloneDeep(tabList[index])
                for (let i in tabList) {
                    if (i !== index && !tabList[i].isFile) {
                        const arr: tabCodeProps[] =
                            +i > +index
                                ? [tabInfo].concat(tabList.splice(+i, tabList.length))
                                : tabList.splice(+i, tabList.length)
                        const num = +i > +index ? 1 : 0

                        setActiveTab(`${num}`)
                        setTabList(arr)
                        setHintFile(arr[num].tab)
                        setHintIndex(num)
                        setHintShow(true)
                        return
                    }
                }
                const code = cloneDeep(tabList[index])
                setTabList([code])
                setActiveTab(`0`)
                return
            case "all":
                for (let i in tabList) {
                    if (!tabList[i].isFile) {
                        const arr = tabList.splice(+i, tabList.length)
                        setActiveTab("0")
                        setTabList(arr)
                        setHintFile(arr[0].tab)
                        setHintIndex(0)
                        setHintShow(true)
                        return
                    }
                }
                setActiveTab("")
                setTabList([])
                return
            case "remove":
                closeCode(index, isFileList)
                return
            case "delete":
                delCode(index)
                return
            case "rename":
                setRenameIndex(+index)
                setRenameFlag(true)
                setRenameCache(tabCodeInfo.tab)
                return
        }
    }

    const openFileLayout = (file: any) => {
        addFile(file)
    }

    useEffect(() => {
        ipcRenderer.invoke("fetch-code-path")
            .then((path: string) => {
                ipcRenderer.invoke("is-exists-file", path)
                    .then(() => {
                        setCodePath("")
                    })
                    .catch(() => {
                        setCodePath(path)
                    })
            })
    }, [])

    useEffect(() => {
        if (tabList.length === 0) setFullScreen(false)
    }, [tabList])

    useEffect(() => {
        if (!xtermRef) {
            return
        }
        // let buffer = "";
        ipcRenderer.on("client-yak-error", async (e: any, data) => {
            failed(`FoundError: ${JSON.stringify(data)}`)
            if (typeof data === "object") {
                setErrors([...errors, `${JSON.stringify(data)}`])
            } else if (typeof data === "string") {
                setErrors([...errors, data])
            } else {
                setErrors([...errors, `${data}`])
            }
        })
        ipcRenderer.on("client-yak-end", () => {
            info("Yak 代码执行完毕")
            setTriggerForUpdatingHistory(getRandomInt(100000))
            setTimeout(() => {
                setExecuting(false)
            }, 300)
        })
        ipcRenderer.on("client-yak-data", async (e: any, data: ExecResult) => {
            if (data.IsMessage) {
                // alert(Buffer.from(data.Message).toString("utf8"))
            }
            if (data?.Raw) {
                writeExecResultXTerm(xtermRef, data, outputEncoding)
                // writeXTerm(xtermRef, Buffer.from(data.Raw).toString(outputEncoding).replaceAll("\n", "\r\n"))
                // monacoEditorWrite(currentOutputEditor, )
            }
        })
        return () => {
            ipcRenderer.removeAllListeners("client-yak-data")
            ipcRenderer.removeAllListeners("client-yak-end")
            ipcRenderer.removeAllListeners("client-yak-error")
        }
    }, [xtermRef])

    const bars = (props: any, TabBarDefault: any) => {
        return (
            <TabBarDefault
                {...props}
                children={(barNode: React.ReactElement) => {
                    return (
                        <Dropdown
                            overlay={CustomMenu(barNode.key, false, tabMenu, fileFunction)}
                            trigger={["contextMenu"]}
                        >
                            {barNode}
                        </Dropdown>
                    )
                }}
            />
        )
    }

    return (
        <AutoCard
            className={"yak-executor-body"}
            // title={"Yak Runner"}
            headStyle={{minHeight: 0}}
            bodyStyle={{padding: 0, overflow: "hidden"}}
        >
            <div
                style={{width: "100%", height: "100%", display: "flex", backgroundColor: "#E8E9E8"}}
                tabIndex={0}
                onKeyDown={(e) => {
                    if (e.keyCode === 78 && (e.ctrlKey || e.metaKey)) {
                        newFile()
                    }
                    if (e.keyCode === 83 && (e.ctrlKey || e.metaKey) && activeTab) {
                        saveCode(tabList[+activeTab], +activeTab)
                    }
                }}
            >
                <div style={{width: `${fullScreen ? 0 : 15}%`}}>
                    <AutoSpin spinning={loading}>
                        <ExecutorFileList
                            lists={fileList}
                            activeFile={tabList[+activeTab]?.route || ""}
                            renameFlag={renameFlag}
                            renameIndex={renameIndex}
                            renameCache={renameCache}
                            setRenameCache={setRenameCache}
                            addFile={addFile}
                            newFile={newFile}
                            openFile={openFileLayout}
                            fileFunction={fileFunction}
                        />
                    </AutoSpin>
                </div>
                <div style={{width: `${fullScreen ? 100 : 85}%`}} className='executor-right-body'>
                    {tabList.length > 0 && (
                        <ResizeBox
                            isVer
                            firstNode={
                                <Tabs
                                    className={"right-editor"}
                                    style={{height: "100%"}}
                                    type='editable-card'
                                    activeKey={activeTab}
                                    hideAdd={true}
                                    onChange={(activeTab) => setActiveTab(activeTab)}
                                    onEdit={(key, event: "add" | "remove") => {
                                        switch (event) {
                                            case "remove":
                                                closeCode(key, false)
                                                return
                                            case "add":
                                                return
                                        }
                                    }}
                                    renderTabBar={(props, TabBarDefault) => {
                                        return bars(props, TabBarDefault)
                                    }}
                                    tabBarExtraContent={
                                        tabList.length && (
                                            <Space style={{marginRight: 5}} size={0}>
                                                <Button
                                                    style={{height: 25}}
                                                    type={"link"}
                                                    size={"small"}
                                                    disabled={
                                                        tabList[+activeTab] && tabList[+activeTab].suffix !== "yak"
                                                    }
                                                    onClick={(e) => {
                                                        let m = showDrawer({
                                                            width: "60%",
                                                            placement: "left",
                                                            title: "选择你的 Yak 模块执行特定功能",
                                                            content: (
                                                                <>
                                                                    <YakScriptManagerPage
                                                                        type={"yak"}
                                                                        onLoadYakScript={(s) => {
                                                                            const tab: tabCodeProps = {
                                                                                tab: `Untitle-${unTitleCount}.yak`,
                                                                                code: s.Content,
                                                                                suffix: "yak",
                                                                                isFile: false
                                                                            }
                                                                            info(`加载 Yak 模块:${s.ScriptName}`)
                                                                            xtermClear(xtermRef)
                                                                            setActiveTab(`${tabList.length}`)
                                                                            setTabList(tabList.concat([tab]))
                                                                            setUnTitleCount(unTitleCount + 1)
                                                                            m.destroy()
                                                                        }}
                                                                    />
                                                                </>
                                                            )
                                                        })
                                                    }}
                                                >
                                                    Yak脚本模板
                                                </Button>

                                                <Button
                                                    icon={
                                                        fullScreen ? (
                                                            <FullscreenExitOutlined style={{fontSize: 15}} />
                                                        ) : (
                                                            <FullscreenOutlined style={{fontSize: 15}} />
                                                        )
                                                    }
                                                    type={"link"}
                                                    size={"small"}
                                                    style={{width: 30, height: 25}}
                                                    onClick={() => setFullScreen(!fullScreen)}
                                                />
                                                <Popover
                                                    trigger={["click"]}
                                                    title={"设置命令行额外参数"}
                                                    placement="bottomRight"
                                                    content={
                                                        <Space style={{width: 400}}>
                                                            <div>yak {tabList[+activeTab]?.tab || "[file]"}</div>
                                                            <Divider type={"vertical"} />
                                                            <Paragraph
                                                                style={{width: 200, marginBottom: 0}}
                                                                editable={{
                                                                    icon: <Space>
                                                                        <EditOutlined />
                                                                        <SaveOutlined onClick={(e) => {
                                                                            e.stopPropagation()
                                                                            tabList[+activeTab].extraParams = extraParams
                                                                            setTabList(tabList)
                                                                            if(tabList[+activeTab].isFile){
                                                                                const files = fileList.map(item => {
                                                                                    if(item.route === tabList[+activeTab].route){
                                                                                        item.extraParams = extraParams
                                                                                        return item
                                                                                    }
                                                                                    return item
                                                                                })
                                                                                setFileList(files)
                                                                            }
                                                                            success("保存成功")
                                                                        }} 
                                                                    /></Space>,
                                                                    tooltip: '编辑/保存为该文件默认参数',
                                                                    onChange: setExtraParams
                                                                }}
                                                            >
                                                                {extraParams}
                                                            </Paragraph>
                                                        </Space>
                                                    }
                                                >
                                                    <Button type={"link"} icon={<EllipsisOutlined />} onClick={() => {
                                                        setExtraParams(tabList[+activeTab]?.extraParams || "")
                                                    }} />
                                                </Popover>
                                                {executing ? (
                                                    <Button
                                                        icon={<PoweroffOutlined style={{fontSize: 15}} />}
                                                        type={"link"}
                                                        danger={true}
                                                        size={"small"}
                                                        style={{width: 30, height: 25}}
                                                        onClick={() => ipcRenderer.invoke("cancel-yak")}
                                                    />
                                                ) : (
                                                    <Button
                                                        icon={<CaretRightOutlined style={{fontSize: 15}} />}
                                                        type={"link"}
                                                        ghost={true}
                                                        size={"small"}
                                                        style={{width: 30, height: 25}}
                                                        disabled={
                                                            tabList[+activeTab] && tabList[+activeTab].suffix !== "yak"
                                                        }
                                                        onClick={() => {
                                                            setErrors([])
                                                            setExecuting(true)
                                                            ipcRenderer.invoke("exec-yak", {
                                                                Script: tabList[+activeTab].code,
                                                                Params: [],
                                                                RunnerParamRaw: extraParams
                                                            })
                                                        }}
                                                    />
                                                )}
                                            </Space>
                                        )
                                    }
                                >
                                    {tabList.map((item, index) => {
                                        return (
                                            <TabPane tab={item.tab} key={`${index}`}>
                                                <div style={{height: "100%"}}>
                                                    <AutoSpin spinning={executing}>
                                                        <div style={{height: "100%"}}>
                                                            <YakEditor
                                                                type={item.suffix}
                                                                value={item.code}
                                                                setValue={(value) => {
                                                                    modifyCode(value, index)
                                                                }}
                                                            />
                                                        </div>
                                                    </AutoSpin>
                                                </div>
                                            </TabPane>
                                        )
                                    })}
                                </Tabs>
                            }
                            firstRatio='70%'
                            secondNode={
                                <div
                                    ref={xtermAsideRef}
                                    style={{
                                        width: "100%",
                                        height: "100%",
                                        overflow: "hidden",
                                        borderTop: "1px solid #dfdfdf"
                                    }}
                                >
                                    <Tabs
                                        style={{height: "100%"}}
                                        className={"right-xterm"}
                                        size={"small"}
                                        tabBarExtraContent={
                                            <Space>
                                                <SelectOne
                                                    formItemStyle={{marginBottom: 0}}
                                                    value={outputEncoding}
                                                    setValue={setOutputEncoding}
                                                    size={"small"}
                                                    data={[
                                                        {text: "GBxxx编码", value: "latin1"},
                                                        {text: "UTF-8编码", value: "utf8"}
                                                    ]}
                                                />
                                                <Button
                                                    size={"small"}
                                                    icon={<DeleteOutlined />}
                                                    type={"link"}
                                                    onClick={(e) => {
                                                        xtermClear(xtermRef)
                                                    }}
                                                />
                                            </Space>
                                        }
                                    >
                                        <TabPane
                                            tab={<div style={{width: 50, textAlign: "center"}}>输出</div>}
                                            key={"output"}
                                        >
                                            <div style={{width: "100%", height: "100%"}}>
                                                <CVXterm
                                                    ref={xtermRef}
                                                    options={{
                                                        convertEol: true,
                                                        theme: {
                                                            foreground: "#536870",
                                                            background: "#E8E9E8",
                                                            cursor: "#536870",

                                                            black: "#002831",
                                                            brightBlack: "#001e27",

                                                            red: "#d11c24",
                                                            brightRed: "#bd3613",

                                                            green: "#738a05",
                                                            brightGreen: "#475b62",

                                                            yellow: "#a57706",
                                                            brightYellow: "#536870",

                                                            blue: "#2176c7",
                                                            brightBlue: "#708284",

                                                            magenta: "#c61c6f",
                                                            brightMagenta: "#5956ba",

                                                            cyan: "#259286",
                                                            brightCyan: "#819090",

                                                            white: "#eae3cb",
                                                            brightWhite: "#fcf4dc"
                                                        }
                                                    }}
                                                />
                                            </div>
                                        </TabPane>
                                        <TabPane
                                            tab={
                                                <div style={{width: 50, textAlign: "center"}} key={"terminal"}>
                                                    终端(监修中)
                                                </div>
                                            }
                                            disabled
                                        >
                                            <Terminal />
                                        </TabPane>
                                    </Tabs>
                                </div>
                            }
                            secondRatio='30%'
                        />
                    )}
                    {tabList.length === 0 && (
                        <Empty className='right-empty' description={<p>请点击左侧打开或新建文件</p>}></Empty>
                    )}
                </div>

                <Modal
                    visible={hintShow}
                    onCancel={() => setHintShow(false)}
                    footer={[
                        <Button key='link' onClick={() => setHintShow(false)}>
                            取消
                        </Button>,
                        <Button key='submit' onClick={() => ownCloseCode()}>
                            不保存
                        </Button>,
                        <Button key='back' type='primary' onClick={() => saveCode(tabList[hintIndex], hintIndex)}>
                            保存
                        </Button>
                    ]}
                >
                    <div style={{height: 40}}>
                        <ExclamationCircleOutlined style={{fontSize: 22, color: "#faad14"}} />
                        <span style={{fontSize: 18, marginLeft: 15}}>文件未保存</span>
                    </div>
                    <p style={{fontSize: 15, marginLeft: 37}}>{`是否要保存${hintFile}里面的内容吗?`}</p>
                </Modal>

                <Modal
                    visible={renameHint}
                    onCancel={() => setHintShow(false)}
                    footer={[
                        <Button key='link' onClick={() => setRenameHint(false)}>
                            取消
                        </Button>,
                        <Button
                            key='back'
                            type='primary'
                            onClick={() => {
                                const oldRoute = tabList[renameIndex].route
                                if (!oldRoute) return
                                const flagStr = oldRoute?.indexOf("/") > -1 ? "/" : "\\"
                                const routes = oldRoute?.split(flagStr)
                                routes?.pop()
                                const newRoute = routes?.concat([renameCache]).join(flagStr)
                                if (!oldRoute || !newRoute) return
                                renameFile(renameIndex, renameCache, oldRoute, newRoute, () => {
                                    setRenameHint(false)
                                })
                            }}
                        >
                            确定
                        </Button>
                    ]}
                >
                    <div style={{height: 40}}>
                        <ExclamationCircleOutlined style={{fontSize: 22, color: "#faad14"}} />
                        <span style={{fontSize: 18, marginLeft: 15}}>文件已存在</span>
                    </div>
                    <p style={{fontSize: 15, marginLeft: 37}}>{`是否要覆盖已存在的文件吗?`}</p>
                </Modal>
            </div>
        </AutoCard>
    )
}
Example #12
Source File: YakScriptCreator.tsx    From yakit with GNU Affero General Public License v3.0 4 votes vote down vote up
YakScriptCreatorForm: React.FC<YakScriptCreatorFormProp> = (props) => {
    const [params, setParams] = useState<YakScript>(props.modified || {
        Content: "", Tags: "", Author: "", Level: "",
        IsHistory: false,
        CreatedAt: 0,
        Help: "",
        Id: 0,
        Params: [],
        ScriptName: "",
        Type: "yak",
        IsGeneralModule: false,
        PluginSelectorTypes: "mitm,port-scan"
    });
    const [paramsLoading, setParamsLoading] = useState(false);
    const [modified, setModified] = useState<YakScript | undefined>(props.modified);
    const [fullscreen, setFullscreen] = useState(false);
    const [loading, setLoading] = useState(false);

    const isNucleiPoC = params.Type === "nuclei";

    const debugButton = (primary?: boolean) => {
        if (loading) {
            return <Button disabled={true}>执行中...无法调试</Button>
        }
        return
    }

    useEffect(() => {
        if (paramsLoading) {
            setTimeout(() => {
                setParamsLoading(false)
            }, 400)
        }
    }, [paramsLoading])

    useEffect(() => {
        switch (params.Type) {
            case "mitm":
                setParams({...params, Content: MITMPluginTemplate})
                return
            case "port-scan":
                setParams(
                    {
                        ...params, Content: PortScanPluginTemplate, Params: [
                            {
                                Field: "target",
                                FieldVerbose: "扫描的目标",
                                TypeVerbose: "string",
                                Required: true
                            } as YakScriptParam,
                            {
                                Field: "ports",
                                FieldVerbose: "端口",
                                TypeVerbose: "string",
                                Required: false,
                                DefaultValue: "80"
                            } as YakScriptParam,
                        ]
                    },
                )
                return
            case "packet-hack":
                setParams({
                    ...params, Content: PacketHackPluginTemplate, Params: [
                        {Field: "request", TypeVerbose: "http-packet", Required: true} as YakScriptParam,
                        {Field: "response", TypeVerbose: "http-packet", Required: false} as YakScriptParam,
                        {Field: "isHttps", TypeVerbose: "bool",} as YakScriptParam,
                    ]
                })
                return
            case "codec":
                setParams({...params, Content: CodecPluginTemplate})
                return
            case "nuclei":
                setParams({...params, Content: "# Add your nuclei formatted PoC!"})
                return
            default:
                setParams({...params, Content: "yakit.AutoInitYakit()\n\n# Input your code!\n\n"})
                return
        }
    }, [params.Type])

    useEffect(() => {
        if (props.modified) setParams({...props.modified});
    }, [props.modified])

    return <div>
        <Form
            onSubmitCapture={e => {
                e.preventDefault()

                ipcRenderer.invoke("SaveYakScript", params).then((data) => {
                    info("创建 / 保存 Yak 脚本成功")
                    props.onCreated && props.onCreated(data)
                    props.onChanged && props.onChanged(data)
                    setTimeout(() => ipcRenderer.invoke("change-main-menu"), 100);
                }).catch((e: any) => {
                    failed(`保存 Yak 模块失败: ${e}`)
                })
            }}
            labelCol={{span: 5}} wrapperCol={{span: 14}}
        >
            <SelectOne disabled={!!modified} label={"模块类型"}
                       data={[
                           {value: "yak", text: "Yak 原生模块"},
                           {value: "mitm", text: "MITM 模块"},
                           {value: "packet-hack", text: "Packet 检查"},
                           {value: "port-scan", text: "端口扫描插件"},
                           {value: "codec", text: "Codec 模块"},
                           {value: "nuclei", text: "nuclei Yaml模块"},
                       ]}
                       setValue={Type => {
                           if (["packet-hack", "codec", "nuclei"].includes(Type)) setParams({
                               ...params,
                               Type,
                               IsGeneralModule: false
                           })
                           else setParams({...params, Type})
                       }} value={params.Type}
            />
            <InputItem
                label={"Yak 模块名"} required={true}
                setValue={ScriptName => setParams({...params, ScriptName})} value={params.ScriptName}
            />
            <InputItem
                label={"简要描述"}
                setValue={Help => setParams({...params, Help})} value={params.Help}
            />
            <InputItem
                label={"模块作者"} setValue={Author => setParams({...params, Author})} value={params.Author}
            />
            <ManyMultiSelectForString
                label={"Tags"}
                data={[
                    {value: "教程", label: "教程"}
                ]} mode={"tags"}
                setValue={Tags => setParams({...params, Tags})} value={params.Tags}
            />
            {["yak", "mitm"].includes(params.Type) && <Form.Item label={"增加参数"}>
                <Button type={"link"}
                        onClick={() => {
                            let m = showModal({
                                title: "添加新参数",
                                width: "60%",
                                content: <>
                                    <CreateYakScriptParamForm onCreated={param => {
                                        let flag = false
                                        const paramArr = (params.Params || []).map(item => {
                                            if (item.Field === param.Field) {
                                                flag = true
                                                info(`参数 [${param.Field}]${param.FieldVerbose ? `(${param.FieldVerbose})` : ""} 已经存在,已覆盖旧参数`)
                                                return param
                                            }
                                            return item
                                        })
                                        if (!flag) paramArr.push(param)
                                        setParams({...params, Params: [...paramArr]})
                                        m.destroy()
                                    }}/>
                                </>
                            })
                        }}
                >添加 / 设置一个参数 <PlusOutlined/></Button>
            </Form.Item>}
            {params.Params.length > 0 ? <Form.Item label={" "} colon={false}>
                <List
                    size={"small"} bordered={true} pagination={false}
                    renderItem={p => {
                        return <List.Item key={p.Field}>
                            <Space size={1}>
                                {p.Required && <div className="form-item-required-title">*</div>}
                                参数名:
                            </Space>
                            <Tag
                                color={"geekblue"}>{p.FieldVerbose && `${p.FieldVerbose} / `}{p.Field}
                            </Tag>
                            类型:<Tag color={"blue"}>{p.TypeVerbose} {p.DefaultValue && `默认值:${p.DefaultValue}`}</Tag>
                            {p.DefaultValue && `默认值为: ${p.DefaultValue}`}
                            {!isNucleiPoC && <Space style={{marginLeft: 20}}>
                                <Button size={"small"} onClick={() => {
                                    let m = showModal({
                                        title: `修改已知参数: ${p.FieldVerbose}(${p.Field})`,
                                        width: "60%",
                                        content: <>
                                            <CreateYakScriptParamForm
                                                modifiedParam={p}
                                                onCreated={param => {
                                                    setParams({
                                                        ...params, Params: [
                                                            ...params.Params.filter(i => i.Field !== param.Field),
                                                            param,
                                                        ]
                                                    })
                                                    m.destroy()
                                                }}/>
                                        </>
                                    })
                                }}>修改参数</Button>
                                <Popconfirm
                                    title={"确认要删除该参数吗?"}
                                    onConfirm={e => {
                                        setParamsLoading(true)
                                        setParams({...params, Params: params.Params.filter(i => i.Field !== p.Field)})
                                    }}
                                >
                                    <Button size={"small"} type={"link"} danger={true}>删除参数</Button>
                                </Popconfirm>
                            </Space>}
                        </List.Item>
                    }}
                    dataSource={params.Params}
                >

                </List>
            </Form.Item> : ""}
            {params.Type === "yak" && <>
                <SwitchItem
                    label={"启用插件联动 UI"} value={params.EnablePluginSelector} formItemStyle={{marginBottom: 2}}
                    setValue={EnablePluginSelector => setParams({...params, EnablePluginSelector})}
                />
                {params.EnablePluginSelector && <ManyMultiSelectForString
                    label={"联动插件类型"} value={params.PluginSelectorTypes}
                    data={["mitm", "port-scan"].map(i => {
                        return {value: i, label: getPluginTypeVerbose(i)}
                    })} mode={"multiple"}
                    setValue={res => {
                        setParams({...params, PluginSelectorTypes: res})
                    }}
                    help={"通过 cli.String(`yakit-plugin-file`) 获取用户选择的插件"}
                />}
            </>}
            <Form.Item label={"源码"} help={<>
                <Space>
                    <Button icon={<FullscreenOutlined/>}
                            onClick={() => {
                                setFullscreen(true)
                                let m = showDrawer({
                                    title: "Edit Code",
                                    width: "100%",
                                    closable: false,
                                    keyboard: false,
                                    content: <>
                                        <YakScriptLargeEditor
                                            script={params}
                                            onExit={(data) => {
                                                m.destroy()
                                                setFullscreen(false)
                                                ipcRenderer.invoke("QueryYakScript", {})
                                            }}
                                            onUpdate={(data: YakScript) => {
                                                props.onChanged && props.onChanged(data)
                                                setParams({...data})
                                            }}
                                        />
                                    </>
                                })
                            }}
                            type={"link"} style={{
                        marginBottom: 12, marginTop: 6
                    }}>大屏模式</Button>
                    {!["packet-hack", "codec", "nuclei"].includes(params.Type) && <Checkbox
                        name={"默认启动"}
                        style={{
                            marginBottom: 12, marginTop: 6
                        }}
                        checked={params.IsGeneralModule}
                        onChange={() => setParams({
                            ...params,
                            IsGeneralModule: !params.IsGeneralModule
                        })}>
                        默认启动 <Tooltip
                        title={"设置默认启动后,将在恰当时候启动该插件(Yak插件不会自动启动,但会自动增加在左侧基础安全工具菜单栏)"}
                    >
                        <Button type={"link"} icon={<QuestionCircleOutlined/>}/>
                    </Tooltip>
                    </Checkbox>}
                </Space>
            </>}>
                {!fullscreen && <div style={{height: 400}}>
                    <YakEditor
                        type={"yak"}
                        setValue={Content => setParams({...params, Content})}
                        value={params.Content}
                    />
                </div>}
            </Form.Item>
            <Form.Item colon={false} label={" "}>
                <Space>
                    <Button type="primary" htmlType="submit"> {modified ? "修改当前" : "创建新的"} Yak 模块 </Button>
                    <Button
                        // type={primary ? "primary" : undefined}
                        disabled={[
                            // "mitm",
                            "",
                        ].includes(params.Type)}
                        onClick={() => {
                            setLoading(true)
                            ipcRenderer.invoke("SaveYakScript", params).then((data: YakScript) => {
                                info("创建 / 保存 Yak 脚本成功")
                                setModified(data)
                                setParams(data)
                                props.onChanged && props.onChanged(data)
                                // YakScriptParamsSetter
                                executeYakScriptByParams(data)
                            }).catch((e: any) => {
                                failed(`保存 Yak 模块失败: ${e}`)
                            }).finally(() => {
                                setTimeout(() => setLoading(false), 400)
                            })
                        }}> 调试:创建(修改)并立即执行 </Button>
                </Space>
            </Form.Item>
        </Form>
    </div>
}
Example #13
Source File: editors.tsx    From yakit with GNU Affero General Public License v3.0 4 votes vote down vote up
HTTPPacketEditor: React.FC<HTTPPacketEditorProp> = React.memo((props) => {
    const isResponse = props.isResponse || (new Buffer(props.originValue.subarray(0, 5)).toString("utf8")).startsWith("HTTP/")
    const [mode, setMode] = useState("text");
    const [strValue, setStrValue] = useState(new Buffer(props.originValue).toString('utf8'));
    const [hexValue, setHexValue] = useState<Uint8Array>(new Buffer(props.originValue))
    const [searchValue, setSearchValue] = useState("");
    const [monacoEditor, setMonacoEditor] = useState<IMonacoEditor>();
    const [fontSize, setFontSize] = useState(12);
    const [highlightDecorations, setHighlightDecorations] = useState<any[]>([]);
    const [noWordwrap, setNoWordwrap] = useState(false);

    const highlightActive = useMemoizedFn((search: string, regexp?: boolean) => {
        if (!monacoEditor) {
            return
        }

        // @ts-ignore
        // let range = monacoEditor?.getModel().findMatches(search, false, !!regexp, false, null, false)
        // if (range && range.length > 0) {
        //     const decs = monacoEditor.deltaDecorations(highlightDecorations, range.map(i => {
        //         return {
        //             id: `highlight[${searchValue}]`,
        //             range: i.range,
        //             options: {
        //                 isWholeLine: false,
        //                 inlineClassName: 'monacoInlineHighlight'
        //             }
        //         } as any
        //     }))
        //     setHighlightDecorations(decs)
        // }
    })

    /*如何实现 monaco editor 高亮?*/
    // https://microsoft.github.io/monaco-editor/playground.html#interacting-with-the-editor-line-and-inline-decorations

    // hex editor
    const [nonce, setNonce] = useState(0);
    // The callback facilitates updates to the source data.
    const handleSetValue = React.useCallback((offset, value) => {
        hexValue[offset] = value;
        setNonce(v => (v + 1));
        setHexValue(new Buffer(hexValue))
    }, [hexValue]);

    useEffect(() => {
        if (!props.defaultHeight) {
            return
        }

        setStrValue(props.defaultStringValue || "")
        setHexValue(Buffer.from(props.defaultStringValue || ""))
    }, [props.defaultStringValue])

    useEffect(() => {
        if (monacoEditor) {
            props.onEditor && props.onEditor(monacoEditor)
            monacoEditor.setSelection({startColumn: 0, startLineNumber: 0, endLineNumber: 0, endColumn: 0})
        }
        if (!props.simpleMode && !props.hideSearch && monacoEditor) {
            setHighlightDecorations(monacoEditor.deltaDecorations(highlightDecorations, []))
        }
    }, [monacoEditor])

    useEffect(() => {
        if (props.readOnly) {
            setStrValue(new Buffer(props.originValue).toString('utf8'))
            setHexValue(new Buffer(props.originValue))
        }
        if (props.readOnly && monacoEditor) {
            monacoEditor.setSelection({startColumn: 0, startLineNumber: 0, endLineNumber: 0, endColumn: 0})
        }
    }, [
        props.originValue,
        props.readOnly,
        // monacoEditor,
    ])

    useEffect(() => {
        if (props.readOnly) {
            return
        }
        setStrValue(new Buffer(props.originValue).toString('utf8'))
        setHexValue(new Buffer(props.originValue))
    }, [props.refreshTrigger])

    useEffect(() => {
        props.onChange && props.onChange(Buffer.from(strValue))
    }, [strValue])

    useEffect(() => {
        props.onChange && props.onChange(hexValue)
    }, [hexValue])

    const empty = !!props.emptyOr && props.originValue.length == 0

    return <div style={{width: "100%", height: "100%"}}>
        <Card
            className={"flex-card"}
            size={"small"} loading={props.loading}
            bordered={props.bordered}
            style={{height: "100%", width: "100%"}}
            title={!props.noHeader && <Space>
                {!props.noTitle && <span>{isResponse ? "Response" : "Request"}</span>}
                {!props.simpleMode ? (!props.noHex && <SelectOne
                    label={" "}
                    colon={false} value={mode}
                    setValue={e => {
                        if (mode === "text" && e === "hex") {
                            setHexValue(new Buffer(strValue))
                        }

                        if (mode === "hex" && e === "text") {
                            setStrValue(Buffer.from(hexValue).toString("utf8"))
                        }
                        setMode(e)
                    }}
                    data={[
                        {text: "TEXT", value: "text"},
                        {text: "HEX", value: "hex"},
                    ]} size={"small"} formItemStyle={{marginBottom: 0}}
                />) : <Form.Item style={{marginBottom: 0}}>
                    <Tag color={"geekblue"}>{mode.toUpperCase()}</Tag>
                </Form.Item>}
                {mode === "text" && !props.hideSearch && !props.simpleMode && <Input.Search
                    size={"small"} value={searchValue}
                    onChange={e => {
                        setSearchValue(e.target.value)
                    }} enterButton={true}
                    onSearch={e => {
                        highlightActive(searchValue)
                    }}
                />}
            </Space>}
            bodyStyle={{padding: 0, width: "100%", display: "flex", flexDirection: "column"}}
            extra={!props.noHeader && <Space size={2}>
                {props.extra}
                {props.sendToWebFuzzer && <Button
                    size={"small"}
                    type={"primary"}
                    icon={<ThunderboltFilled/>}
                    onClick={() => {
                        ipcRenderer.invoke("send-to-tab", {
                            type: "fuzzer",
                            data: {isHttps: props.defaultHttps || false, request: strValue}
                        })
                    }}
                >FUZZ</Button>}
                <Tooltip title={"不自动换行"}>
                    <Button
                        size={"small"}
                        type={noWordwrap ? "link" : "primary"}
                        icon={<EnterOutlined/>}
                        onClick={() => {
                            setNoWordwrap(!noWordwrap)
                        }}
                    />
                </Tooltip>
                {!props.simpleMode && <Popover
                    title={"配置编辑器"}
                    content={<>
                        <Form
                            onSubmitCapture={e => {
                                e.preventDefault()
                            }} size={"small"}
                            layout={"horizontal"}
                            wrapperCol={{span: 16}}
                            labelCol={{span: 8}}
                        >
                            <SelectOne
                                formItemStyle={{marginBottom: 4}}
                                label={"字号"}
                                data={[
                                    {text: "小", value: 12},
                                    {text: "中", value: 16},
                                    {text: "大", value: 20},
                                ]} value={fontSize} setValue={setFontSize}
                            />
                            <Form.Item label={"全屏"}>
                                <Button
                                    size={"small"}
                                    type={"link"}
                                    icon={<FullscreenOutlined/>}
                                    onClick={() => {
                                        showDrawer({
                                            title: "全屏", width: "100%",
                                            content: <div style={{height: "100%", width: "100%"}}>
                                                <HTTPPacketEditor
                                                    {...props} disableFullscreen={true}
                                                    defaultHeight={670}

                                                />
                                            </div>
                                        })
                                    }}
                                />
                            </Form.Item>
                        </Form>
                    </>}
                >
                    <Button
                        icon={<SettingOutlined/>}
                        type={"link"} size={"small"}
                    />
                </Popover>}
            </Space>}
        >
            <div style={{flex: 1}}>
                {empty && props.emptyOr}
                {mode === "text" && !empty && <YakEditor
                    loading={props.loading}
                    type={props.language || (isResponse ? "html" : "http")}
                    value={
                        props.readOnly && props.originValue.length > 0 ?
                            new Buffer(props.originValue).toString() : strValue
                    }
                    readOnly={props.readOnly}
                    setValue={setStrValue} noWordWrap={noWordwrap}
                    fontSize={fontSize}
                    actions={[
                        ...(props.actions || []),
                        ...MonacoEditorCodecActions,
                        ...(props.noPacketModifier ? [] : MonacoEditorMutateHTTPRequestActions),
                        ...(props.noPacketModifier ? [] : MonacoEditorFullCodecActions),
                    ]}
                    editorDidMount={editor => {
                        setMonacoEditor(editor)
                    }}

                    {...props.extraEditorProps}
                />}
                {mode === "hex" && !empty && <HexEditor
                    className={props.system === 'Windows_NT' ? 'hex-editor-style' : ''}
                    showAscii={true}
                    data={hexValue}
                    showRowLabels={true}
                    showColumnLabels={false}
                    nonce={nonce}
                    onSetValue={props.readOnly ? undefined : handleSetValue}
                />}
            </div>
        </Card>
    </div>
})