@ant-design/icons#UndoOutlined TypeScript Examples

The following examples show how to use @ant-design/icons#UndoOutlined. 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: icons.tsx    From posthog-foss with MIT License 6 votes vote down vote up
export function IconSeekBack({
    onClick,
    time,
}: {
    onClick: () => void
    time: number
    className?: string
}): JSX.Element {
    return (
        <BaseIcon onClick={onClick} className="rrweb-controller-icon-seek">
            <>
                <span className="seek-seconds">{time}</span>
                <UndoOutlined className="seek-icon" rotate={90} />
            </>
        </BaseIcon>
    )
}
Example #2
Source File: UndoRedo.tsx    From dnde with GNU General Public License v3.0 6 votes vote down vote up
UndoRedo = ({ undoCallback, redoCallback }: UndoRedoProps) => {
  return (
    <div
      style={{
        position: 'fixed',
        padding: '8px',
        display: 'flex',
        flexDirection: 'column',
        rowGap: '4px',
        zIndex: 200,
      }}
    >
      <Tooltip mouseEnterDelay={0.5} color="cyan" title="undo" placement="right">
        <Button
          disabled={UNDOREDO.isUndoEmpty()}
          onClick={undoCallback}
          type="default"
          size="large"
          style={{ background: '#fff' }}
          icon={<UndoOutlined />}
        />
      </Tooltip>

      <Tooltip mouseEnterDelay={0.5} color="cyan" title="redo" placement="right">
        <Button
          disabled={UNDOREDO.isRedoEmpty()}
          onClick={redoCallback}
          type="default"
          style={{ background: '#fff' }}
          size="large"
          icon={<RedoOutlined />}
        />
      </Tooltip>
    </div>
  );
}
Example #3
Source File: config-toolbar.ts    From XFlow with MIT License 6 votes vote down vote up
registerIcon = () => {
  IconStore.set('SaveOutlined', SaveOutlined)
  IconStore.set('UndoOutlined', UndoOutlined)
  IconStore.set('RedoOutlined', RedoOutlined)
  IconStore.set('VerticalAlignTopOutlined', VerticalAlignTopOutlined)
  IconStore.set('VerticalAlignBottomOutlined', VerticalAlignBottomOutlined)
  IconStore.set('GatewayOutlined', GatewayOutlined)
  IconStore.set('GroupOutlined', GroupOutlined)
  IconStore.set('UngroupOutlined', UngroupOutlined)
  IconStore.set('CopyOutlined', CopyOutlined)
  IconStore.set('SnippetsOutlined', SnippetsOutlined)
}
Example #4
Source File: undo.tsx    From imove with MIT License 6 votes vote down vote up
Save: React.FC<IProps> = makeBtnWidget({
  tooltip: '撤销',
  handler: shortcuts.undo.handler,
  getIcon() {
    return <UndoOutlined />;
  },
  disabled(flowChart: Graph) {
    return !flowChart.canUndo();
  },
})
Example #5
Source File: UndoRedo.tsx    From datart with Apache License 2.0 6 votes vote down vote up
UndoBtn: FC<{
  fn: MouseEventHandler<HTMLElement> | undefined;
  title: string;
}> = ({ fn, title }) => {
  const pastState = useSelector(selectPastState);
  const canUndo = useMemo(() => !!pastState.length, [pastState.length]);
  return (
    <Tooltip title={title}>
      <ToolbarButton disabled={!canUndo} onClick={fn} icon={<UndoOutlined />} />
    </Tooltip>
  );
}
Example #6
Source File: index.tsx    From visual-layout with MIT License 5 votes vote down vote up
History: React.FC<{}> = () => {
  const { appService } = useContext(AppContext);

  const page = Object.values(appService.project.getPages()).filter(
    ({ id }) => id === appService.project.currentId,
  )[0];

  const renderHistory = (): React.ReactNode => {
    return page?.history.history
      .slice()
      .filter(_ => _)
      .reverse()
      .map(history => (
        <HistoryList
          history={history}
          key={history.id}
          renderSpanIcon={(id: number) => (
            <span
              onClick={() => {
                page.returnHistory(id);
              }}
            >
              <Tooltip placement="right" title="回退版本">
                <RedoOutlined />
              </Tooltip>
            </span>
          )}
        />
      ));
  };

  const renderFutureHistory = (): React.ReactNode => {
    return page?.history.future
      .slice()
      .filter(_ => _)
      .reverse()
      .map(history => (
        <HistoryList
          className={styles.futureHistory}
          history={history}
          key={history.id}
          renderSpanIcon={(id: number) => (
            <span
              onClick={() => {
                page.recoveryHistory(id);
              }}
            >
              <Tooltip placement="right" title="还原版本">
                <UndoOutlined />
              </Tooltip>
            </span>
          )}
        />
      ));
  };

  return (
    <div className={styles.container}>
      {renderFutureHistory()}
      {renderHistory()}
    </div>
  );
}
Example #7
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 #8
Source File: SlideViewer.tsx    From slim with Apache License 2.0 4 votes vote down vote up
render (): React.ReactNode {
    const rois: dmv.roi.ROI[] = []
    const segments: dmv.segment.Segment[] = []
    const mappings: dmv.mapping.ParameterMapping[] = []
    const annotationGroups: dmv.annotation.AnnotationGroup[] = []
    rois.push(...this.volumeViewer.getAllROIs())
    segments.push(...this.volumeViewer.getAllSegments())
    mappings.push(...this.volumeViewer.getAllParameterMappings())
    annotationGroups.push(...this.volumeViewer.getAllAnnotationGroups())

    const openSubMenuItems = ['specimens', 'opticalpaths', 'annotations']

    let report: React.ReactNode
    const dataset = this.state.generatedReport
    if (dataset !== undefined) {
      report = <Report dataset={dataset} />
    }

    let annotationMenuItems: React.ReactNode
    if (rois.length > 0) {
      annotationMenuItems = (
        <AnnotationList
          rois={rois}
          selectedRoiUIDs={this.state.selectedRoiUIDs}
          visibleRoiUIDs={this.state.visibleRoiUIDs}
          onSelection={this.handleAnnotationSelection}
          onVisibilityChange={this.handleAnnotationVisibilityChange}
        />
      )
    }

    const findingOptions = this.findingOptions.map(finding => {
      return (
        <Select.Option
          key={finding.CodeValue}
          value={finding.CodeValue}
        >
          {finding.CodeMeaning}
        </Select.Option>
      )
    })

    const geometryTypeOptionsMapping: { [key: string]: React.ReactNode } = {
      point: <Select.Option key='point' value='point'>Point</Select.Option>,
      circle: <Select.Option key='circle' value='circle'>Circle</Select.Option>,
      box: <Select.Option key='box' value='box'>Box</Select.Option>,
      polygon: <Select.Option key='polygon' value='polygon'>Polygon</Select.Option>,
      line: <Select.Option key='line' value='line'>Line</Select.Option>,
      freehandpolygon: (
        <Select.Option key='freehandpolygon' value='freehandpolygon'>
          Polygon (freehand)
        </Select.Option>
      ),
      freehandline: (
        <Select.Option key='freehandline' value='freehandline'>
          Line (freehand)
        </Select.Option>
      )
    }

    const selections: React.ReactNode[] = [
      (
        <Select
          style={{ minWidth: 130 }}
          onSelect={this.handleAnnotationFindingSelection}
          key='annotation-finding'
          defaultActiveFirstOption
        >
          {findingOptions}
        </Select>
      )
    ]

    const selectedFinding = this.state.selectedFinding
    if (selectedFinding !== undefined) {
      const key = _buildKey(selectedFinding)
      this.evaluationOptions[key].forEach(evaluation => {
        const evaluationOptions = evaluation.values.map(code => {
          return (
            <Select.Option
              key={code.CodeValue}
              value={code.CodeValue}
              label={evaluation.name}
            >
              {code.CodeMeaning}
            </Select.Option>
          )
        })
        selections.push(
          <>
            {evaluation.name.CodeMeaning}
            <Select
              style={{ minWidth: 130 }}
              onSelect={this.handleAnnotationEvaluationSelection}
              allowClear
              onClear={this.handleAnnotationEvaluationClearance}
              defaultActiveFirstOption={false}
            >
              {evaluationOptions}
            </Select>
          </>
        )
      })
      const geometryTypeOptions = this.geometryTypeOptions[key].map(name => {
        return geometryTypeOptionsMapping[name]
      })
      selections.push(
        <Select
          style={{ minWidth: 130 }}
          onSelect={this.handleAnnotationGeometryTypeSelection}
          key='annotation-geometry-type'
        >
          {geometryTypeOptions}
        </Select>
      )
      selections.push(
        <Checkbox
          onChange={this.handleAnnotationMeasurementActivation}
          key='annotation-measurement'
        >
          measure
        </Checkbox>
      )
    }

    const specimenMenu = (
      <Menu.SubMenu key='specimens' title='Specimens'>
        <SpecimenList
          metadata={this.props.slide.volumeImages[0]}
          showstain={false}
        />
      </Menu.SubMenu>
    )

    const equipmentMenu = (
      <Menu.SubMenu key='equipment' title='Equipment'>
        <Equipment metadata={this.props.slide.volumeImages[0]} />
      </Menu.SubMenu>
    )

    const defaultOpticalPathStyles: {
      [identifier: string]: {
        opacity: number
        color?: number[]
        limitValues?: number[]
      }
    } = {}
    const opticalPathMetadata: {
      [identifier: string]: dmv.metadata.VLWholeSlideMicroscopyImage[]
    } = {}
    const opticalPaths = this.volumeViewer.getAllOpticalPaths()
    opticalPaths.sort((a, b) => {
      if (a.identifier < b.identifier) {
        return -1
      } else if (a.identifier > b.identifier) {
        return 1
      }
      return 0
    })
    opticalPaths.forEach(opticalPath => {
      const identifier = opticalPath.identifier
      const metadata = this.volumeViewer.getOpticalPathMetadata(identifier)
      opticalPathMetadata[identifier] = metadata
      const style = this.volumeViewer.getOpticalPathStyle(identifier)
      defaultOpticalPathStyles[identifier] = style
    })
    const opticalPathMenu = (
      <Menu.SubMenu key='opticalpaths' title='Optical Paths'>
        <OpticalPathList
          metadata={opticalPathMetadata}
          opticalPaths={opticalPaths}
          defaultOpticalPathStyles={defaultOpticalPathStyles}
          visibleOpticalPathIdentifiers={this.state.visibleOpticalPathIdentifiers}
          activeOpticalPathIdentifiers={this.state.activeOpticalPathIdentifiers}
          onOpticalPathVisibilityChange={this.handleOpticalPathVisibilityChange}
          onOpticalPathStyleChange={this.handleOpticalPathStyleChange}
          onOpticalPathActivityChange={this.handleOpticalPathActivityChange}
          selectedPresentationStateUID={this.state.selectedPresentationStateUID}
        />
      </Menu.SubMenu>
    )

    let presentationStateMenu
    console.log('DEBUG: ', this.state.presentationStates)
    if (this.state.presentationStates.length > 0) {
      const presentationStateOptions = this.state.presentationStates.map(
        presentationState => {
          return (
            <Select.Option
              key={presentationState.SOPInstanceUID}
              value={presentationState.SOPInstanceUID}
              dropdownMatchSelectWidth={false}
              size='small'
            >
              {presentationState.ContentDescription}
            </Select.Option>
          )
        }
      )
      presentationStateMenu = (
        <Menu.SubMenu key='presentationStates' title='Presentation States'>
          <Space align='center' size={20} style={{ padding: '14px' }}>
            <Select
              style={{ minWidth: 200, maxWidth: 200 }}
              onSelect={this.handlePresentationStateSelection}
              key='presentation-states'
              defaultValue={this.props.selectedPresentationStateUID}
              value={this.state.selectedPresentationStateUID}
            >
              {presentationStateOptions}
            </Select>
            <Tooltip title='Reset'>
              <Btn
                icon={<UndoOutlined />}
                type='primary'
                onClick={this.handlePresentationStateReset}
              />
            </Tooltip>
          </Space>
        </Menu.SubMenu>
      )
    }

    let segmentationMenu
    if (segments.length > 0) {
      const defaultSegmentStyles: {
        [segmentUID: string]: {
          opacity: number
        }
      } = {}
      const segmentMetadata: {
        [segmentUID: string]: dmv.metadata.Segmentation[]
      } = {}
      const segments = this.volumeViewer.getAllSegments()
      segments.forEach(segment => {
        defaultSegmentStyles[segment.uid] = this.volumeViewer.getSegmentStyle(
          segment.uid
        )
        segmentMetadata[segment.uid] = this.volumeViewer.getSegmentMetadata(
          segment.uid
        )
      })
      segmentationMenu = (
        <Menu.SubMenu key='segmentations' title='Segmentations'>
          <SegmentList
            segments={segments}
            metadata={segmentMetadata}
            defaultSegmentStyles={defaultSegmentStyles}
            visibleSegmentUIDs={this.state.visibleSegmentUIDs}
            onSegmentVisibilityChange={this.handleSegmentVisibilityChange}
            onSegmentStyleChange={this.handleSegmentStyleChange}
          />
        </Menu.SubMenu>
      )
      openSubMenuItems.push('segmentations')
    }

    let parametricMapMenu
    if (mappings.length > 0) {
      const defaultMappingStyles: {
        [mappingUID: string]: {
          opacity: number
        }
      } = {}
      const mappingMetadata: {
        [mappingUID: string]: dmv.metadata.ParametricMap[]
      } = {}
      mappings.forEach(mapping => {
        defaultMappingStyles[mapping.uid] = this.volumeViewer.getParameterMappingStyle(
          mapping.uid
        )
        mappingMetadata[mapping.uid] = this.volumeViewer.getParameterMappingMetadata(
          mapping.uid
        )
      })
      parametricMapMenu = (
        <Menu.SubMenu key='parmetricmaps' title='Parametric Maps'>
          <MappingList
            mappings={mappings}
            metadata={mappingMetadata}
            defaultMappingStyles={defaultMappingStyles}
            visibleMappingUIDs={this.state.visibleMappingUIDs}
            onMappingVisibilityChange={this.handleMappingVisibilityChange}
            onMappingStyleChange={this.handleMappingStyleChange}
          />
        </Menu.SubMenu>
      )
      openSubMenuItems.push('parametricmaps')
    }

    let annotationGroupMenu
    if (annotationGroups.length > 0) {
      const defaultAnnotationGroupStyles: {
        [annotationGroupUID: string]: {
          opacity: number
        }
      } = {}
      const annotationGroupMetadata: {
        [annotationGroupUID: string]: dmv.metadata.MicroscopyBulkSimpleAnnotations
      } = {}
      const annotationGroups = this.volumeViewer.getAllAnnotationGroups()
      annotationGroups.forEach(annotationGroup => {
        defaultAnnotationGroupStyles[annotationGroup.uid] = this.volumeViewer.getAnnotationGroupStyle(
          annotationGroup.uid
        )
        annotationGroupMetadata[annotationGroup.uid] = this.volumeViewer.getAnnotationGroupMetadata(
          annotationGroup.uid
        )
      })
      annotationGroupMenu = (
        <Menu.SubMenu key='annotationGroups' title='Annotation Groups'>
          <AnnotationGroupList
            annotationGroups={annotationGroups}
            metadata={annotationGroupMetadata}
            defaultAnnotationGroupStyles={defaultAnnotationGroupStyles}
            visibleAnnotationGroupUIDs={this.state.visibleAnnotationGroupUIDs}
            onAnnotationGroupVisibilityChange={this.handleAnnotationGroupVisibilityChange}
            onAnnotationGroupStyleChange={this.handleAnnotationGroupStyleChange}
          />
        </Menu.SubMenu>
      )
      openSubMenuItems.push('annotationGroups')
    }

    let toolbar
    let toolbarHeight = '0px'
    if (this.props.enableAnnotationTools) {
      toolbar = (
        <Row>
          <Button
            tooltip='Draw ROI [d]'
            icon={FaDrawPolygon}
            onClick={this.handleRoiDrawing}
            isSelected={this.state.isRoiDrawingActive}
          />
          <Button
            tooltip='Modify ROIs [m]'
            icon={FaHandPointer}
            onClick={this.handleRoiModification}
            isSelected={this.state.isRoiModificationActive}
          />
          <Button
            tooltip='Translate ROIs [t]'
            icon={FaHandPaper}
            onClick={this.handleRoiTranslation}
            isSelected={this.state.isRoiTranslationActive}
          />
          <Button
            tooltip='Remove selected ROI [r]'
            onClick={this.handleRoiRemoval}
            icon={FaTrash}
          />
          <Button
            tooltip='Show/Hide ROIs [v]'
            icon={this.state.areRoisHidden ? FaEye : FaEyeSlash}
            onClick={this.handleRoiVisibilityChange}
            isSelected={this.state.areRoisHidden}
          />
          <Button
            tooltip='Save ROIs [s]'
            icon={FaSave}
            onClick={this.handleReportGeneration}
          />
        </Row>
      )
      toolbarHeight = '50px'
    }

    /* It would be nicer to use the ant Spin component, but that causes issues
     * with the positioning of the viewport.
     */
    let loadingDisplay = 'none'
    if (this.state.isLoading) {
      loadingDisplay = 'block'
    }

    return (
      <Layout style={{ height: '100%' }} hasSider>
        <Layout.Content style={{ height: '100%' }}>
          {toolbar}

          <div className='dimmer' style={{ display: loadingDisplay }} />
          <div className='spinner' style={{ display: loadingDisplay }} />
          <div
            style={{
              height: `calc(100% - ${toolbarHeight})`,
              overflow: 'hidden'
            }}
            ref={this.volumeViewportRef}
          />

          <Modal
            visible={this.state.isAnnotationModalVisible}
            title='Configure annotations'
            onOk={this.handleAnnotationConfigurationCompletion}
            onCancel={this.handleAnnotationConfigurationCancellation}
            okText='Select'
          >
            <Space align='start' direction='vertical'>
              {selections}
            </Space>
          </Modal>

          <Modal
            visible={this.state.isReportModalVisible}
            title='Verify and save report'
            onOk={this.handleReportVerification}
            onCancel={this.handleReportCancellation}
            okText='Save'
          >
            {report}
          </Modal>
        </Layout.Content>

        <Layout.Sider
          width={300}
          reverseArrow
          style={{
            borderLeft: 'solid',
            borderLeftWidth: 0.25,
            overflow: 'hidden',
            background: 'none'
          }}
        >
          <Menu
            mode='inline'
            defaultOpenKeys={openSubMenuItems}
            style={{ height: '100%' }}
            inlineIndent={14}
            forceSubMenuRender
          >
            <Menu.SubMenu key='label' title='Slide label'>
              <Menu.Item style={{ height: '100%' }}>
                <div
                  style={{ height: '220px' }}
                  ref={this.labelViewportRef}
                />
              </Menu.Item>
            </Menu.SubMenu>
            {specimenMenu}
            {equipmentMenu}
            {opticalPathMenu}
            {presentationStateMenu}
            <Menu.SubMenu key='annotations' title='Annotations'>
              {annotationMenuItems}
            </Menu.SubMenu>
            {annotationGroupMenu}
            {segmentationMenu}
            {parametricMapMenu}
          </Menu>
        </Layout.Sider>
      </Layout>
    )
  }
