@ant-design/icons#QuestionOutlined TypeScript Examples

The following examples show how to use @ant-design/icons#QuestionOutlined. 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: FunctionDebuggerStatusbar.tsx    From next-basics with GNU General Public License v3.0 5 votes vote down vote up
export function FunctionDebuggerStatusbar({
  coverage,
  testStats,
}: FunctionDebuggerStatusbarProps): React.ReactElement {
  const coverageIsOk = coverage && coverage.status !== "failed";
  const totalCoverage = useMemo(
    () => (coverageIsOk ? getTotalCoverage(coverage) : null),
    [coverageIsOk, coverage]
  );
  const coverageStats = useMemo(
    () => (coverageIsOk ? getCoverageStats(coverage) : null),
    [coverageIsOk, coverage]
  );

  return (
    <div className={styles.debuggerStatusbar} data-override-theme="dark">
      <div className={styles.coverage}>
        {coverage == null ? (
          <span>
            <span className={styles.coverageIcon}>
              <QuestionOutlined />
            </span>
            <span>Coverage: expired</span>
          </span>
        ) : testStats?.failed > 0 ? (
          <span className={styles.hasFailedTests}>
            <span className={styles.coverageIcon}>
              <WarningOutlined />
            </span>
            <span>
              {testStats.failed}/{testStats.total} tests failed!
            </span>
          </span>
        ) : coverageIsOk ? (
          <>
            <span
              className={
                totalCoverage < 60
                  ? styles.coverageLow
                  : totalCoverage < 90
                  ? styles.coverageMedium
                  : totalCoverage < 100
                  ? styles.coverageHigh
                  : styles.coverageFull
              }
            >
              <span className={styles.coverageIcon}>
                {totalCoverage < 100 ? <WarningOutlined /> : <CheckOutlined />}
              </span>
              <span>Coverage: {totalCoverage}%</span>
            </span>
            {Object.entries(coverageStats).map(
              ([type, { covered, total, percentage }]) => (
                <span key={type} className={styles.subCoverage}>
                  <span>{upperFirst(type)}: </span>
                  <span>
                    {percentage}% ({covered}/{total})
                  </span>
                </span>
              )
            )}
          </>
        ) : (
          <span className={styles.coverageFailed}>
            <span className={styles.coverageIcon}>
              <CloseOutlined />
            </span>
            <span>{(coverage as RawCoverageFailed).error}</span>
          </span>
        )}
      </div>
    </div>
  );
}
Example #2
Source File: TAQueueListItem.tsx    From office-hours with GNU General Public License v3.0 5 votes vote down vote up
export default function TAQueueListItem({
  index,
  selected,
  question,
  onClick,
  showCheckbox,
}: {
  index: number | false;
  selected: boolean;
  question: Question;
  onClick: () => void;
  showCheckbox?: boolean;
}): ReactElement {
  const isDrafting = question.status === OpenQuestionStatus.Drafting;

  const metaInfo: [ReactElement, string][] = [
    [<HourglassOutlined key="h" />, getWaitTime(question)],
  ];
  if (!isDrafting) {
    metaInfo.push([<QuestionOutlined key="q" />, question.questionType]);
  }
  return (
    <Container
      selected={selected}
      data-cy={`queue-list-item-${question.id}`}
      onClick={onClick}
    >
      {showCheckbox && <StyledCheckbox checked={selected} />}
      <BodyContainer>
        <AvatarContainer>
          <Badge
            // 0 is not displayed, hide if no index
            count={index ? `#${index}` : 0}
            style={{ backgroundColor: "#3684c6" }}
            offset={[-40, 0]}
          >
            <KOHAvatar
              size={40}
              name={question.creator.name}
              photoURL={question.creator.photoURL}
            />
          </Badge>
        </AvatarContainer>
        <QuestionInfoContainer>
          <Name>{question.creator.name}</Name>
          <QuestionText>
            {isDrafting ? (
              <i>Still Drafting...</i>
            ) : (
              truncate(question.text, 80)
            )}
          </QuestionText>
          <QuestionMetaRow info={metaInfo} />
        </QuestionInfoContainer>
      </BodyContainer>
    </Container>
  );
}
Example #3
Source File: palette.tsx    From jmix-frontend with Apache License 2.0 4 votes vote down vote up
palette = () => (
  <Palette>
    <Category name="Text">
      <Component name="Formatted Message">
        <Variant>
          <FormattedMessage />
        </Variant>
      </Component>
      <Component name="Heading">
        <Variant name="h1">
          <Typography.Title></Typography.Title>
        </Variant>
        <Variant name="h2">
          <Typography.Title level={2}></Typography.Title>
        </Variant>
        <Variant name="h3">
          <Typography.Title level={3}></Typography.Title>
        </Variant>
        <Variant name="h4">
          <Typography.Title level={4}></Typography.Title>
        </Variant>
        <Variant name="h5">
          <Typography.Title level={5}></Typography.Title>
        </Variant>
      </Component>
      <Component name="Text">
        <Variant>
          <Typography.Text></Typography.Text>
        </Variant>
        <Variant name="Secondary">
          <Typography.Text type="secondary"></Typography.Text>
        </Variant>
        <Variant name="Success">
          <Typography.Text type="success"></Typography.Text>
        </Variant>
        <Variant name="Warning">
          <Typography.Text type="warning"></Typography.Text>
        </Variant>
        <Variant name="Danger">
          <Typography.Text type="danger"></Typography.Text>
        </Variant>
        <Variant name="Disabled">
          <Typography.Text disabled></Typography.Text>
        </Variant>
      </Component>
    </Category>
    <Category name="Layout">
      <Component name="Divider">
        <Variant>
          <Divider />
        </Variant>
      </Component>

      <Component name="Grid">
        <Variant name="Simple Row">
          <Row></Row>
        </Variant>
        <Variant name="Two columns">
          <Row>
            <Col span={12}></Col>
            <Col span={12}></Col>
          </Row>
        </Variant>
        <Variant name="Three columns">
          <Row>
            <Col span={8}></Col>
            <Col span={8}></Col>
            <Col span={8}></Col>
          </Row>
        </Variant>
      </Component>

      <Component name="Space">
        <Variant>
          <Space />
        </Variant>
        <Variant name="Small">
          <Space size={"small"} />
        </Variant>
        <Variant name="Large">
          <Space size={"large"} />
        </Variant>
      </Component>
    </Category>
    <Category name="Controls">
      <Component name="Autocomplete">
        <Variant>
          <AutoComplete placeholder="input here" />
        </Variant>
      </Component>

      <Component name="Button">
        <Variant>
          <Button></Button>
        </Variant>
        <Variant name="Primary">
          <Button type="primary"></Button>
        </Variant>
        <Variant name="Link">
          <Button type="link"></Button>
        </Variant>
        <Variant name="Dropdown">
          <Dropdown
            trigger={["click"]}
            overlay={
              <Menu>
                <Menu.Item></Menu.Item>
                <Menu.Item></Menu.Item>
                <Menu.Item></Menu.Item>
              </Menu>
            }
          >
            <Button></Button>
          </Dropdown>
        </Variant>
      </Component>

      <Component name="Checkbox">
        <Variant>
          <Checkbox />
        </Variant>
      </Component>

      <Component name="Switch">
        <Variant>
          <Switch />
        </Variant>
      </Component>

      <Component name="Radio Group">
        <Variant>
          <Radio.Group>
            <Radio value={1}>A</Radio>
            <Radio value={2}>B</Radio>
            <Radio value={3}>C</Radio>
            <Radio value={4}>D</Radio>
          </Radio.Group>
        </Variant>
        <Variant name="Button">
          <Radio.Group>
            <Radio.Button value={1}>A</Radio.Button>
            <Radio.Button value={2}>B</Radio.Button>
            <Radio.Button value={3}>C</Radio.Button>
            <Radio.Button value={4}>D</Radio.Button>
          </Radio.Group>
        </Variant>
      </Component>

      <Component name="DatePicker">
        <Variant>
          <DatePicker />
        </Variant>
        <Variant name="Range">
          <DatePicker.RangePicker />
        </Variant>
      </Component>

      <Component name="TimePicker">
        <Variant>
          <TimePicker />
        </Variant>
        <Variant name="Range">
          <TimePicker.RangePicker />
        </Variant>
      </Component>

      <Component name="Input">
        <Variant>
          <Input />
        </Variant>
        <Variant name="Number">
          <InputNumber />
        </Variant>
      </Component>

      <Component name="Select">
        <Variant>
          <Select defaultValue="1">
            <Select.Option value="1">1</Select.Option>
            <Select.Option value="2">2</Select.Option>
          </Select>
        </Variant>
        <Variant name="Multiple">
          <Select defaultValue={["1"]} mode="multiple" allowClear>
            <Select.Option value="1">1</Select.Option>
            <Select.Option value="2">2</Select.Option>
          </Select>
        </Variant>
      </Component>

      <Component name="Link">
        <Variant>
          <Typography.Link href="" target="_blank"></Typography.Link>
        </Variant>
      </Component>

      <Component name="Slider">
        <Variant>
          <Slider defaultValue={30} />
        </Variant>
        <Variant name="Range">
          <Slider range defaultValue={[20, 50]} />
        </Variant>
      </Component>
    </Category>
    <Category name="Data Display">
      <Component name="Field">
        <Variant>
          <Field
            entityName={ENTITY_NAME}
            disabled={readOnlyMode}
            propertyName=""
            formItemProps={{
              style: { marginBottom: "12px" }
            }}
          />
        </Variant>
      </Component>
      <Component name="Card">
        <Variant>
          <Card />
        </Variant>
        <Variant name="With Title">
          <Card>
            <Card title="Card title">
              <p>Card content</p>
            </Card>
          </Card>
        </Variant>
        <Variant name="My custom card">
          <Card>
            <Card title="Card title">
              <p>Card content</p>
              <Avatar />
            </Card>
          </Card>
        </Variant>
      </Component>
      <Component name="Tabs">
        <Variant>
          <Tabs defaultActiveKey="1">
            <Tabs.TabPane tab="Tab 1" key="1">
              Content of Tab Pane 1
            </Tabs.TabPane>
            <Tabs.TabPane tab="Tab 2" key="2">
              Content of Tab Pane 2
            </Tabs.TabPane>
            <Tabs.TabPane tab="Tab 3" key="3">
              Content of Tab Pane 3
            </Tabs.TabPane>
          </Tabs>
        </Variant>
        <Variant name="Tab Pane">
          <Tabs.TabPane></Tabs.TabPane>
        </Variant>
      </Component>
      <Component name="Collapse">
        <Variant>
          <Collapse defaultActiveKey="1">
            <Collapse.Panel
              header="This is panel header 1"
              key="1"
            ></Collapse.Panel>
            <Collapse.Panel
              header="This is panel header 2"
              key="2"
            ></Collapse.Panel>
            <Collapse.Panel
              header="This is panel header 3"
              key="3"
            ></Collapse.Panel>
          </Collapse>
        </Variant>
      </Component>
      <Component name="Image">
        <Variant>
          <Image width={200} src="" />
        </Variant>
      </Component>
      <Component name="Avatar">
        <Variant>
          <Avatar icon={<UserOutlined />} />
        </Variant>
        <Variant name="Image">
          <Avatar src="https://joeschmoe.io/api/v1/random" />
        </Variant>
      </Component>
      <Component name="Badge">
        <Variant>
          <Badge count={1}></Badge>
        </Variant>
      </Component>
      <Component name="Statistic">
        <Variant>
          <Statistic title="Title" value={112893} />
        </Variant>
      </Component>
      <Component name="Alert">
        <Variant name="Success">
          <Alert message="Text" type="success" />
        </Variant>
        <Variant name="Info">
          <Alert message="Text" type="info" />
        </Variant>
        <Variant name="Warning">
          <Alert message="Text" type="warning" />
        </Variant>
        <Variant name="Error">
          <Alert message="Text" type="error" />
        </Variant>
      </Component>
      <Component name="List">
        <Variant>
          <List
            bordered
            dataSource={[]}
            renderItem={item => <List.Item></List.Item>}
          />
        </Variant>
      </Component>
    </Category>
    <Category name="Icons">
      <Component name="Arrow">
        <Variant name="Up">
          <ArrowUpOutlined />
        </Variant>
        <Variant name="Down">
          <ArrowDownOutlined />
        </Variant>
        <Variant name="Left">
          <ArrowLeftOutlined />
        </Variant>
        <Variant name="Right">
          <ArrowRightOutlined />
        </Variant>
      </Component>
      <Component name="Question">
        <Variant>
          <QuestionOutlined />
        </Variant>
        <Variant name="Circle">
          <QuestionCircleOutlined />
        </Variant>
      </Component>
      <Component name="Plus">
        <Variant>
          <PlusOutlined />
        </Variant>
        <Variant name="Circle">
          <PlusCircleOutlined />
        </Variant>
      </Component>
      <Component name="Info">
        <Variant>
          <InfoOutlined />
        </Variant>
        <Variant name="Circle">
          <InfoCircleOutlined />
        </Variant>
      </Component>
      <Component name="Exclamation">
        <Variant>
          <ExclamationOutlined />
        </Variant>
        <Variant name="Circle">
          <ExclamationCircleOutlined />
        </Variant>
      </Component>
      <Component name="Close">
        <Variant>
          <CloseOutlined />
        </Variant>
        <Variant name="Circle">
          <CloseCircleOutlined />
        </Variant>
      </Component>
      <Component name="Check">
        <Variant>
          <CheckOutlined />
        </Variant>
        <Variant name="Circle">
          <CheckCircleOutlined />
        </Variant>
      </Component>
      <Component name="Edit">
        <Variant>
          <EditOutlined />
        </Variant>
      </Component>
      <Component name="Copy">
        <Variant>
          <CopyOutlined />
        </Variant>
      </Component>
      <Component name="Delete">
        <Variant>
          <DeleteOutlined />
        </Variant>
      </Component>
      <Component name="Bars">
        <Variant>
          <BarsOutlined />
        </Variant>
      </Component>
      <Component name="Bell">
        <Variant>
          <BellOutlined />
        </Variant>
      </Component>
      <Component name="Clear">
        <Variant>
          <ClearOutlined />
        </Variant>
      </Component>
      <Component name="Download">
        <Variant>
          <DownloadOutlined />
        </Variant>
      </Component>
      <Component name="Upload">
        <Variant>
          <UploadOutlined />
        </Variant>
      </Component>
      <Component name="Sync">
        <Variant>
          <SyncOutlined />
        </Variant>
      </Component>
      <Component name="Save">
        <Variant>
          <SaveOutlined />
        </Variant>
      </Component>
      <Component name="Search">
        <Variant>
          <SearchOutlined />
        </Variant>
      </Component>
      <Component name="Settings">
        <Variant>
          <SettingOutlined />
        </Variant>
      </Component>
      <Component name="Paperclip">
        <Variant>
          <PaperClipOutlined />
        </Variant>
      </Component>
      <Component name="Phone">
        <Variant>
          <PhoneOutlined />
        </Variant>
      </Component>
      <Component name="Mail">
        <Variant>
          <MailOutlined />
        </Variant>
      </Component>
      <Component name="Home">
        <Variant>
          <HomeOutlined />
        </Variant>
      </Component>
      <Component name="Contacts">
        <Variant>
          <ContactsOutlined />
        </Variant>
      </Component>
      <Component name="User">
        <Variant>
          <UserOutlined />
        </Variant>
        <Variant name="Add">
          <UserAddOutlined />
        </Variant>
        <Variant name="Remove">
          <UserDeleteOutlined />
        </Variant>
      </Component>
      <Component name="Team">
        <Variant>
          <TeamOutlined />
        </Variant>
      </Component>
    </Category>
    <Category name="Screens">
      <Component name="ExampleCustomScreen">
        <Variant>
          <ExampleCustomScreen />
        </Variant>
      </Component>
      <Component name="CustomEntityFilterTest">
        <Variant>
          <CustomEntityFilterTest />
        </Variant>
      </Component>
      <Component name="CustomFormControls">
        <Variant>
          <CustomFormControls />
        </Variant>
      </Component>
      <Component name="CustomDataDisplayComponents">
        <Variant>
          <CustomDataDisplayComponents />
        </Variant>
      </Component>
      <Component name="CustomAppLayouts">
        <Variant>
          <CustomAppLayouts />
        </Variant>
      </Component>
      <Component name="CustomControls">
        <Variant>
          <CustomControls />
        </Variant>
      </Component>
      <Component name="ErrorBoundaryTests">
        <Variant>
          <ErrorBoundaryTests />
        </Variant>
      </Component>
      <Component name="TestBlankScreen">
        <Variant>
          <TestBlankScreen />
        </Variant>
      </Component>
      <Component name="CarEditor">
        <Variant>
          <CarEditor />
        </Variant>
      </Component>
      <Component name="CarBrowserCards">
        <Variant>
          <CarBrowserCards />
        </Variant>
      </Component>
      <Component name="CarBrowserList">
        <Variant>
          <CarBrowserList />
        </Variant>
      </Component>
      <Component name="CarBrowserTable">
        <Variant>
          <CarBrowserTable />
        </Variant>
      </Component>
      <Component name="CarCardsGrid">
        <Variant>
          <CarCardsGrid />
        </Variant>
      </Component>
      <Component name="FavoriteCars">
        <Variant>
          <FavoriteCars />
        </Variant>
      </Component>
      <Component name="CarCardsWithDetails">
        <Variant>
          <CarCardsWithDetails />
        </Variant>
      </Component>
      <Component name="CarTableWithFilters">
        <Variant>
          <CarTableWithFilters />
        </Variant>
      </Component>
      <Component name="CarMasterDetail">
        <Variant>
          <CarMasterDetail />
        </Variant>
      </Component>
      <Component name="FormWizardCompositionO2O">
        <Variant>
          <FormWizardCompositionO2O />
        </Variant>
      </Component>
      <Component name="FormWizardEditor">
        <Variant>
          <FormWizardEditor />
        </Variant>
      </Component>
      <Component name="FormWizardBrowserTable">
        <Variant>
          <FormWizardBrowserTable />
        </Variant>
      </Component>
      <Component name="CarMultiSelectionTable">
        <Variant>
          <CarMultiSelectionTable />
        </Variant>
      </Component>
      <Component name="DatatypesTestEditor">
        <Variant>
          <DatatypesTestEditor />
        </Variant>
      </Component>
      <Component name="DatatypesTestBrowserCards">
        <Variant>
          <DatatypesTestBrowserCards />
        </Variant>
      </Component>
      <Component name="DatatypesTestBrowserList">
        <Variant>
          <DatatypesTestBrowserList />
        </Variant>
      </Component>
      <Component name="DatatypesTestBrowserTable">
        <Variant>
          <DatatypesTestBrowserTable />
        </Variant>
      </Component>
      <Component name="DatatypesTestCards">
        <Variant>
          <DatatypesTestCards />
        </Variant>
      </Component>
      <Component name="AssociationO2OEditor">
        <Variant>
          <AssociationO2OEditor />
        </Variant>
      </Component>
      <Component name="AssociationO2OBrowserTable">
        <Variant>
          <AssociationO2OBrowserTable />
        </Variant>
      </Component>
      <Component name="AssociationO2MEditor">
        <Variant>
          <AssociationO2MEditor />
        </Variant>
      </Component>
      <Component name="AssociationO2MBrowserTable">
        <Variant>
          <AssociationO2MBrowserTable />
        </Variant>
      </Component>
      <Component name="AssociationM2OEditor">
        <Variant>
          <AssociationM2OEditor />
        </Variant>
      </Component>
      <Component name="AssociationM2OBrowserTable">
        <Variant>
          <AssociationM2OBrowserTable />
        </Variant>
      </Component>
      <Component name="AssociationM2MEditor">
        <Variant>
          <AssociationM2MEditor />
        </Variant>
      </Component>
      <Component name="AssociationM2MBrowserTable">
        <Variant>
          <AssociationM2MBrowserTable />
        </Variant>
      </Component>
      <Component name="CompositionO2OEditor">
        <Variant>
          <CompositionO2OEditor />
        </Variant>
      </Component>
      <Component name="CompositionO2OBrowserTable">
        <Variant>
          <CompositionO2OBrowserTable />
        </Variant>
      </Component>
      <Component name="CompositionO2MEditor">
        <Variant>
          <CompositionO2MEditor />
        </Variant>
      </Component>
      <Component name="CompositionO2MBrowserTable">
        <Variant>
          <CompositionO2MBrowserTable />
        </Variant>
      </Component>
      <Component name="DeeplyNestedTestEntityEditor">
        <Variant>
          <DeeplyNestedTestEntityEditor />
        </Variant>
      </Component>
      <Component name="DeeplyNestedO2MTestEntityTable">
        <Variant>
          <DeeplyNestedO2MTestEntityTable />
        </Variant>
      </Component>
      <Component name="DeeplyNestedO2MTestEntityEditor">
        <Variant>
          <DeeplyNestedO2MTestEntityEditor />
        </Variant>
      </Component>
      <Component name="IntIdEditor">
        <Variant>
          <IntIdEditor />
        </Variant>
      </Component>
      <Component name="IntIdBrowserTable">
        <Variant>
          <IntIdBrowserTable />
        </Variant>
      </Component>
      <Component name="IntIdBrowserCards">
        <Variant>
          <IntIdBrowserCards />
        </Variant>
      </Component>
      <Component name="IntIdBrowserList">
        <Variant>
          <IntIdBrowserList />
        </Variant>
      </Component>
      <Component name="IntIdentityIdCards">
        <Variant>
          <IntIdentityIdCards />
        </Variant>
      </Component>
      <Component name="IntIdentityIdEditor">
        <Variant>
          <IntIdentityIdEditor />
        </Variant>
      </Component>
      <Component name="IntIdentityIdBrowserTable">
        <Variant>
          <IntIdentityIdBrowserTable />
        </Variant>
      </Component>
      <Component name="IntIdentityIdBrowserCards">
        <Variant>
          <IntIdentityIdBrowserCards />
        </Variant>
      </Component>
      <Component name="IntIdentityIdBrowserList">
        <Variant>
          <IntIdentityIdBrowserList />
        </Variant>
      </Component>
      <Component name="StringIdCards">
        <Variant>
          <StringIdCards />
        </Variant>
      </Component>
      <Component name="StringIdMgtCardsEdit">
        <Variant>
          <StringIdMgtCardsEdit />
        </Variant>
      </Component>
      <Component name="StringIdBrowserCards">
        <Variant>
          <StringIdBrowserCards />
        </Variant>
      </Component>
      <Component name="StringIdBrowserList">
        <Variant>
          <StringIdBrowserList />
        </Variant>
      </Component>
      <Component name="StringIdBrowserTable">
        <Variant>
          <StringIdBrowserTable />
        </Variant>
      </Component>
      <Component name="WeirdStringIdEditor">
        <Variant>
          <WeirdStringIdEditor />
        </Variant>
      </Component>
      <Component name="WeirdStringIdBrowserCards">
        <Variant>
          <WeirdStringIdBrowserCards />
        </Variant>
      </Component>
      <Component name="WeirdStringIdBrowserList">
        <Variant>
          <WeirdStringIdBrowserList />
        </Variant>
      </Component>
      <Component name="WeirdStringIdBrowserTable">
        <Variant>
          <WeirdStringIdBrowserTable />
        </Variant>
      </Component>
      <Component name="BoringStringIdEditor">
        <Variant>
          <BoringStringIdEditor />
        </Variant>
      </Component>
      <Component name="BoringStringIdBrowserTable">
        <Variant>
          <BoringStringIdBrowserTable />
        </Variant>
      </Component>
      <Component name="TrickyIdEditor">
        <Variant>
          <TrickyIdEditor />
        </Variant>
      </Component>
      <Component name="TrickyIdBrowserTable">
        <Variant>
          <TrickyIdBrowserTable />
        </Variant>
      </Component>
    </Category>
  </Palette>
)
Example #4
Source File: palette.tsx    From jmix-frontend with Apache License 2.0 4 votes vote down vote up
palette = () =>
  <Palette>
    <Category name="Text">
      <Component name="Formatted Message">
        <Variant>
          <FormattedMessage />
        </Variant>
      </Component>
      <Component name="Heading">
        <Variant name='h1'>
          <Typography.Title></Typography.Title>
        </Variant>
        <Variant name='h2'>
          <Typography.Title level = {2}></Typography.Title>
        </Variant>
        <Variant name='h3'>
          <Typography.Title level = {3}></Typography.Title>
        </Variant>
        <Variant name='h4'>
          <Typography.Title level = {4}></Typography.Title>
        </Variant>
        <Variant name='h5'>
          <Typography.Title level = {5}></Typography.Title>
        </Variant>
      </Component>
      <Component name='Text'>
        <Variant>
          <Typography.Text></Typography.Text>
        </Variant>
        <Variant name = 'Secondary'>
          <Typography.Text type="secondary"></Typography.Text>
        </Variant>
        <Variant name = 'Success'>
          <Typography.Text type="success"></Typography.Text>
        </Variant>
        <Variant name = 'Warning'>
          <Typography.Text type="warning"></Typography.Text>
        </Variant>
        <Variant name = 'Danger'>
          <Typography.Text type="danger"></Typography.Text>
        </Variant>
        <Variant name = 'Disabled'>
          <Typography.Text disabled></Typography.Text>
        </Variant>
      </Component>
    </Category>
    <Category name="Layout">
      <Component name="Divider">
        <Variant>
          <Divider />
        </Variant>
      </Component>

      <Component name="Grid">
        <Variant name="Simple Row">
          <Row></Row>
        </Variant>
        <Variant name="Two columns">
          <Row>
            <Col span={12}></Col>
            <Col span={12}></Col>
          </Row>
        </Variant>
        <Variant name="Three columns">
          <Row>
            <Col span={8}></Col>
            <Col span={8}></Col>
            <Col span={8}></Col>
          </Row>
        </Variant>
      </Component>

      <Component name="Space">
        <Variant>
          <Space />
        </Variant>
        <Variant name="Small">
          <Space size={"small"} />
        </Variant>
        <Variant name="Large">
          <Space size={"large"} />
        </Variant>
      </Component>
    </Category>
    <Category name="Controls">
      <Component name="Autocomplete">
        <Variant>
          <AutoComplete placeholder="input here" />
        </Variant>
      </Component>

      <Component name="Button">
        <Variant>
          <Button></Button>
        </Variant>
        <Variant name="Primary">
          <Button type="primary" ></Button>
        </Variant>
        <Variant name="Link">
          <Button type="link" ></Button>
        </Variant>
        <Variant name="Dropdown">
          <Dropdown
            trigger={['click']}
            overlay={<Menu>
              <Menu.Item>
              </Menu.Item>
              <Menu.Item>
              </Menu.Item>
              <Menu.Item>
              </Menu.Item>
            </Menu>}
          >
            <Button></Button>
          </Dropdown>
        </Variant>
      </Component>

      <Component name="Checkbox">
        <Variant>
          <Checkbox />
        </Variant>
      </Component>

      <Component name='Switch'>
        <Variant>
          <Switch />
        </Variant>
      </Component>

      <Component name='Radio Group'>
        <Variant>
          <Radio.Group>
            <Radio value={1}>A</Radio>
            <Radio value={2}>B</Radio>
            <Radio value={3}>C</Radio>
            <Radio value={4}>D</Radio>
          </Radio.Group>
        </Variant>
        <Variant name = 'Button'>
          <Radio.Group>
            <Radio.Button value={1}>A</Radio.Button>
            <Radio.Button value={2}>B</Radio.Button>
            <Radio.Button value={3}>C</Radio.Button>
            <Radio.Button value={4}>D</Radio.Button>
          </Radio.Group>
        </Variant>
      </Component>

      <Component name="DatePicker">
        <Variant>
          <DatePicker />
        </Variant>
        <Variant name="Range">
          <DatePicker.RangePicker />
        </Variant>
      </Component>

      <Component name="TimePicker">
        <Variant>
          <TimePicker />
        </Variant>
        <Variant name="Range">
          <TimePicker.RangePicker />
        </Variant>
      </Component>

      <Component name="Input">
        <Variant>
          <Input />
        </Variant>
        <Variant name='Number'>
          <InputNumber />
        </Variant>
      </Component>

      <Component name='Select'>
        <Variant>
          <Select defaultValue="1">
            <Select.Option value="1">1</Select.Option>
            <Select.Option value="2">2</Select.Option>
          </Select>
        </Variant>
        <Variant name='Multiple'>
          <Select
            defaultValue={["1"]}
            mode="multiple"
            allowClear
          >
            <Select.Option value="1">1</Select.Option>
            <Select.Option value="2">2</Select.Option>
          </Select>
        </Variant>
      </Component>

      <Component name="Link">
        <Variant>
          <Typography.Link href="" target="_blank">
          </Typography.Link>
        </Variant>
      </Component>

      <Component name='Slider'>
        <Variant>
          <Slider defaultValue={30} />
        </Variant>
        <Variant name = 'Range'>
          <Slider range defaultValue={[20, 50]}/>
        </Variant>
      </Component>
    </Category>
    <Category name="Data Display">
    <Component name="Field">
        <Variant>
          <Field
            entityName={ENTITY_NAME}
            disabled={readOnlyMode}
            propertyName=''
            formItemProps={{
              style: { marginBottom: "12px" }
            }}
          />
        </Variant>
      </Component>
      <Component name="Card">
        <Variant>
          <Card />
        </Variant>
        <Variant name="With Title">
          <Card>
            <Card title="Card title">
              <p>Card content</p>
            </Card>
          </Card>
        </Variant>
        <Variant name="My custom card">
          <Card>
            <Card title="Card title">
              <p>Card content</p>
              <Avatar />
            </Card>
          </Card>
        </Variant>
      </Component>
      <Component name="Tabs">
        <Variant>
          <Tabs defaultActiveKey="1">
            <Tabs.TabPane tab="Tab 1" key="1">
              Content of Tab Pane 1
            </Tabs.TabPane>
            <Tabs.TabPane tab="Tab 2" key="2">
              Content of Tab Pane 2
            </Tabs.TabPane>
            <Tabs.TabPane tab="Tab 3" key="3">
              Content of Tab Pane 3
            </Tabs.TabPane>
          </Tabs>
        </Variant>
        <Variant name = "Tab Pane">
          <Tabs.TabPane>
          </Tabs.TabPane>
        </Variant>
      </Component>
      <Component name="Collapse">
        <Variant>
          <Collapse defaultActiveKey='1'>
            <Collapse.Panel header="This is panel header 1" key="1">
            </Collapse.Panel>
            <Collapse.Panel header="This is panel header 2" key="2">
            </Collapse.Panel>
            <Collapse.Panel header="This is panel header 3" key="3">
            </Collapse.Panel>
          </Collapse>
        </Variant>
      </Component>
      <Component name="Image">
        <Variant>
          <Image
            width={200}
            src=""
          />
        </Variant>
      </Component>
      <Component name="Avatar">
        <Variant>
          <Avatar icon={<UserOutlined />} />
        </Variant>
        <Variant name="Image">
          <Avatar src="https://joeschmoe.io/api/v1/random" />
        </Variant>
      </Component>
      <Component name="Badge">
        <Variant>
          <Badge count={1}>
          </Badge>
        </Variant>
      </Component>
      <Component name="Statistic">
        <Variant>
          <Statistic title="Title" value={112893} />
        </Variant>
      </Component>
      <Component name="Alert">
        <Variant name="Success">
          <Alert message="Text" type="success" />
        </Variant>
        <Variant name="Info">
          <Alert message="Text" type="info" />
        </Variant>
        <Variant name="Warning">
          <Alert message="Text" type="warning" />
        </Variant>
        <Variant name="Error">
          <Alert message="Text" type="error" />
        </Variant>
      </Component>
      <Component name='List'>
        <Variant>
          <List
            bordered
            dataSource={[]}
            renderItem={item => (
              <List.Item>
              </List.Item>
            )}
          />
        </Variant>
      </Component>
    </Category>
    <Category name="Icons">
      <Component name="Arrow">
        <Variant name = 'Up'>
          <ArrowUpOutlined />
        </Variant>
        <Variant name = 'Down'>
          <ArrowDownOutlined />
        </Variant>
        <Variant name = 'Left'>
          <ArrowLeftOutlined />
        </Variant>
        <Variant name = 'Right'>
          <ArrowRightOutlined />
        </Variant>
      </Component>
      <Component name = 'Question'>
        <Variant>
          <QuestionOutlined />
        </Variant>
        <Variant name = 'Circle'>
          <QuestionCircleOutlined />
        </Variant>
      </Component>
      <Component name = 'Plus'>
        <Variant>
          <PlusOutlined />
        </Variant>
        <Variant name = 'Circle'>
          <PlusCircleOutlined />
        </Variant>
      </Component>
      <Component name = 'Info'>
        <Variant>
          <InfoOutlined />
        </Variant>
        <Variant name = 'Circle'>
          <InfoCircleOutlined />
        </Variant>
      </Component>
      <Component name = 'Exclamation'>
        <Variant>
          <ExclamationOutlined />
        </Variant>
        <Variant name = 'Circle'>
          <ExclamationCircleOutlined />
        </Variant>
      </Component>
      <Component name = 'Close'>
        <Variant>
          <CloseOutlined />
        </Variant>
        <Variant name = 'Circle'>
          <CloseCircleOutlined />
        </Variant>
      </Component>
      <Component name = 'Check'>
        <Variant>
          <CheckOutlined />
        </Variant>
        <Variant name = 'Circle'>
          <CheckCircleOutlined />
        </Variant>
      </Component>
      <Component name = 'Edit'>
        <Variant>
          <EditOutlined />
        </Variant>
      </Component>
      <Component name = 'Copy'>
        <Variant>
          <CopyOutlined />
        </Variant>
      </Component>
      <Component name = 'Delete'>
        <Variant>
          <DeleteOutlined />
        </Variant>
      </Component>
      <Component name = 'Bars'>
        <Variant>
          <BarsOutlined />
        </Variant>
      </Component>
      <Component name = 'Bell'>
        <Variant>
          <BellOutlined />
        </Variant>
      </Component>
      <Component name = 'Clear'>
        <Variant>
          <ClearOutlined />
        </Variant>
      </Component>
      <Component name = 'Download'>
        <Variant>
          <DownloadOutlined />
        </Variant>
      </Component>
      <Component name = 'Upload'>
        <Variant>
          <UploadOutlined />
        </Variant>
      </Component>
      <Component name = 'Sync'>
        <Variant>
          <SyncOutlined />
        </Variant>
      </Component>
      <Component name = 'Save'>
        <Variant>
          <SaveOutlined />
        </Variant>
      </Component>
      <Component name = 'Search'>
        <Variant>
          <SearchOutlined />
        </Variant>
      </Component>
      <Component name = 'Settings'>
        <Variant>
          <SettingOutlined />
        </Variant>
      </Component>
      <Component name = 'Paperclip'>
        <Variant>
          <PaperClipOutlined />
        </Variant>
      </Component>
      <Component name = 'Phone'>
        <Variant>
          <PhoneOutlined />
        </Variant>
      </Component>
      <Component name = 'Mail'>
        <Variant>
          <MailOutlined />
        </Variant>
      </Component>
      <Component name = 'Home'>
        <Variant>
          <HomeOutlined />
        </Variant>
      </Component>
      <Component name = 'Contacts'>
        <Variant>
          <ContactsOutlined />
        </Variant>
      </Component>
      <Component name = 'User'>
        <Variant>
          <UserOutlined />
        </Variant>
        <Variant name = 'Add'>
          <UserAddOutlined />
        </Variant>
        <Variant name = 'Remove'>
          <UserDeleteOutlined />
        </Variant>
      </Component>
      <Component name = 'Team'>
        <Variant>
          <TeamOutlined />
        </Variant>
      </Component>
    </Category>
  </Palette>