Example #9
Source File: index.tsx    From foodie with MIT License 4 votes vote down vote up
Home: React.FC<IProps> = (props) => {
    const state = useSelector((state: IRootReducer) => ({
        newsFeed: state.newsFeed,
        auth: state.auth,
        error: state.error.newsFeedError,
        isLoadingFeed: state.loading.isLoadingFeed,
        isLoadingCreatePost: state.loading.isLoadingCreatePost
    }), shallowEqual);
    const dispatch = useDispatch();
    const { isOpen, openModal, closeModal } = useModal();
    const from = props.location.state?.from || null;


    useDocumentTitle('Foodie | Social Network');
    useEffect(() => {
        console.log('TRIGGER', from)
        if (state.newsFeed.items.length === 0 || from === '/') {
            dispatch(clearNewsFeed());
            dispatch(getNewsFeedStart({ offset: 0 }));
        }

        socket.on('newFeed', () => {
            dispatch(hasNewFeed());
        });
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    const fetchNewsFeed = () => {
        dispatch(getNewsFeedStart({ offset: state.newsFeed.offset }));
    };

    const likeCallback = (postID: string, state: boolean, newLikeCount: number) => {
        dispatch(updatePostLikes(postID, state, newLikeCount));
    }

    const updateSuccessCallback = (post: IPost) => {
        dispatch(updateFeedPost(post));
    }

    const deleteSuccessCallback = (postID: string) => {
        dispatch(deleteFeedPost(postID));
    }

    const dispatchCreatePost = (form: FormData) => {
        dispatch(createPostStart(form));
    }

    const onClickNewFeed = () => {
        dispatch(clearNewsFeed());
        dispatch(getNewsFeedStart({ offset: 0 }));
        dispatch(hasNewFeed(false));
    }

    const infiniteRef = useInfiniteScroll({
        loading: state.isLoadingFeed,
        hasNextPage: !state.error && state.newsFeed.offset > 0,
        onLoadMore: fetchNewsFeed,
        scrollContainer: 'window',
    });

    return (
        <div className="laptop:px-6% pt-20 flex items-start">
            {/*  --- SIDE MENU --- */}
            <div className="hidden laptop:block laptop:w-1/4 laptop:rounded-md bg-white laptop:sticky laptop:top-20 mr-4 laptop:shadow-lg divide-y-2 dark:bg-indigo-1000">
                {props.isAuth && (
                    <SideMenu username={state.auth.username} profilePicture={state.auth.profilePicture?.url} />
                )}
            </div>
            <div className="w-full laptop:w-2/4 relative">
                {/* --- CREATE POST INPUT ---- */}
                {props.isAuth && (
                    <div className="flex items-center justify-start mb-4 px-4 laptop:px-0">
                        <Avatar url={state.auth.profilePicture?.url} className="mr-2" />
                        <div className="flex-grow">
                            <input
                                className="dark:bg-indigo-1000 dark:!border-gray-800 dark:text-white"
                                type="text"
                                placeholder="Create a post."
                                onClick={() => (!state.isLoadingCreatePost && !state.isLoadingFeed) && openModal()}
                                readOnly={state.isLoadingFeed || state.isLoadingCreatePost}
                            />
                        </div>
                    </div>
                )}
                {/*  --- HAS NEW FEED NOTIF --- */}
                {state.newsFeed.hasNewFeed && (
                    <button
                        className="sticky mt-2 top-16 left-0 right-0 mx-auto z-20 flex items-center"
                        onClick={onClickNewFeed}
                    >
                        <UndoOutlined className="flex items-center justify-center text-xl mr-4" />
                        New Feed Available
                    </button>
                )}
                {/* --- CREATE POST MODAL ----- */}
                {(props.isAuth && isOpen) && (
                    <CreatePostModal
                        isOpen={isOpen}
                        openModal={openModal}
                        closeModal={closeModal}
                        dispatchCreatePost={dispatchCreatePost}
                    />
                )}
                {(state.error && state.newsFeed.items.length === 0 && !state.isLoadingCreatePost) && (
                    <div className="flex flex-col w-full min-h-24rem px-8 items-center justify-center text-center">
                        {state.error.status_code === 404 ? (
                            <>
                                <CoffeeOutlined className="text-8xl text-gray-300 mb-4 dark:text-gray-800" />
                                <h5 className="text-gray-500">News feed is empty</h5>
                                <p className="text-gray-400">Start following people or create your first post.</p>
                                <br />
                                <Link className="underline dark:text-indigo-400" to={SUGGESTED_PEOPLE}>
                                    See Suggested People
                                </Link>
                            </>
                        ) : (
                            <h5 className="text-gray-500 italic">
                                {state.error?.error?.message || 'Something went wrong :('}
                            </h5>
                        )}
                    </div>
                )}
                {/* ---- LOADING INDICATOR ----- */}
                {(state.isLoadingFeed && state.newsFeed.items.length === 0) && (
                    <div className="mt-4 px-2 overflow-hidden space-y-6 pb-10">
                        <PostLoader />
                        <PostLoader />
                    </div>
                )}
                {state.isLoadingCreatePost && (
                    <div className="mt-4 px-2 overflow-hidden pb-10">
                        <PostLoader />
                    </div>
                )}
                {(!props.isAuth && !state.isLoadingFeed) && (
                    <div className="px-4 laptop:px-0 py-4 mb-4">
                        <h2 className="dark:text-white">Public posts that might <br />interest you.</h2>
                    </div>
                )}
                {/* ---- NEWS FEED ---- */}
                {(state.newsFeed.items.length !== 0) && (
                    <div className="mb-8">
                        <TransitionGroup component={null}>
                            <div ref={infiniteRef as React.RefObject<HTMLDivElement>}>
                                {state.newsFeed.items.map((post: IPost) => post.author && ( // avoid render posts with null author
                                    <CSSTransition
                                        timeout={500}
                                        classNames="fade"
                                        key={post.id}
                                    >
                                        <PostItem
                                            key={post.id}
                                            post={post}
                                            likeCallback={likeCallback}
                                        />
                                    </CSSTransition>
                                ))}
                            </div>
                        </TransitionGroup>
                        {state.isLoadingFeed && (
                            <div className="flex justify-center py-6">
                                <Loader />
                            </div>
                        )}
                        {state.error && (
                            <div className="flex justify-center py-6">
                                <p className="text-gray-400 italic">
                                    {state.error.error?.message || 'Something went wrong.'}
                                </p>
                            </div>
                        )}
                    </div>
                )}
            </div>
            {/* --- SUGGESTED PEOPLE --- */}
            <div className="hidden laptop:block laptop:w-1/4 laptop:sticky laptop:top-20 ml-4">
                {props.isAuth && (
                    <SuggestedPeople />
                )}
            </div>
            {/*  --- ALL POST MODALS (DELETE COMMENT NOT INCLUDED) --- */}
            <PostModals
                deleteSuccessCallback={deleteSuccessCallback}
                updateSuccessCallback={updateSuccessCallback}
            />
        </div >
    );
}
Example #10
Source File: StudentBanner.tsx    From office-hours with GNU General Public License v3.0 4 votes vote down vote up
export default function StudentBanner({
  queueId,
  editQuestion,
  leaveQueue,
}: StudentBannerProps): ReactElement {
  const { studentQuestion, studentQuestionIndex } = useStudentQuestion(queueId);
  const isQueueOnline = useQueue(queueId).queue?.room.startsWith("Online");

  switch (studentQuestion?.status) {
    case "Drafting":
      return (
        <Banner
          titleColor="#faad14"
          contentColor="#ffd666"
          title="Please finish writing your question"
          content="Your spot in queue has been temporarily reserved. Please finish describing your question to receive help and finish joining the queue."
          buttons={
            <>
              <Tooltip title="Delete Draft">
                <BannerButton
                  icon={<DeleteRowOutlined />}
                  onClick={leaveQueue}
                />
              </Tooltip>
              <Tooltip title="Finish Draft">
                <BannerButton
                  data-cy="edit-question"
                  icon={<EditOutlined />}
                  onClick={async () => {
                    editQuestion();
                  }}
                />
              </Tooltip>
            </>
          }
        />
      );
    case "Queued":
      return (
        <Banner
          titleColor="#3684C6"
          contentColor="#ABD4F3"
          title={
            <span>
              You are{" "}
              <BoldNumber>{toOrdinal(studentQuestionIndex + 1)}</BoldNumber> in
              queue
            </span>
          }
          buttons={
            <>
              <LeaveQueueButton leaveQueue={leaveQueue} />
              <Tooltip title="Edit Question">
                <BannerButton
                  data-cy="edit-question"
                  icon={<EditOutlined />}
                  onClick={editQuestion}
                />
              </Tooltip>
            </>
          }
          content={<QuestionDetailRow studentQuestion={studentQuestion} />}
        />
      );
    case "Helping":
      return (
        <Banner
          titleColor="#66BB6A"
          contentColor="#82C985"
          title={
            <span>
              <BoldNumber>{studentQuestion.taHelped.name}</BoldNumber> is coming
              to help you
            </span>
          }
          buttons={
            <>
              <LeaveQueueButton leaveQueue={leaveQueue} />
              {isQueueOnline && (
                <Tooltip title="Open Teams DM">
                  <BannerButton
                    icon={<TeamOutlined />}
                    onClick={() => {
                      window.open(
                        `https://teams.microsoft.com/l/chat/0/0?users=${studentQuestion.taHelped.email}`
                      );
                    }}
                  />
                </Tooltip>
              )}
            </>
          }
          content={
            <Bullets>
              <li>Please be dressed appropriately</li>
              <li>Be respectful of the TA’s time</li>
              <li>Come prepared with your question!</li>
            </Bullets>
          }
        />
      );
    case "ReQueueing":
      return (
        <Banner
          titleColor="#66BB6A"
          contentColor="#82C985"
          title={<span>Are you ready to re-join the queue?</span>}
          buttons={
            <>
              <LeaveQueueButton leaveQueue={leaveQueue} />
              <Tooltip title="Rejoin Queue">
                <Button
                  shape="circle"
                  style={{
                    marginLeft: "16px",
                    border: 0,
                  }}
                  icon={<UndoOutlined />}
                  onClick={async () => {
                    await API.questions.update(studentQuestion.id, {
                      status: OpenQuestionStatus.PriorityQueued,
                    });
                  }}
                  type="primary"
                  data-cy="re-join-queue"
                  size="large"
                />
              </Tooltip>
            </>
          }
          content={
            <Bullets>
              <li>Have you finished doing what the TA has told you?</li>
              <li>
                Once you hit requeue, you will be placed at the top of the queue
              </li>
            </Bullets>
          }
        />
      );
    case "PriorityQueued":
      return (
        <Banner
          titleColor="#3684C6"
          contentColor="#ABD4F3"
          title={
            <PriorityQueuedBanner>
              You are now in a priority queue, you will be helped soon. <br />
              <span style={{ fontSize: 16 }}>
                You were last helped by{" "}
                <span style={{ fontWeight: "bold" }}>
                  {studentQuestion.taHelped.name}
                </span>
                .
              </span>
            </PriorityQueuedBanner>
          }
          buttons={
            <>
              <LeaveQueueButton leaveQueue={leaveQueue} />
              <Tooltip title="Edit Question">
                <BannerButton
                  data-cy="edit-question"
                  icon={<EditOutlined />}
                  onClick={editQuestion}
                />
              </Tooltip>
            </>
          }
          content={<QuestionDetailRow studentQuestion={studentQuestion} />}
        />
      );
    default:
      return <div />;
  }
}
Example #11
Source File: TAQueueDetailButtons.tsx    From office-hours with GNU General Public License v3.0 4 votes vote down vote up
export default function TAQueueDetailButtons({
  courseId,
  queueId,
  question,
  hasUnresolvedRephraseAlert,
}: {
  courseId: number;
  queueId: number;
  question: Question;
  hasUnresolvedRephraseAlert: boolean;
}): ReactElement {
  const defaultMessage = useDefaultMessage();
  const { mutateQuestions } = useQuestions(queueId);

  const changeStatus = useCallback(
    async (status: QuestionStatus) => {
      await API.questions.update(question.id, { status });
      mutateQuestions();
    },
    [question.id, mutateQuestions]
  );
  const { isCheckedIn, isHelping } = useTAInQueueInfo(queueId);

  const openTeams = useTeams(queueId, question.creator.email, defaultMessage);

  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const sendRephraseAlert = async () => {
    const payload: RephraseQuestionPayload = {
      queueId,
      questionId: question.id,
      courseId,
    };
    try {
      await API.alerts.create({
        alertType: AlertType.REPHRASE_QUESTION,
        courseId,
        payload,
        targetUserId: question.creator.id,
      });
      await mutateQuestions();
      message.success("Successfully asked student to rephrase their question.");
    } catch (e) {
      //If the ta creates an alert that already exists the error is caught and nothing happens
    }
  };

  const helpStudent = () => {
    changeStatus(OpenQuestionStatus.Helping);
    openTeams();
  };
  const deleteQuestion = async () => {
    await changeStatus(
      question.status === OpenQuestionStatus.Drafting
        ? ClosedQuestionStatus.DeletedDraft
        : LimboQuestionStatus.TADeleted
    );
    await API.questions.notify(question.id);
  };

  useHotkeys(
    "shift+d",
    () => {
      if (isCheckedIn) {
        deleteQuestion();
      }
    },
    [question]
  );

  if (question.status === OpenQuestionStatus.Helping) {
    return (
      <>
        <Popconfirm
          title="Are you sure you want to send this student back to the queue?"
          okText="Yes"
          cancelText="No"
          onConfirm={async () => {
            message.success(PRORITY_QUEUED_MESSAGE_TEXT, 2);
            await changeStatus(LimboQuestionStatus.ReQueueing);
          }}
        >
          <Tooltip title="Requeue Student">
            <RequeueButton
              icon={<UndoOutlined />}
              data-cy="requeue-student-button"
            />
          </Tooltip>
        </Popconfirm>
        <Popconfirm
          title="Are you sure you can't find this student?"
          okText="Yes"
          cancelText="No"
          onConfirm={async () => {
            message.success(PRORITY_QUEUED_MESSAGE_TEXT, 2);
            await changeStatus(LimboQuestionStatus.CantFind);
            await API.questions.notify(question.id);
          }}
        >
          <Tooltip title="Can't Find">
            <CantFindButton
              shape="circle"
              icon={<CloseOutlined />}
              data-cy="cant-find-button"
            />
          </Tooltip>
        </Popconfirm>
        <Tooltip title="Finish Helping">
          <FinishHelpingButton
            icon={<CheckOutlined />}
            onClick={() => changeStatus(ClosedQuestionStatus.Resolved)}
            data-cy="finish-helping-button"
          />
        </Tooltip>
      </>
    );
  } else {
    const [canHelp, helpTooltip] = ((): [boolean, string] => {
      if (!isCheckedIn) {
        return [false, "You must check in to help students!"];
      } else if (isHelping) {
        return [false, "You are already helping a student"];
      } else {
        return [true, "Help Student"];
      }
    })();
    const [canRephrase, rephraseTooltip] = ((): [boolean, string] => {
      if (!isCheckedIn) {
        return [
          false,
          "You must check in to ask this student to rephrase their question",
        ];
      } else if (hasUnresolvedRephraseAlert) {
        return [
          false,
          "The student has already been asked to rephrase their question",
        ];
      } else if (question.status === OpenQuestionStatus.Drafting) {
        return [
          false,
          "The student must finish drafting before they can be asked to rephrase their question",
        ];
      } else {
        return [true, "Ask the student to add more detail to their question"];
      }
    })();
    return (
      <>
        <Popconfirm
          title="Are you sure you want to delete this question from the queue?"
          disabled={!isCheckedIn}
          okText="Yes"
          cancelText="No"
          onConfirm={async () => {
            await deleteQuestion();
          }}
        >
          <Tooltip
            title={
              isCheckedIn
                ? "Remove From Queue"
                : "You must check in to remove students from the queue"
            }
          >
            <span>
              {/* This span is a workaround for tooltip-on-disabled-button 
              https://github.com/ant-design/ant-design/issues/9581#issuecomment-599668648 */}
              <BannerDangerButton
                shape="circle"
                icon={<DeleteOutlined />}
                data-cy="remove-from-queue"
                disabled={!isCheckedIn}
              />
            </span>
          </Tooltip>
        </Popconfirm>
        <Tooltip title={rephraseTooltip}>
          <span>
            <BannerOrangeButton
              shape="circle"
              icon={<QuestionOutlined />}
              onClick={sendRephraseAlert}
              data-cy="request-rephrase-question"
              disabled={!canRephrase}
            />
          </span>
        </Tooltip>
        <Tooltip title={helpTooltip}>
          <span>
            <BannerPrimaryButton
              icon={<PhoneOutlined />}
              onClick={() => helpStudent()}
              disabled={!canHelp}
              data-cy="help-student"
            />
          </span>
        </Tooltip>
      </>
    );
  }
}