Example #5
Source File: ToolbarButton.tsx    From posthog-foss with MIT License 4 votes vote down vote up
export function ToolbarButton(): JSX.Element {
    const {
        extensionPercentage,
        heatmapInfoVisible,
        toolbarListVerticalPadding,
        helpButtonOnTop,
        side,
        closeDistance,
        closeRotation,
        inspectExtensionPercentage,
        heatmapExtensionPercentage,
        actionsExtensionPercentage,
        actionsInfoVisible,
        featureFlagsExtensionPercentage,
        flagsVisible,
    } = useValues(toolbarButtonLogic)
    const {
        setExtensionPercentage,
        showHeatmapInfo,
        hideHeatmapInfo,
        showActionsInfo,
        hideActionsInfo,
        showFlags,
        hideFlags,
    } = useActions(toolbarButtonLogic)
    const { buttonActionsVisible, showActionsTooltip } = useValues(actionsTabLogic)
    const { hideButtonActions, showButtonActions } = useActions(actionsTabLogic)
    const { actionCount, allActionsLoading } = useValues(actionsLogic)

    const { enableInspect, disableInspect } = useActions(elementsLogic)
    const { inspectEnabled, selectedElement } = useValues(elementsLogic)

    const { enableHeatmap, disableHeatmap } = useActions(heatmapLogic)
    const { heatmapEnabled, heatmapLoading, elementCount, showHeatmapTooltip } = useValues(heatmapLogic)

    const { isAuthenticated } = useValues(toolbarLogic)
    const { authenticate, logout } = useActions(toolbarLogic)

    const globalMouseMove = useRef((e: MouseEvent) => {
        e
    })

    useEffect(() => {
        globalMouseMove.current = function (e: MouseEvent): void {
            const buttonDiv = getShadowRoot()?.getElementById('button-toolbar')
            if (buttonDiv) {
                const rect = buttonDiv.getBoundingClientRect()
                const x = rect.left + rect.width / 2
                const y = rect.top + rect.height / 2
                const distance = Math.sqrt((e.clientX - x) * (e.clientX - x) + (e.clientY - y) * (e.clientY - y))

                const maxDistance = isAuthenticated ? 300 : 100

                if (distance >= maxDistance && toolbarButtonLogic.values.extensionPercentage !== 0) {
                    setExtensionPercentage(0)
                }
            }
        }
        window.addEventListener('mousemove', globalMouseMove.current)
        return () => window.removeEventListener('mousemove', globalMouseMove.current)
    }, [isAuthenticated])

    // using useLongPress for short presses (clicks) since it detects if the element was dragged (no click) or not (click)
    const clickEvents = useLongPress(
        (clicked) => {
            if (clicked) {
                if (isAuthenticated) {
                    setExtensionPercentage(extensionPercentage === 1 ? 0 : 1)
                } else {
                    authenticate()
                }
            }
        },
        {
            ms: undefined,
            clickMs: 1,
            touch: true,
            click: true,
        }
    )

    const borderRadius = 14
    const buttonWidth = 42
    let n = 0

    return (
        <Circle
            rootNode
            width={62}
            className="floating-toolbar-button"
            content={<HogLogo style={{ width: 45, cursor: 'pointer' }} />}
            {...clickEvents}
            onMouseOver={isAuthenticated ? undefined : () => setExtensionPercentage(1)}
            style={{ borderRadius: 10, height: 46, marginTop: -23 }}
            zIndex={3}
        >
            <Circle
                width={26}
                extensionPercentage={extensionPercentage}
                distance={closeDistance}
                rotation={closeRotation}
                content={<Close style={{ width: 14, height: 14 }} />}
                zIndex={extensionPercentage > 0.95 ? 5 : 2}
                onClick={logout}
                style={{
                    cursor: 'pointer',
                    background: '#393939',
                    borderRadius: 6,
                    color: 'white',
                    transform: `scale(${0.2 + 0.8 * extensionPercentage})`,
                }}
            />
            {isAuthenticated ? (
                <>
                    <Circle
                        width={32}
                        extensionPercentage={extensionPercentage}
                        distance={helpButtonOnTop ? 75 : 55}
                        rotation={helpButtonOnTop ? (side === 'left' ? -95 + 360 : -95) : 90}
                        content={<QuestionOutlined style={{ fontSize: 22 }} />}
                        label="Help"
                        zIndex={2}
                        onClick={() => window.open(HELP_URL, '_blank')?.focus()}
                        labelStyle={{ opacity: extensionPercentage > 0.8 ? (extensionPercentage - 0.8) / 0.2 : 0 }}
                        style={{
                            cursor: 'pointer',
                            background: '#777',
                            color: 'white',
                            borderRadius: 10,
                            transform: `scale(${0.2 + 0.8 * extensionPercentage})`,
                        }}
                    />
                    <Circle
                        width={buttonWidth}
                        x={side === 'left' ? 80 : -80}
                        y={toolbarListVerticalPadding + n++ * 60}
                        extensionPercentage={inspectExtensionPercentage}
                        rotationFixer={(r) => (side === 'right' && r < 0 ? 360 : 0)}
                        label="Inspect"
                        labelPosition={side === 'left' ? 'right' : 'left'}
                        labelStyle={{
                            opacity: inspectExtensionPercentage > 0.8 ? (inspectExtensionPercentage - 0.8) / 0.2 : 0,
                        }}
                        content={
                            <div style={{ position: 'relative' }}>
                                <Magnifier style={{ height: 34, paddingTop: 2 }} engaged={inspectEnabled} />
                                {inspectEnabled && selectedElement ? (
                                    <div
                                        style={{
                                            position: 'absolute',
                                            top: 8,
                                            left: 9,
                                            fontSize: 13,
                                            color: 'white',
                                        }}
                                    >
                                        <Close style={{ width: 10, height: 10 }} />
                                    </div>
                                ) : null}
                            </div>
                        }
                        zIndex={1}
                        onClick={inspectEnabled ? disableInspect : enableInspect}
                        style={{
                            cursor: 'pointer',
                            background: inspectEnabled ? '#8F98FF' : '#E7EAFD',
                            transition: 'transform 0.2s, color 0.2s, background: 0.2s',
                            transform: `scale(${0.2 + 0.8 * inspectExtensionPercentage})`,
                            borderRadius,
                        }}
                    />
                    <Circle
                        width={buttonWidth}
                        x={side === 'left' ? 80 : -80}
                        y={toolbarListVerticalPadding + n++ * 60}
                        extensionPercentage={heatmapExtensionPercentage}
                        rotationFixer={(r) => (side === 'right' && r < 0 ? 360 : 0)}
                        label={heatmapEnabled && !heatmapLoading ? null : 'Heatmap'}
                        labelPosition={side === 'left' ? 'right' : 'left'}
                        labelStyle={{
                            opacity:
                                heatmapEnabled && !heatmapLoading
                                    ? 0
                                    : heatmapExtensionPercentage > 0.8
                                    ? (heatmapExtensionPercentage - 0.8) / 0.2
                                    : 0,
                        }}
                        content={<Fire style={{ height: 26 }} engaged={heatmapEnabled} animated={heatmapLoading} />}
                        zIndex={2}
                        onClick={heatmapEnabled ? disableHeatmap : enableHeatmap}
                        style={{
                            cursor: 'pointer',
                            background: heatmapEnabled ? '#FF9870' : '#FEE3DA',
                            transform: `scale(${0.2 + 0.8 * heatmapExtensionPercentage})`,
                            borderRadius,
                        }}
                    >
                        {heatmapEnabled && !heatmapLoading ? (
                            <Circle
                                width={26}
                                x={
                                    (side === 'left' ? 50 : -50) *
                                    heatmapExtensionPercentage *
                                    heatmapExtensionPercentage
                                }
                                y={0}
                                content={
                                    <Tooltip
                                        visible={showHeatmapTooltip}
                                        title="Click for details"
                                        placement={side === 'left' ? 'right' : 'left'}
                                        getPopupContainer={getShadowRootPopupContainer}
                                    >
                                        <div style={{ whiteSpace: 'nowrap', textAlign: 'center' }}>{elementCount}</div>
                                    </Tooltip>
                                }
                                zIndex={4}
                                onClick={heatmapInfoVisible ? hideHeatmapInfo : showHeatmapInfo}
                                style={{
                                    cursor: 'pointer',
                                    background: heatmapInfoVisible ? 'hsla(17, 100%, 47%, 1)' : 'hsla(17, 84%, 95%, 1)',
                                    color: heatmapInfoVisible ? '#FFEB3B' : 'hsl(17, 64%, 32%)',
                                    width: 'auto',
                                    minWidth: 26,
                                    fontSize: '20px',
                                    lineHeight: '26px',
                                    padding: '0 4px',
                                    transform: `scale(${0.2 + 0.8 * heatmapExtensionPercentage})`,
                                    borderRadius: 7,
                                }}
                            />
                        ) : null}
                    </Circle>
                    <Circle
                        width={buttonWidth}
                        x={side === 'left' ? 80 : -80}
                        y={toolbarListVerticalPadding + n++ * 60}
                        extensionPercentage={actionsExtensionPercentage}
                        rotationFixer={(r) => (side === 'right' && r < 0 ? 360 : 0)}
                        label={buttonActionsVisible && (!allActionsLoading || actionCount > 0) ? null : 'Actions'}
                        labelPosition={side === 'left' ? 'right' : 'left'}
                        labelStyle={{
                            opacity: actionsExtensionPercentage > 0.8 ? (actionsExtensionPercentage - 0.8) / 0.2 : 0,
                        }}
                        content={
                            <AimOutlined
                                style={{ fontSize: '28px', color: buttonActionsVisible ? '#fef5e2' : '#f1aa04' }}
                            />
                        }
                        zIndex={1}
                        onClick={buttonActionsVisible ? hideButtonActions : showButtonActions}
                        style={{
                            cursor: 'pointer',
                            transform: `scale(${0.2 + 0.8 * actionsExtensionPercentage})`,
                            background: buttonActionsVisible ? '#f1aa04' : '#fef5e2',
                            borderRadius,
                        }}
                    >
                        {buttonActionsVisible && (!allActionsLoading || actionCount > 0) ? (
                            <Circle
                                width={26}
                                x={
                                    (side === 'left' ? 50 : -50) *
                                    actionsExtensionPercentage *
                                    actionsExtensionPercentage
                                }
                                y={0}
                                content={
                                    <Tooltip
                                        visible={showActionsTooltip}
                                        title="Click for details"
                                        placement={side === 'left' ? 'right' : 'left'}
                                        getPopupContainer={getShadowRootPopupContainer}
                                    >
                                        <div style={{ whiteSpace: 'nowrap', textAlign: 'center' }}>{actionCount}</div>
                                    </Tooltip>
                                }
                                zIndex={4}
                                onClick={actionsInfoVisible ? hideActionsInfo : showActionsInfo}
                                style={{
                                    cursor: 'pointer',
                                    background: actionsInfoVisible ? '#f1aa04' : '#fef5e2',
                                    color: actionsInfoVisible ? '#fef5e2' : '#f1aa04',
                                    width: 'auto',
                                    minWidth: 26,
                                    fontSize: '20px',
                                    lineHeight: '26px',
                                    padding: '0 4px',
                                    transform: `scale(${0.2 + 0.8 * actionsExtensionPercentage})`,
                                    borderRadius: 7,
                                }}
                            />
                        ) : null}
                    </Circle>
                    <Circle
                        width={buttonWidth}
                        x={side === 'left' ? 80 : -80}
                        y={toolbarListVerticalPadding + n++ * 60}
                        extensionPercentage={featureFlagsExtensionPercentage}
                        rotationFixer={(r) => (side === 'right' && r < 0 ? 360 : 0)}
                        label="Feature Flags"
                        labelPosition={side === 'left' ? 'right' : 'left'}
                        labelStyle={{
                            opacity:
                                featureFlagsExtensionPercentage > 0.8
                                    ? (featureFlagsExtensionPercentage - 0.8) / 0.2
                                    : 0,
                        }}
                        content={<Flag style={{ height: 29 }} engaged={flagsVisible} />}
                        zIndex={1}
                        onClick={flagsVisible ? hideFlags : showFlags}
                        style={{
                            cursor: 'pointer',
                            transform: `scale(${0.2 + 0.8 * featureFlagsExtensionPercentage})`,
                            background: flagsVisible ? '#94D674' : '#D6EBCC',
                            borderRadius,
                        }}
                    />
                </>
            ) : null}
        </Circle>
    )
}
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: FunctionDebuggerSidebar.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
export function FunctionDebuggerSidebar({
  functionName,
  functionModified,
  activeTab,
  tests,
  onActiveTabSwitch,
  onRunAllTests,
  onAddTest,
}: FunctionDebuggerSidebarProps): React.ReactElement {
  const [currentTab, setCurrentTab] = useState<string>(activeTab ?? "function");

  useEffect(() => {
    setCurrentTab(activeTab ?? "function");
  }, [activeTab]);

  const groups: SidebarGroup[] = useMemo(() => {
    const refinedTests = Array.isArray(tests) ? tests : [];
    return [
      {
        label: "Function",
        value: "function",
        items: [
          {
            label: functionName,
            value: "function",
            icon: <CodeOutlined />,
            modified: functionModified,
          },
        ],
      },
      {
        label: "Debug",
        value: "debug",
        items: [
          {
            label: "Debug",
            value: "debug",
            icon: <BugOutlined />,
          },
        ],
      },
      {
        label: `Tests (${refinedTests.length})`,
        value: "tests",
        items: refinedTests.map((test, index) => ({
          label: test.name ?? `Case ${index + 1}`,
          value: `test:${String(index)}`,
          modified: test.testModified,
          ...(test.testMatched
            ? {
                icon: <CheckOutlined />,
                className: styles.matched,
              }
            : test.testMatched === false
            ? {
                icon: <CloseOutlined />,
                className: styles.notMatched,
              }
            : {
                icon: <QuestionOutlined />,
              }),
        })),
      },
    ];
  }, [functionModified, functionName, tests]);

  const switchActiveTab = useCallback(
    (tab: string) => {
      if (currentTab !== tab) {
        setCurrentTab(tab);
        onActiveTabSwitch?.(tab);
      }
    },
    [currentTab, onActiveTabSwitch]
  );

  return (
    <div
      className={`${styles.sidebarContainer} ${sharedStyles.customScrollbarContainer}`}
      data-override-theme="dark"
    >
      <ul className={styles.sidebarGroups}>
        {groups.map((group) => (
          <li key={group.label}>
            <div className={styles.sidebarGroupLabel}>
              <span className={styles.groupText}>{group.label}</span>
              {group.value === "tests" && (
                <div className={styles.groupIconContainer}>
                  {group.items.length > 0 && (
                    <span
                      className={styles.groupIcon}
                      title="Run All Tests"
                      onClick={onRunAllTests}
                    >
                      <PlayCircleOutlined />
                    </span>
                  )}
                  <span
                    className={styles.groupIcon}
                    title="Add Test"
                    onClick={onAddTest}
                  >
                    <PlusCircleOutlined />
                  </span>
                </div>
              )}
            </div>
            <ul className={styles.sidebarItems}>
              {group.items.map((item) => (
                <li
                  key={item.label}
                  className={classNames({
                    [styles.active]: item.value === currentTab,
                  })}
                  onClick={() => switchActiveTab(item.value)}
                >
                  <span className={classNames(styles.icon, item.className)}>
                    {item.icon}
                  </span>
                  <span className={styles.text}>{item.label}</span>
                  {item.modified && <span className={styles.modified}></span>}
                </li>
              ))}
            </ul>
          </li>
        ))}
      </ul>
    </div>
  );
}
Example #8
Source File: FunctionDebuggerStatusbar.spec.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
describe("FunctionDebuggerStatusbar", () => {
  const getCoverage = (coveredStatements: number): any => ({
    statements: {
      covered: coveredStatements,
      total: 16,
    },
    branches: {
      covered: 3,
      total: 3,
    },
    functions: {
      covered: 1,
      total: 1,
    },
    lines: {
      covered: 2,
      total: 2,
      counts: new Map(),
    },
  });

  it("should work for nil coverage", () => {
    const wrapper = shallow(<FunctionDebuggerStatusbar />);
    expect(wrapper.find(".coverageIcon").childAt(0).type()).toBe(
      QuestionOutlined
    );
  });

  it("should work for empty coverage", () => {
    const wrapper = shallow(
      <FunctionDebuggerStatusbar
        coverage={
          {
            statements: {
              covered: 0,
              total: 0,
            },
            branches: {
              covered: 0,
              total: 0,
            },
            functions: {
              covered: 0,
              total: 0,
            },
            lines: {
              covered: 0,
              total: 0,
            },
          } as any
        }
      />
    );
    expect(wrapper.find(".coverageFull").childAt(1).text()).toBe(
      "Coverage: 100%"
    );
  });

  it("should work for 100% coverage", () => {
    const wrapper = shallow(
      <FunctionDebuggerStatusbar coverage={getCoverage(16)} />
    );
    expect(wrapper.find(".coverageFull").childAt(1).text()).toBe(
      "Coverage: 100%"
    );
  });

  it("should work for 95% coverage with nil test stats", () => {
    const wrapper = shallow(
      <FunctionDebuggerStatusbar
        coverage={getCoverage(15)}
        testStats={{
          total: undefined,
          failed: undefined,
        }}
      />
    );
    expect(wrapper.find(".coverageHigh").childAt(1).text()).toBe(
      "Coverage: 95%"
    );
  });

  it("should work for 85% coverage with no failed tests", () => {
    const wrapper = shallow(
      <FunctionDebuggerStatusbar
        coverage={getCoverage(13)}
        testStats={{
          total: 3,
          failed: 0,
        }}
      />
    );
    expect(wrapper.find(".coverageMedium").childAt(1).text()).toBe(
      "Coverage: 85%"
    );
  });

  it("should work for 55% coverage with failed tests", () => {
    const wrapper = shallow(
      <FunctionDebuggerStatusbar
        coverage={getCoverage(7)}
        testStats={{
          total: 3,
          failed: 2,
        }}
      />
    );
    expect(wrapper.find(".hasFailedTests").childAt(1).text()).toBe(
      "2/3 tests failed!"
    );
  });

  it("should work for failed coverage", () => {
    const wrapper = shallow(
      <FunctionDebuggerStatusbar
        coverage={{
          status: "failed",
          error: "oops",
        }}
      />
    );
    expect(wrapper.find(".coverageFailed").childAt(1).text()).toBe("oops");
  });
});
Example #9
Source File: FunctionDebuggerToolbar.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
export function FunctionDebuggerToolbar({
  type,
  status,
  saveDisabled,
  onButtonClick,
}: FunctionDebuggerToolbarProps): React.ReactElement {
  const refinedType = type ?? "input";
  const isInput = refinedType === "input" || refinedType === "test-input";

  const handleRunClick = useCallback(() => {
    onButtonClick?.({ action: "run" });
  }, [onButtonClick]);

  const handleSaveClick = useCallback(() => {
    if (!saveDisabled) {
      onButtonClick?.({ action: "save" });
    }
  }, [onButtonClick, saveDisabled]);

  const handleDeleteClick = useCallback(() => {
    onButtonClick?.({ action: "delete" });
  }, [onButtonClick]);

  return (
    <div
      className={classNames(
        styles.debuggerToolbar,
        status && styles[status],
        refinedType === "input" || refinedType === "output"
          ? styles.debug
          : styles.test,
        isInput ? styles.input : styles.output
      )}
      data-override-theme="dark"
    >
      <div className={styles.header}>
        {refinedType === "input"
          ? "Input"
          : refinedType === "test-input"
          ? "Test Input"
          : refinedType === "test-output"
          ? "Expect Output"
          : "Output"}
        {isInput && (
          <span className={styles.headerSuffix}>
            &nbsp;(argument list in JSON format)
          </span>
        )}
      </div>
      {isInput ? (
        <div className={styles.buttons}>
          <Tooltip title="Run">
            <div className={styles.debuggerButton} onClick={handleRunClick}>
              <PlayCircleOutlined />
            </div>
          </Tooltip>
          <Tooltip
            title={refinedType === "input" ? "Add as a test case" : "Update"}
          >
            <div
              className={classNames(styles.debuggerButton, {
                [styles.disabled]: saveDisabled,
              })}
              onClick={handleSaveClick}
            >
              {refinedType === "input" ? (
                <PlusCircleOutlined />
              ) : (
                <SaveOutlined />
              )}
            </div>
          </Tooltip>
          {refinedType === "test-input" && (
            <Tooltip title="Delete">
              <div
                className={styles.debuggerButton}
                onClick={handleDeleteClick}
              >
                <DeleteOutlined />
              </div>
            </Tooltip>
          )}
        </div>
      ) : (
        refinedType === "test-output" && (
          <div className={styles.secondHeader}>
            {status === "ok" ? (
              <>
                <span className={styles.secondHeaderIcon}>
                  <CheckOutlined />
                </span>
                <span>Test: passed</span>
              </>
            ) : status === "failed" ? (
              <>
                <span className={styles.secondHeaderIcon}>
                  <CloseOutlined />
                </span>
                <span>Test: failed</span>
              </>
            ) : (
              <>
                <span className={styles.secondHeaderIcon}>
                  <QuestionOutlined />
                </span>
                <span>Test: expired</span>
              </>
            )}
          </div>
        )
      )}
    </div>
  );
}
Example #10
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>
      </>
    );
  }
}
Example #11
Source File: ReportViewerPage.tsx    From yakit with GNU Affero General Public License v3.0 4 votes vote down vote up
ReportList: React.FC<ReportListProp> = React.memo((props) => {
    const [response, setResponse] = useState<QueryGeneralResponse<Report>>({
        Data: [],
        Pagination: genDefaultPagination(20),
        Total: 0
    })
    const [params, setParams] = useState<QueryReports>({
        From: "",
        Keyword: "",
        Owner: "",
        Pagination: genDefaultPagination(),
        Title: ""
    })
    const [loading, setLoading] = useState(false);
    const pagination = params.Pagination;
    const total = response.Total;

    const update = useMemoizedFn((page?: number, limit?: number) => {
        const pagination = {...params.Pagination};
        if (!!page) {
            pagination.Page = page
        }
        if (!!limit) {
            pagination.Limit = limit
        }
        setLoading(true)
        ipcRenderer.invoke("QueryReports", {
            ...params,
            Pagination: pagination
        }).then((rsp: QueryGeneralResponse<Report>) => {
            if (rsp) setResponse(rsp)
        }).catch(e => {
            failed("Query Reports Failed")
            console.info(e)
        }).finally(() => setTimeout(() => setLoading(false), 300))
    })

    useEffect(() => {
        update()
    }, [])

    return <AutoCard
        title={<Space>
            报告列表
        </Space>} size={"small"} loading={loading} bordered={false}
        extra={<Space>
            <Tooltip title={<>{`点击列表中的报告检查内容`}</>}><a href="#"><QuestionOutlined/></a></Tooltip>
            <a href="#" onClick={() => {
                update(1)
            }}><ReloadOutlined/></a>
        </Space>}
    >
        <List
            renderItem={(item: Report) => {
                return <AutoCard
                    onClick={() => {
                        props.onClick(item)
                    }}
                    style={{marginBottom: 8, backgroundColor: props.selectedId === item.Id ? "#cfdfff" : undefined}}
                    size="small"
                    title={item.Title}
                    extra={<Tag>{formatTimestamp(item.PublishedAt)}</Tag>}
                    hoverable={true}
                >
                    <Space>
                        {item.Id && <Tag color={"red"}>ID:{item.Id}</Tag>}
                        {item.Owner && <Tag color={"green"}>发起人:{item.Owner}</Tag>}
                        {item.From && <Tag color={"orange"}>来源:{item.From}</Tag>}
                    </Space>
                </AutoCard>
            }}
            dataSource={response.Data || []}
            pagination={{
                size: "small",
                pageSize: pagination?.Limit || 10, simple: true,
                total, showTotal: (i) => <Tag>共{i}条历史记录</Tag>,
                onChange: (page: number, limit?: number) => {
                    update(page, limit)
                }
            }}>

        </List>
    </AutoCard>
})
Example #12
Source File: YakScriptParamsSetter.tsx    From yakit with GNU Affero General Public License v3.0 4 votes vote down vote up
YakScriptParamsSetter: React.FC<YakScriptParamsSetterProps> = (props) => {
    // 新参数组件标记数组
    const newParamCom: string[] = ["upload-path", "select"]
    const [originParams, setOriginParams] = useState<YakScriptParam[]>(props.Params || []);
    const [groupStates, setGroupStates] = useState<{ group: string, hidden: boolean }[]>([]);

    // 参数组数据流
    const [extraGroup, setExtraGroup] = useState<string[]>([])
    const [requiredParams, setRequiredParams] = useState<YakScriptParam[]>([])
    const groupToParams = useRef<Map<string, YakScriptParam[]>>(new Map<string, YakScriptParam[]>())

    // 控制局部组件的加载状态
    const [templateLoading, setTemplateLoading] = useState<boolean>(false)
    // 上传组件多选时定时器和临时数据暂存点
    const timerToData = useRef<{ time: any, data: string }>({time: undefined, data: ""})
    // antd的Form表单验证,此变量非常重要,复制Form验证功能必须
    const [form] = Form.useForm()

    useEffect(() => {
        if ((props.Params || []).length === 0) return
        const cloneParams = props.Params.map(item => {
            item.Value = item.DefaultValue ? item.DefaultValue : undefined
            return item
        })
        setOriginParams(cloneParams)
        form.resetFields()
        form.setFieldsValue({originParams: cloneParams})
    }, [props.Params])

    useEffect(() => {
        const groupToParam = new Map<string, YakScriptParam[]>();
        const extraGroup: string[] = [];
        for (let item of originParams) {
            const group = item.Required ? "required" : (item.Group || "default");
            if (group !== "required" && !extraGroup.includes(group)) {
                extraGroup.push(group)
            }

            let params: YakScriptParam[] | undefined = groupToParam.get(group)
            if (params === undefined) {
                groupToParam.set(group, [])
                params = groupToParam.get(group)
            }
            if (params) params.push(item)
        }
        const requiredParam: YakScriptParam[] = groupToParam.get("required") || [];

        groupToParams.current = groupToParam
        setRequiredParams(requiredParam)
        setExtraGroup(extraGroup)
    }, [originParams])

    const yakScriptParamToNode = (i: YakScriptParam, required: boolean, key: string, disabled: boolean, formItemStyle?: React.CSSProperties) => {
        let index = 0
        for (let id in originParams) {
            if (originParams[id].Field === i.Field) {
                index = +id
                break
            }
        }

        return <Form.Item
            labelCol={{span: 6}}
            key={key}
            style={{marginBottom: 8, ...formItemStyle}}
            label={<Space size={2}>
                <>{i.FieldVerbose ? `${i.FieldVerbose}` : `${i.Field}`}</>
                {i.Help && <Tooltip title={i.Help}>
                    <Button icon={<QuestionOutlined/>} type={"link"} size={"small"}/>
                </Tooltip>}
            </Space>}
            // help={i.Help || undefined}
            required={required}
            name={["originParams", `${index}`, "Value"]}
            rules={[{
                validator: async (rule, value) => {
                    if (i.TypeVerbose === "boolean") return
                    else if (i.TypeVerbose === "float") {
                        if (value === undefined || value === null) throw new Error('该参数为必填项!')
                    } else {
                        if (required && (value || []).length === 0) throw new Error('该参数为必填项!')
                    }
                }
            }]}
        >
            <TypeVerboseToInput
                TypeVerbose={i.TypeVerbose}
                value={i.Value || i.DefaultValue}
                placeholder={i.DefaultValue}
                defaultValue={i.DefaultValue}
                disabled={disabled}
                setValue={value => {
                    originParams[index].Value = value
                    setOriginParams([...originParams])
                    form.setFieldsValue({originParams: {...originParams}})
                }}
            />
        </Form.Item>
    }

    const yakScriptParamToNewNode = (
        i: YakScriptParam,
        required: boolean,
        key: string,
        disabled: boolean,
        formItemStyle?: React.CSSProperties
    ) => {
        let index = 0
        for (let id in originParams) {
            if (originParams[id].Field === i.Field) {
                index = +id
                break
            }
        }

        let extraSetting: any = undefined
        try {
            extraSetting = JSON.parse(i.ExtraSetting || "{}")
        } catch (error) {
            failed("获取参数配置数据错误,请重新打开该页面")
        }

        if (i.TypeVerbose === "upload-path") {
            const before = (f: any) => {
                if (!timerToData.current.time) setTemplateLoading(true)
                if (timerToData.current.time) {
                    clearTimeout(timerToData.current.time)
                    timerToData.current.time = null
                }

                timerToData.current.data = timerToData.current.data ? `${timerToData.current.data},${f.path}` : f.path
                timerToData.current.time = setTimeout(() => {
                    for (let item of originParams) {
                        if (item.Field === i.Field) {
                            item.Value = item.Value ? `${item.Value},${timerToData.current.data}` : timerToData.current.data
                            break
                        }
                    }
                    setOriginParams([...originParams])
                    form.setFieldsValue({originParams: {...originParams}})
                    timerToData.current = {time: undefined, data: ""}
                    setTimeout(() => setTemplateLoading(false), 50)
                }, 100);

                return false
            }

            return (
                <Spin key={key} spinning={templateLoading}>
                    <ContentUploadInput
                        type={extraSetting.isTextArea ? "textarea" : "input"}
                        beforeUpload={(f: any) => before(f)}
                        dragger={{
                            accept: "",
                            multiple: true,
                            disabled: disabled || templateLoading
                        }}
                        item={{
                            style: {marginBottom: 8, ...formItemStyle},
                            labelCol: {span: 6},
                            label: (
                                <Space size={2}>
                                    <>{i.FieldVerbose ? `${i.FieldVerbose}` : `${i.Field}`}</>
                                    {i.Help && (
                                        <Tooltip title={i.Help}>
                                            <Button icon={<QuestionOutlined/>} type={"link"} size={"small"}/>
                                        </Tooltip>
                                    )}
                                </Space>
                            ),
                            required: required,
                            help: (
                                <div className='content-upload-input-help'>
                                    点击此处
                                    <Upload
                                        // accept={"text/plain"}
                                        accept={"*"}
                                        multiple={true}
                                        maxCount={1}
                                        showUploadList={false}
                                        beforeUpload={(f) => {
                                            before(f)
                                            return false
                                        }}
                                    >
                                        <span className='help-hint-title'>上传文件</span>
                                    </Upload>
                                    <Divider style={{margin: "0 5px"}} type="vertical"/>
                                    <Upload
                                        directory
                                        multiple={false}
                                        maxCount={1}
                                        showUploadList={false}
                                        beforeUpload={(f) => {
                                            before(f)
                                            return false
                                        }}
                                    >
                                        <span className='help-hint-title'>上传文件夹</span>
                                    </Upload>
                                </div>
                            ),
                            name: ["originParams", `${index}`, "Value"],
                            rules: [{
                                validator: async (rule, value) => {
                                    if (required && (value || []).length === 0) throw new Error('该参数为必填项!')
                                }
                            }],
                        }}
                        input={{
                            isBubbing: true,
                            setValue: (value) => {
                                originParams[index].Value = value
                                setOriginParams([...originParams])
                                form.setFieldsValue({originParams: {...originParams}})
                            },
                            value: i.Value,
                            placeholder: "获取文件路径,支持多选文件,文件夹,路径以逗号分隔",
                            disabled: disabled
                        }}
                        textarea={{
                            isBubbing: true,
                            setValue: (value) => {
                                originParams[index].Value = value
                                setOriginParams([...originParams])
                                form.setFieldsValue({originParams: {...originParams}})
                            },
                            rows: 1,
                            value: i.Value,
                            placeholder: "获取文件路径,支持多选文件,文件夹,路径以逗号分隔",
                            disabled: disabled
                        }}
                    />
                </Spin>
            )
        }

        if (i.TypeVerbose === "select") {
            return (
                <ItemSelects
                    key={key}
                    item={{
                        style: {marginBottom: 8, ...formItemStyle},
                        labelCol: {span: 6},
                        label: (
                            <Space size={2}>
                                <>{i.FieldVerbose ? `${i.FieldVerbose}` : `${i.Field}`}</>
                                {i.Help && (
                                    <Tooltip title={i.Help}>
                                        <Button icon={<QuestionOutlined/>} type={"link"} size={"small"}/>
                                    </Tooltip>
                                )}
                            </Space>
                        ),
                        name: ["originParams", `${index}`, "Value"],
                        required: required,
                        rules: [{
                            validator: async (rule, value) => {
                                if (required && (value || []).length === 0) throw new Error('该参数为必填项!')
                            }
                        }],
                    }}
                    select={{
                        tokenSeparators: [","],
                        allowClear: true,
                        data: extraSetting.data || [],
                        optText: "key",
                        value: (`${i.Value}` || "").split(",").filter(i => !!i),
                        setValue: (value) => {
                            originParams[index].Value = value
                            setOriginParams([...originParams])
                            form.setFieldsValue({originParams: {...originParams}})
                        },
                        mode: !!extraSetting.double ? 'tags' : undefined,
                        maxTagCount: !!extraSetting.double ? 'responsive' : undefined,
                        disabled: disabled
                    }}
                />
            )
        }
        return <div style={{height: 0}}></div>
    }

    const setHideGroup = (group: string, hidden: boolean) => {
        let newGroups: { group: string, hidden: boolean }[] = [
            ...groupStates.filter(i => i.group !== group),
            {group, hidden: hidden}];

        setGroupStates(newGroups)
    };

    const submit = () => {
        if (props.onClearData) props.onClearData()

        let params = originParams.filter(i => {
            // 处理 Bool 的情况
            if (isBoolean(i.TypeVerbose)) {
                return !!i.Value
            }

            // 真实的为空值
            if (!(i.Value || i.DefaultValue)) {
                if (i.Required) {
                    i.Value = `${i.TypeVerbose}_undefined`
                    return true
                } else {
                    return false
                }
            }

            // 处理其他参数的情况
            return true
        })
        props.onParamsConfirm(params.map(i => {
            return {Key: i.Field, Value: i.Value || i.DefaultValue}
        }))
    }

    const isGroupHidden = useMemoizedFn((group: string, defaultValue: boolean) => {
        if (group === "default") return false

        let res = defaultValue;
        groupStates.filter(i => i.group === group).forEach(i => {
            res = i.hidden
        })
        return res;
    })

    const renderExtraParams = (defaultExpand?: boolean) => {
        return <>
            {
                (extraGroup.length <= 1 && extraGroup.length > 0) ? <>
                    {/*<Title level={5} style={{fontSize: 14}}>*/}
                    {/*    <Space>*/}
                    {/*    <span>*/}
                    {/*        默认参数组*/}
                    {/*        </span>*/}
                    {/*        <Switch*/}
                    {/*            size={"small"}*/}
                    {/*            defaultChecked={!isGroupHidden("default", !defaultExpand)}*/}
                    {/*            onChange={(res) => {*/}
                    {/*                setHideGroup('default', !res)*/}
                    {/*            }}*/}
                    {/*        />*/}
                    {/*    </Space>*/}
                    {/*</Title>*/}
                    {!isGroupHidden(extraGroup[0] || "default", !defaultExpand) && <>
                        {(groupToParams.current.get(extraGroup[0] || "default") || []).map((i: YakScriptParam, index) => {
                            if (newParamCom.includes(i.TypeVerbose)) return yakScriptParamToNewNode(i, false, `defaultParamsGroup-${index}`, !!props.loading)
                            else return yakScriptParamToNode(i, false, `defaultParamsGroup-${index}`, !!props.loading)
                        })}
                    </>}
                </> : <>
                    {extraGroup.map((i, index) => {
                        if ((groupToParams.current.get(i) || []).length <= 0) {
                            return <></>
                        }
                        return <div key={`${index}`}>
                            <Title level={5} style={{fontSize: 14}}>
                                <Space>
                                    <span>
                                    参数组:{i}
                                    </span>
                                    <Switch
                                        size={"small"}
                                        checked={!isGroupHidden(i, !defaultExpand)}
                                        onChange={(res) => setHideGroup(i, !res)}
                                    />
                                </Space>
                            </Title>
                            {!isGroupHidden(i, !defaultExpand) && <>
                                {(groupToParams.current.get(i) || []).map((i: YakScriptParam, index) => {
                                    if (newParamCom.includes(i.TypeVerbose)) return yakScriptParamToNewNode(i, false, `paramsGroup-${index}`, !!props.loading)
                                    else return yakScriptParamToNode(i, false, `paramsGroup-${index}`, !!props.loading)
                                })}
                            </>}
                        </div>
                    })}
                </>
            }
        </>
    }

    if (props.primaryParamsOnly) {
        return (
            <Form
                form={form}
                onFinish={(value) => {
                    form.validateFields()
                        .then(values => submit())
                }}
                // onSubmitCapture={(e) => {
                //     e.preventDefault()
                //     // submit()
                // }}
                {...{labelCol: {span: 7}, wrapperCol: {span: 15}}}
            >
                {requiredParams.length > 0 ? (
                    <>
                        <div style={{marginTop: 0}}>
                            {requiredParams.map((i, index) => {
                                if (newParamCom.includes(i.TypeVerbose)) return yakScriptParamToNewNode(i, true, `params-${index}`, !!props.loading)
                                else return yakScriptParamToNode(i, true, `params-${index}`, !!props.loading)
                            })}
                        </div>
                        <Form.Item
                            label={" "}
                            colon={false}
                            style={{width: "100%", textAlign: "right"}}
                            labelCol={{span: 6}}
                        >
                            <Space>
                                {!props.hideClearButton && (
                                    <Button
                                        type={"link"}
                                        size={"small"}
                                        danger={true}
                                        onClick={() => {
                                            if (props.onClearData) props.onClearData()
                                        }}
                                    >
                                        清除缓存
                                    </Button>
                                )}
                                {groupToParams.current.size > 0 &&
                                (groupToParams.current.size === 1 &&
                                (groupToParams.current.get("default") || []).length <= 0 ? (
                                    ""
                                ) : (
                                    <Popover
                                        title={"设置额外参数"}
                                        trigger={"click"}
                                        content={<div style={{width: 700}}>{renderExtraParams(true)}</div>}
                                    >
                                        <Button size={"small"} type={"link"}>
                                            额外参数
                                        </Button>
                                    </Popover>
                                ))}
                                {props.loading ? (
                                    <Button
                                        style={{width: 120}}
                                        danger={true}
                                        onClick={() => {
                                            if (props.onCanceled) props.onCanceled()
                                        }}
                                        type={"primary"}
                                    >
                                        {props.cancelVerbose ? props.cancelVerbose : "停止任务"}
                                    </Button>
                                ) : (
                                    <Button style={{width: 120}} htmlType={"submit"} type={"primary"}>
                                        {props.submitVerbose ? props.submitVerbose : "启动任务"}
                                    </Button>
                                )}
                            </Space>
                        </Form.Item>
                    </>
                ) : (
                    <>
                        <Form.Item style={{width: "100%", textAlign: "right"}}>
                            <Space>
                                {props.loading ? (
                                    <Button
                                        style={{width: 200}}
                                        danger={true}
                                        onClick={() => {
                                            if (props.onCanceled) props.onCanceled()
                                        }}
                                        type={"primary"}
                                    >
                                        停止任务
                                    </Button>
                                ) : (
                                    <Button style={{width: 200}} htmlType={"submit"} type={"primary"}>
                                        启动任务
                                    </Button>
                                )}
                                {groupToParams.current.size > 0 && (
                                    <Popover
                                        title={"设置额外参数"}
                                        trigger={"click"}
                                        content={<div style={{width: 700}}>{renderExtraParams(true)}</div>}
                                    >
                                        <Button size={"small"} type={"link"}>
                                            额外参数
                                        </Button>
                                    </Popover>
                                )}
                            </Space>
                        </Form.Item>
                    </>
                )}
            </Form>
        )
    }

    return <div style={{
        marginLeft: props.styleSize === "big" ? 80 : undefined,
        marginRight: props.styleSize === "big" ? 100 : undefined,
    }}>
        <Card title={""} bodyStyle={{padding: 0}} bordered={false}>
            <Form
                onSubmitCapture={e => {
                    e.preventDefault()
                    submit()
                }}
                {...(props.styleSize !== "big" ? {
                    labelCol: {span: 7}, wrapperCol: {span: 14}
                } : {
                    layout: "vertical",
                })}
            >
                {/* 设置基础必须的参数,剩下其他参数不一定是必须的*/}
                {requiredParams.length > 0 && <>
                    <Title level={5} style={{fontSize: 14}}>
                        <Space>
                        <span>
                        必要参数
                        </span>
                            <Tooltip title={'执行该脚本不可或缺的参数 / Necessary Params'}>
                                <Button icon={<QuestionOutlined/>} type={"link"} size={"small"}/>
                            </Tooltip>
                        </Space>
                    </Title>
                    {requiredParams.map((i, index) => {
                        if (newParamCom.includes(i.TypeVerbose)) return yakScriptParamToNewNode(i, true, `params-${index}`, !!props.loading)
                        else return yakScriptParamToNode(i, true, `params-${index}`, !!props.loading)
                    })}
                </>}
                {renderExtraParams()}
                {originParams.length <= 0 && <Form.Item label={" "} colon={false}>
                    <h2>本模块无需设置额外参数</h2>
                </Form.Item>}
                <Form.Item colon={false} label={" "}>
                    <Button type="primary" loading={!!props.loading}
                            htmlType="submit"> {props.submitVerbose ? props.submitVerbose : "提交已设置的参数"} </Button>
                </Form.Item>
            </Form>
        </Card>
    </div>
}
Example #13
Source File: PluginOperator.tsx    From yakit with GNU Affero General Public License v3.0 4 votes vote down vote up
PluginOperator: React.FC<YakScriptOperatorProp> = (props) => {
    const [script, setScript] = useState<YakScript>()
    const [error, setError] = useState("")
    const [loading, setLoading] = useState(false)
    const [groups, setGroups] = useState<string[]>([])
    const [markdown, setMarkdown] = useState("")
    const [trigger, setTrigger] = useState(false)
    const [extraParams, setExtraParams] = useState<YakExecutorParam[]>();
    const [details, setDetails] = useState(true)

    const [settingShow, setSettingShow] = useState<boolean>(false)

    const updateGroups = () => {
        ipcRenderer
            .invoke("QueryGroupsByYakScriptId", {YakScriptId: props.yakScriptId})
            .then((data: { Groups: string[] }) => {
                setGroups(data.Groups)
            })
            .catch((e: any) => {
                console.info(e)
            })
            .finally()
    }

    const update = () => {
        if (props.yakScriptId <= 0) {
            return
        }
        updateGroups()

        setLoading(true)
        ipcRenderer
            .invoke("GetYakScriptById", {Id: props.yakScriptId})
            .then((e: YakScript) => {
                setScript(e)
                // setDetails(!e.IsGeneralModule)

                ipcRenderer
                    .invoke("GetMarkdownDocument", {
                        YakScriptId: e?.Id,
                        YakScriptName: e?.ScriptName
                    })
                    .then((data: { Markdown: string }) => {
                        setMarkdown(data.Markdown)
                    })
                    .catch((e: any) => {
                        setMarkdown("")
                    })
            })
            .catch((e: any) => {
                failed("Query YakScript By ID failed")
            })
            .finally(() =>
                setTimeout(() => {
                    setTrigger(!trigger)
                    setLoading(false)
                }, 300)
            )
    }

    useEffect(() => {
        update()
    }, [props.yakScriptId])

    // 来源于菜单进入以及开启了插件选择的话,就打开
    const enablePluginSelector = (!!script?.EnablePluginSelector) && props.fromMenu;
    const executor = useMemoizedFn(() => {
        return script && (
            <PluginExecutor
                subTitle={
                    <Space>
                        {script.Help && (
                            <Tooltip title={script.Help}>
                                <Button type={"link"} icon={<QuestionOutlined/>}/>
                            </Tooltip>
                        )}
                        <Space size={8}>
                            {/*{script?.ScriptName && (*/}
                            {/*    <Tag>{formatTimestamp(script?.CreatedAt)}</Tag>*/}
                            {/*)}*/}
                            <p style={{color: "#999999", marginBottom: 0}}>作者:{script?.Author}</p>
                            {script?.Tags
                                ? (script?.Tags || "")
                                    .split(",")
                                    .filter((i) => !!i)
                                    .map((i) => {
                                        return (
                                            <Tag
                                                style={{marginLeft: 2, marginRight: 0}}
                                                key={`${i}`}
                                                color={"geekblue"}
                                            >
                                                {i}
                                            </Tag>
                                        )
                                    })
                                : "No Tags"}
                        </Space>
                    </Space>
                }
                extraNode={
                    !props.fromMenu && (
                        <Space>
                            <Tooltip placement='top' title={"插件管理"}>
                                <Button
                                    type={"link"}
                                    icon={<SettingOutlined/>}
                                    onClick={() => setSettingShow(!settingShow)}
                                />
                            </Tooltip>
                            <Tooltip placement='top' title={"编辑插件"}>
                                <Button
                                    type={"link"}
                                    icon={<EditOutlined/>}
                                    style={{color: "#a7a7a7"}}
                                    onClick={(e) => {
                                        let m = showDrawer({
                                            title: `修改插件: ${script?.ScriptName}`,
                                            width: "100%",
                                            content: (
                                                <>
                                                    <YakScriptCreatorForm
                                                        modified={script}
                                                        onChanged={(i) => update()}
                                                        onCreated={() => {
                                                            m.destroy()
                                                        }}
                                                    />
                                                </>
                                            ),
                                            keyboard: false
                                        })
                                    }}
                                />
                            </Tooltip>
                        </Space>
                    )
                }
                script={script}
                size={props.size}
                extraYakExecutorParams={extraParams}
                settingShow={settingShow}
                settingNode={
                    <PluginManagement
                        style={{marginBottom: 10}}
                        script={script}
                        groups={groups}
                        update={() => {
                            setTimeout(() => props.setTrigger!(), 300)
                        }}
                        updateGroups={updateGroups}
                        setScript={props.setScript}
                    />
                }
            />
        )
    })

    const defaultContent = () => {
        return (
            <Tabs className="plugin-store-info" style={{height: "100%"}} type={"card"} defaultValue={"runner"}
                  tabPosition={"right"}>
                <Tabs.TabPane tab={"执行"} key={"runner"}>
                    {!enablePluginSelector && executor()}
                    {enablePluginSelector && <ResizeBox
                        firstNode={<SimplePluginList
                            pluginTypes={script?.PluginSelectorTypes || "mitm,port-scan"}
                            onSelected={names => {
                                setExtraParams([{Key: BUILDIN_PARAM_NAME_YAKIT_PLUGIN_NAMES, Value: names.join("|")}])
                            }}
                        />}
                        firstMinSize={"300px"}
                        firstRatio={"320px"}
                        secondNode={executor()}
                    >

                    </ResizeBox>}
                </Tabs.TabPane>
                <Tabs.TabPane tab={"文档"} key={"docs"}>
                    {script && (
                        <div style={{textAlign: "right", marginBottom: 10}}>
                            <Button
                                onClick={(e) => {
                                    let m = showDrawer({
                                        title: "编辑文档",
                                        keyboard: false,
                                        width: "94%",
                                        onClose: () => {
                                            update()
                                            m.destroy()
                                        },
                                        content: (
                                            <>
                                                <DocumentEditor
                                                    onFinished={() => {
                                                        m.destroy()
                                                    }}
                                                    markdown={markdown}
                                                    yakScript={script}
                                                />
                                            </>
                                        )
                                    })
                                }}
                            >
                                编辑文档
                            </Button>
                        </div>
                    )}
                    {markdown ? (
                        <div>
                            <MDEditor.Markdown source={markdown}/>
                        </div>
                    ) : (
                        <Empty style={{marginTop: 80}} description={"插件作者未添加文档"}/>
                    )}
                </Tabs.TabPane>
                <Tabs.TabPane tab={"源码"} key={"code"}>
                    <div style={{height: "100%"}}>
                        <YakEditor type={script?.Type || "yak"} value={script?.Content} readOnly={true}/>
                    </div>
                </Tabs.TabPane>
                <Tabs.TabPane tab={"历史"} key={"history"}>
                    {script && <PluginHistoryTable script={script} trigger={trigger}/>}
                    {/*<ExecHistoryTable mini={false} trigger={null as any}/>*/}
                </Tabs.TabPane>
                <Tabs.TabPane tab={"结果"} key={"results"}>
                    {script && <YakScriptExecResultTable YakScriptName={script.ScriptName} trigger={trigger}/>}
                </Tabs.TabPane>
            </Tabs>
        )
    }

    const showContent = (module: YakScript): JSX.Element => {
        if (!module) return <></>

        const key = module.GeneralModuleKey

        switch (key) {
            default:
                return defaultContent()
        }
    }

    return <div style={{
        marginLeft: 16,
        height: "100%"
    }}>{!!script && !!props.fromMenu ? showContent(script) : defaultContent()}</div>
}