@ant-design/icons#CheckCircleOutlined TypeScript Examples

The following examples show how to use @ant-design/icons#CheckCircleOutlined. 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: PasswordReset.tsx    From posthog-foss with MIT License 6 votes vote down vote up
export function PasswordReset(): JSX.Element {
    const { preflight, preflightLoading } = useValues(preflightLogic)
    const { resetResponse } = useValues(passwordResetLogic)

    return (
        <div className="bridge-page password-reset">
            <Row>
                <Col span={24} className="auth-main-content">
                    <WelcomeLogo view="login" />
                    <div className="inner">
                        {resetResponse?.success && (
                            <div className="text-center">
                                <CheckCircleOutlined style={{ color: 'var(--success)', fontSize: '4em' }} />
                            </div>
                        )}
                        <h2 className="subtitle" style={{ justifyContent: 'center' }}>
                            Reset password
                        </h2>
                        {preflightLoading ? (
                            <Skeleton active paragraph={{ rows: 4 }} />
                        ) : !preflight?.email_service_available ? (
                            <EmailUnavailable />
                        ) : resetResponse?.success ? (
                            <ResetSuccess />
                        ) : (
                            <ResetForm />
                        )}
                    </div>
                </Col>
            </Row>
        </div>
    )
}
Example #2
Source File: BillingSubscribed.tsx    From posthog-foss with MIT License 6 votes vote down vote up
function SubscriptionSuccess(): JSX.Element {
    const { push } = useActions(router)
    const { billing } = useValues(billingSubscribedLogic)

    return (
        <>
            <CheckCircleOutlined style={{ color: 'var(--success)' }} className="title-icon" />
            <h2 className="subtitle">You're all set!</h2>
            <p>
                You are now subscribed
                {billing?.is_billing_active && billing.plan && (
                    <>
                        {' '}
                        to the <b>{billing.plan.name}</b>
                    </>
                )}{' '}
                and can use all the premium features immediately.
            </p>
            {billing?.plan?.key === 'standard' && (
                <p className="text-muted-alt">
                    You will be billed within the <b>first 3 days of each month</b>. If you ingest less than 1M events,
                    you will not be billed.
                </p>
            )}
            <p>
                Please reach out to <a href="mailto:[email protected]">[email protected]</a> if you have any billing
                questions.
            </p>
            <Button className="btn-bridge outlined" block onClick={() => push('/')}>
                Finish
            </Button>
        </>
    )
}
Example #3
Source File: experimentsLogic.tsx    From posthog-foss with MIT License 6 votes vote down vote up
experimentsLogic = kea<experimentsLogicType>({
    path: ['scenes', 'experiments', 'experimentsLogic'],
    connect: { values: [teamLogic, ['currentTeamId']] },
    actions: {},
    loaders: ({ values }) => ({
        experiments: [
            [] as Experiment[],
            {
                loadExperiments: async () => {
                    const response = await api.get(`api/projects/${values.currentTeamId}/experiments`)
                    return response.results as Experiment[]
                },
                deleteExperiment: async (id: number) => {
                    await api.delete(`api/projects/${values.currentTeamId}/experiments/${id}`)
                    toast(
                        <div>
                            <h1 className="text-success">
                                <CheckCircleOutlined /> Experiment removed
                            </h1>
                        </div>
                    )
                    return values.experiments.filter((experiment) => experiment.id !== id)
                },
            },
        ],
    }),
    events: ({ actions }) => ({
        afterMount: () => {
            actions.loadExperiments()
        },
    }),
})
Example #4
Source File: Seeds.tsx    From dendron with GNU Affero General Public License v3.0 6 votes vote down vote up
/**
 * Component for Button to Add Seed to Workspace on a seed browser card
 * @param existsInWorkspace - does the seed already exist in the users workspace?
 * @param seedId - seed unique ID
 * @returns
 */
export function AddToWorkspaceButton({
  existsInWorkspace,
  seedId,
}: {
  existsInWorkspace: boolean;
  seedId: string;
}) {
  function onClick() {
    postVSCodeMessage({
      type: SeedBrowserMessageType.onSeedAdd,
      data: { data: seedId },
      source: DMessageSource.webClient,
    } as SeedBrowserMessage);
  }

  if (!existsInWorkspace) {
    return (
      <Tooltip placement="top" title="Add to Workspace">
        <DownloadOutlined key="download" onClick={onClick} />
      </Tooltip>
    );
  }
  return (
    <Tooltip placement="top" title="Already in Workspace">
      <CheckCircleOutlined key="installed" disabled />
    </Tooltip>
  );
}
Example #5
Source File: seeds.tsx    From dendron with GNU Affero General Public License v3.0 6 votes vote down vote up
/**
 * Component for Button to Add Seed to Workspace on a seed browser card
 * @param existsInWorkspace - does the seed already exist in the users workspace?
 * @param seedId - seed unique ID
 * @returns
 */
export function AddToWorkspaceButton({
  existsInWorkspace,
  seedId,
}: {
  existsInWorkspace: boolean;
  seedId: string;
}) {
  function onClick() {
    postVSCodeMessage({
      type: SeedBrowserMessageType.onSeedAdd,
      data: { data: seedId },
      source: DMessageSource.webClient,
    } as SeedBrowserMessage);
  }

  if (!existsInWorkspace) {
    return (
      <Tooltip placement="top" title="Add to Workspace">
        <DownloadOutlined key="download" onClick={onClick} />
      </Tooltip>
    );
  }
  return (
    <Tooltip placement="top" title="Already in Workspace">
      <CheckCircleOutlined key="installed" disabled />
    </Tooltip>
  );
}
Example #6
Source File: algo-node.tsx    From XFlow with MIT License 6 votes vote down vote up
AlgoIcon: React.FC<IProps> = props => {
  if (props.hide) {
    return null
  }
  switch (props.status) {
    case NsGraphStatusCommand.StatusEnum.PROCESSING:
      return <RedoOutlined spin style={{ color: '#c1cdf7', fontSize: '16px' }} />
    case NsGraphStatusCommand.StatusEnum.ERROR:
      return <CloseCircleOutlined style={{ color: '#ff4d4f', fontSize: '16px' }} />
    case NsGraphStatusCommand.StatusEnum.SUCCESS:
      return <CheckCircleOutlined style={{ color: '#39ca74cc', fontSize: '16px' }} />
    case NsGraphStatusCommand.StatusEnum.WARNING:
      return <ExclamationCircleOutlined style={{ color: '#faad14', fontSize: '16px' }} />
    case NsGraphStatusCommand.StatusEnum.DEFAULT:
      return <InfoCircleOutlined style={{ color: '#d9d9d9', fontSize: '16px' }} />
    default:
      return null
  }
}
Example #7
Source File: index.tsx    From XFlow with MIT License 6 votes vote down vote up
AlgoIcon: React.FC<IProps> = props => {
  if (props.hide) {
    return null
  }
  switch (props.status) {
    case StatusEnum.PROCESSING:
      return <RedoOutlined spin style={{ color: '#c1cdf7', fontSize: '16px' }} />
    case StatusEnum.ERROR:
      return <CloseCircleOutlined style={{ color: '#ff4d4f', fontSize: '16px' }} />
    case StatusEnum.SUCCESS:
      return <CheckCircleOutlined style={{ color: '#39ca74cc', fontSize: '16px' }} />
    case StatusEnum.WARNING:
      return <ExclamationCircleOutlined style={{ color: '#faad14', fontSize: '16px' }} />
    case StatusEnum.DEFAULT:
      return <InfoCircleOutlined style={{ color: '#d9d9d9', fontSize: '16px' }} />
    default:
      return null
  }
}
Example #8
Source File: WithoutActivation.tsx    From datart with Apache License 2.0 5 votes vote down vote up
Success = styled(CheckCircleOutlined)`
  display: block;
  padding-bottom: ${SPACE_MD};
  font-size: ${SPACE_TIMES(12)};
  color: ${p => p.theme.success};
  text-align: center;
`
Example #9
Source File: SendEmailTips.tsx    From datart with Apache License 2.0 5 votes vote down vote up
Success = styled(CheckCircleOutlined)`
  display: block;
  padding-bottom: ${SPACE_MD};
  font-size: ${SPACE_TIMES(12)};
  color: ${p => p.theme.success};
  text-align: center;
`
Example #10
Source File: UpdateStatusButton.tsx    From mayoor with MIT License 5 votes vote down vote up
UpdateStatusButton: React.FC<Props> = ({
	productionLogType,
	orderId,
	orderStatus,
}) => {
	const { t } = useTranslation();

	const [updateOrderStatus] = useMutation<UpdateOrderStatus, UpdateOrderStatusVariables>(
		UPDATE_ORDER_STATUS,
	);

	const getIsButtonDisabled = () => {
		if (
			productionLogType === ProductionLogType.PRINT &&
			orderStatus === OrderStatus.READY_TO_PRINT
		) {
			return false;
		}
		if (
			productionLogType === ProductionLogType.PRODUCTION &&
			orderStatus === OrderStatus.WAITING_FOR_PRODUCTION
		) {
			return false;
		}
		return true;
	};

	const getNextStatus = (): OrderStatus | undefined => {
		if (productionLogType === ProductionLogType.PRINT) {
			return OrderStatus.WAITING_FOR_PRODUCTION;
		}
		if (productionLogType === ProductionLogType.PRODUCTION) {
			return OrderStatus.TO_BE_SHIPPED;
		}
	};

	const markAsDoneHandler = async () => {
		const status = getNextStatus();
		if (!status) {
			return;
		}

		try {
			await updateOrderStatus({
				variables: {
					id: orderId,
					status,
				},
			});
			message.success(t('order_updated'));
		} catch (err) {
			console.error(err);
			message.error(t('order_update_failed'));
		}
	};

	return (
		<Button
			type="primary"
			icon={<CheckCircleOutlined />}
			onClick={markAsDoneHandler}
			disabled={getIsButtonDisabled()}
		>
			{t('Mark order as done')}
		</Button>
	);
}
Example #11
Source File: invitesLogic.tsx    From posthog-foss with MIT License 5 votes vote down vote up
invitesLogic = kea<invitesLogicType>({
    path: ['scenes', 'organization', 'Settings', 'invitesLogic'],
    loaders: ({ values }) => ({
        invites: {
            __default: [] as OrganizationInviteType[],
            loadInvites: async () => {
                return (await api.get('api/organizations/@current/invites/')).results
            },
            createInvite: async ({ targetEmail }: { targetEmail?: string }) => {
                const newInvite: OrganizationInviteType = await api.create('api/organizations/@current/invites/', {
                    target_email: targetEmail,
                })
                preflightLogic.actions.loadPreflight() // Make sure licensed_users_available is updated

                if (newInvite.emailing_attempt_made) {
                    toast(
                        <div>
                            <h1>Invite sent!</h1>
                            <p>{targetEmail} can now join PostHog by clicking the link on the sent email.</p>
                        </div>
                    )
                }

                return [newInvite, ...values.invites]
            },
            deleteInvite: async (invite: OrganizationInviteType) => {
                await api.delete(`api/organizations/@current/invites/${invite.id}/`)
                preflightLogic.actions.loadPreflight() // Make sure licensed_users_available is updated
                toast(
                    <div className="text-success">
                        <CheckCircleOutlined /> Invite for {invite.target_email} removed!
                    </div>
                )
                return values.invites.filter((thisInvite) => thisInvite.id !== invite.id)
            },
        },
    }),
    listeners: {
        createInviteSuccess: async () => {
            const nameProvided = false // TODO: Change when adding support for names on invites
            eventUsageLogic.actions.reportInviteAttempted(
                nameProvided,
                !!preflightLogic.values.preflight?.email_service_available
            )
        },
    },
    events: ({ actions }) => ({
        afterMount: actions.loadInvites,
    }),
})
Example #12
Source File: OnboardingSetup.tsx    From posthog-foss with MIT License 5 votes vote down vote up
function OnboardingStep({
    label,
    title,
    icon,
    identifier,
    disabled,
    completed,
    handleClick,
    caption,
    customActionElement,
    analyticsExtraArgs = {},
}: {
    label?: string
    title?: string
    icon: React.ReactNode
    identifier: string
    disabled?: boolean
    completed?: boolean
    handleClick?: () => void
    caption?: JSX.Element | string
    customActionElement?: JSX.Element
    analyticsExtraArgs?: Record<string, string | number | boolean>
}): JSX.Element {
    const actionElement = (
        <>
            {customActionElement || (
                <Button type="primary" disabled={disabled}>
                    {label}
                </Button>
            )}
        </>
    )
    const { reportOnboardingStepTriggered } = useActions(eventUsageLogic)

    const onClick = (): void => {
        if (disabled || completed || !handleClick) {
            return
        }
        reportOnboardingStepTriggered(identifier, analyticsExtraArgs)
        handleClick()
    }

    return (
        <div
            className={`onboarding-step${disabled ? ' disabled' : ''}${completed ? ' completed' : ''}`}
            onClick={onClick}
            data-attr="onboarding-setup-step"
            data-step={identifier}
        >
            {title && <div className="title">{title}</div>}
            <div className="icon-container">{icon}</div>
            {caption && <div className="caption">{caption}</div>}
            {completed ? (
                <div className="completed-label">
                    <CheckCircleOutlined />
                    {label}
                </div>
            ) : (
                actionElement
            )}
        </div>
    )
}
Example #13
Source File: membersLogic.tsx    From posthog-foss with MIT License 5 votes vote down vote up
membersLogic = kea<membersLogicType>({
    path: ['scenes', 'organization', 'Settings', 'membersLogic'],
    actions: {
        changeMemberAccessLevel: (member: OrganizationMemberType, level: OrganizationMembershipLevel) => ({
            member,
            level,
        }),
        postRemoveMember: (userUuid: string) => ({ userUuid }),
    },
    loaders: ({ values, actions }) => ({
        members: {
            __default: [] as OrganizationMemberType[],
            loadMembers: async () => {
                return (await api.get('api/organizations/@current/members/?limit=200')).results
            },
            removeMember: async (member: OrganizationMemberType) => {
                await api.delete(`api/organizations/@current/members/${member.user.uuid}/`)
                toast(
                    <div>
                        <h1 className="text-success">
                            <CheckCircleOutlined /> Removed <b>{member.user.first_name}</b> from organization.
                        </h1>
                    </div>
                )
                actions.postRemoveMember(member.user.uuid)
                return values.members.filter((thisMember) => thisMember.user.id !== member.user.id)
            },
        },
    }),
    listeners: ({ actions }) => ({
        changeMemberAccessLevel: async ({ member, level }) => {
            await api.update(`api/organizations/@current/members/${member.user.uuid}/`, { level })
            toast(
                <div>
                    <h1 className="text-success">
                        <CheckCircleOutlined /> Made <b>{member.user.first_name}</b> organization{' '}
                        {membershipLevelToName.get(level)}.
                    </h1>
                </div>
            )
            // reload organization to account for no longer being organization owner
            if (level === OrganizationMembershipLevel.Owner) {
                organizationLogic.actions.loadCurrentOrganization()
            }
            actions.loadMembers()
        },
        postRemoveMember: async ({ userUuid }) => {
            if (userUuid === userLogic.values.user?.uuid) {
                location.reload()
            }
        },
    }),
    events: ({ actions }) => ({
        afterMount: actions.loadMembers,
    }),
})
Example #14
Source File: GeoDataResolver.tsx    From jitsu with MIT License 4 votes vote down vote up
function GeoDataResolver() {
  const services = useServices()

  const [saving, setSaving] = useState(false)
  const [testingConnection, setTestingConnection] = useState(false)
  const [formDisabled, setFormDisabled] = useState(false)

  const [form] = useForm<GeoDataResolverFormValues>()

  const {
    error: loadingError,
    data: formConfig,
    setData: setFormConfig,
  } = useLoaderAsObject<MaxMindConfig>(async () => {
    const response = await services.backendApiClient.get(
      `/configurations/${geoDataResolversCollection}?id=${services.activeProject.id}`
    )

    let config = {
      license_key: response.maxmind?.license_key,
      enabled: response.maxmind?.enabled,
      editions: [],
    }

    //set statuses or load
    if (response.maxmind?.enabled && response.maxmind?._statuses) {
      config.editions = response.maxmind._statuses
    } else {
      const response = await ApplicationServices.get().backendApiClient.get(
        withQueryParams("/geo_data_resolvers/editions", { project_id: services.activeProject.id }),
        { proxy: true }
      )
      config.editions = response.editions
    }

    form.setFieldsValue({
      license_key: config.license_key,
      enabled: config.enabled,
    })

    setFormDisabled(!config.enabled)

    return config
  }, [])

  const submit = async () => {
    setSaving(true)
    let formValues = form.getFieldsValue()
    try {
      if (formValues.enabled) {
        await testConnection(true)
      }
      await save()
    } catch (error) {
      actionNotification.error(error.message || error)
    } finally {
      setSaving(false)
    }
  }

  const save = async () => {
    let formValues = form.getFieldsValue()

    let config = {
      maxmind: {
        enabled: formValues.enabled,
        license_key: formValues.license_key,
        _statuses: formValues.enabled ? formConfig.editions : null,
      },
    }

    await services.backendApiClient.post(
      `/configurations/${geoDataResolversCollection}?id=${services.activeProject.id}`,
      Marshal.toPureJson(config)
    )

    let anyConnected =
      formConfig.editions.filter(editionStatus => {
        return editionStatus.main.status === "ok" || editionStatus.analog?.status === "ok"
      }).length > 0

    if (!formValues.enabled || anyConnected) {
      actionNotification.success("Settings saved!")
    }

    if (formValues.enabled && !anyConnected) {
      actionNotification.warn(
        `Settings have been saved, but there is no available MaxMind database for this license key. Geo Resolution won't be applied to your JSON events`
      )
    }
  }

  const testConnection = async (hideMessage?: boolean) => {
    setTestingConnection(true)

    let formValues = form.getFieldsValue()

    try {
      const response = await ApplicationServices.get().backendApiClient.post(
        withQueryParams("/geo_data_resolvers/test", { project_id: services.activeProject.id }),
        { maxmind_url: formValues.license_key },
        {
          proxy: true,
        }
      )

      if (response.message) throw new Error(response.message)

      //enrich state
      let currentFormConfig = formConfig
      currentFormConfig.editions = response.editions
      setFormConfig(currentFormConfig)

      //show notification
      if (!hideMessage) {
        let anyConnected =
          formConfig.editions.filter(editionStatus => {
            return editionStatus.main.status === "ok" || editionStatus.analog?.status === "ok"
          }).length > 0

        if (anyConnected) {
          actionNotification.success("Successfully connected!")
        } else {
          actionNotification.error("Connection failed: there is no available MaxMind database for this license key")
        }
      }
    } catch (error) {
      if (!hideMessage) {
        handleError(error, "Connection failed")
      }
    } finally {
      setTestingConnection(false)
    }
  }

  const databaseStatusesRepresentation = (dbStatus: any) => {
    let body = <>-</>
    if (dbStatus) {
      let icon = (
        <Tooltip title="Not connected yet">
          <ClockCircleOutlined className="text-secondaryText" />
        </Tooltip>
      )

      if (dbStatus.status === "ok") {
        icon = (
          <Tooltip title="Successfully connected">
            <CheckCircleOutlined className="text-success" />
          </Tooltip>
        )
      } else if (dbStatus.status === "error") {
        icon = (
          <Tooltip title={dbStatus.message}>
            <CloseCircleOutlined className="text-error" />
          </Tooltip>
        )
      }

      body = (
        <>
          {dbStatus.name}: {icon}
        </>
      )
    }

    return body
  }

  if (loadingError) {
    return <CenteredError error={loadingError} />
  } else if (!formConfig) {
    return <CenteredSpin />
  }

  return (
    <div className="flex justify-center w-full">
      <div className="w-full pt-8 px-4" style={{ maxWidth: "1000px" }}>
        <p>
          Jitsu uses <a href="https://www.maxmind.com/">MaxMind</a> databases for geo resolution. There are two families
          of MaxMind databases: <b>GeoIP2</b> and <b>GeoLite2</b>. After setting a license key{" "}
          <b>all available MaxMind databases, which the license key has access</b>, will be downloaded and used for
          enriching incoming events. For using a certain database add{" "}
          <CodeInline>{"?edition_id=<database type>"}</CodeInline> to MaxMind License Key value. For example:{" "}
          <CodeInline>{"M10sDzWKmnDYUBM0?edition_id=GeoIP2-City,GeoIP2-ISP"}</CodeInline>.
        </p>

        <div className="w-96 flex-wrap flex justify-content-center">
          <Table
            pagination={false}
            columns={[
              {
                title: (
                  <>
                    Database{" "}
                    <Tooltip title="Paid MaxMind Database">
                      <QuestionCircleOutlined className="label-with-tooltip_question-mark" />
                    </Tooltip>
                  </>
                ),
                dataIndex: "main",
                key: "name",
                render: databaseStatusesRepresentation,
              },
              {
                title: (
                  <>
                    Analog{" "}
                    <Tooltip title="Free MaxMind Database analog. Usually it is less accurate than paid version. It is downloaded only if paid one is unavailable.">
                      <QuestionCircleOutlined className="label-with-tooltip_question-mark" />
                    </Tooltip>
                  </>
                ),
                dataIndex: "analog",
                key: "name",
                render: databaseStatusesRepresentation,
              },
            ]}
            dataSource={formConfig.editions}
          />
        </div>

        <br />
        <Form form={form} onFinish={submit}>
          <FormLayout>
            <FormField
              label="Enabled"
              tooltip={
                <>
                  If enabled - Jitsu downloads <a href="https://www.maxmind.com/en/geoip2-databases">GeoIP Databases</a>{" "}
                  with your license key and enriches incoming JSON events with location based data. Read more
                  information about{" "}
                  <a href="https://jitsu.com/docs/other-features/geo-data-resolution">Geo data resolution</a>.
                </>
              }
              key="enabled"
            >
              <Form.Item name="enabled" valuePropName="checked">
                <Switch
                  onChange={value => {
                    setFormDisabled(!value)
                  }}
                  size="default"
                />
              </Form.Item>
            </FormField>
            <FormField
              label="MaxMind License Key"
              tooltip={
                <>
                  Your MaxMind licence key. Obtain a new one in your <a href="https://www.maxmind.com/">Account</a>{" "}
                  {"->"} Manage License Keys. Jitsu downloads all available MaxMind databases with your license key. If
                  you would like to enrich events JSON with the only certain MaxMind DB data{": "}
                  specify license key with the format:{" "}
                  {"<license_key>?edition_id=<comma separated editions like: GeoIP2-City,GeoIP2-ISP>"}. If you use{" "}
                  <a href="https://cloud.jitsu.com/">Jitsu.Cloud</a> and MaxMind isn't set - free GeoLite2-City and
                  GeoLite2-ASN MaxMind databases are applied. Read more about{" "}
                  <a href="https://dev.maxmind.com/geoip/geolite2-free-geolocation-data?lang=en">
                    free MaxMind databases
                  </a>
                  .{" "}
                </>
              }
              key="license_key"
            >
              <Form.Item name="license_key">
                <Input
                  disabled={formDisabled}
                  size="large"
                  name="license_key"
                  placeholder="for example: M10sDzWKmnDYUBM0"
                  required={true}
                />
              </Form.Item>
            </FormField>
            <FormActions>
              <Button
                size="large"
                className="mr-3"
                type="dashed"
                loading={testingConnection}
                onClick={() => testConnection()}
                icon={<ApiOutlined />}
                disabled={formDisabled}
              >
                Test connection
              </Button>
              <Button loading={saving} htmlType="submit" size="large" type="primary">
                Save
              </Button>
            </FormActions>
          </FormLayout>
        </Form>
      </div>
    </div>
  )
}
Example #15
Source File: CustomDataDisplayComponents.tsx    From jmix-frontend with Apache License 2.0 4 votes vote down vote up
CustomDataDisplayComponents = () => {
    return (
        <div className={styles.narrowLayout}>
            <Space direction="vertical" style={{width: "100%"}}>
                <Card title="EntityHierarchyTree" size="small">
                    <EntityHierarchyTree
                        hierarchyProperty="parent"
                        items={[
                            {
                                id: "A",
                                _instanceName: "Node A",
                            }, {
                                id: "A1",
                                parent: "A",
                                _instanceName: "Node A1",
                            }, {
                                id: "A2",
                                parent: "A",
                                _instanceName: "Node A2",
                            }, {
                                id: "A21",
                                parent: "A2",
                                _instanceName: "Node A21",
                            }, {
                                id: "B",
                                _instanceName: "Node B",
                            }, {
                                id: "B1",
                                parent: "B",
                                _instanceName: "Node B1",
                            }, {
                                id: "C",
                                parent: undefined,
                                _instanceName: "Node C",
                            }]}
                    />
                </Card>
                <Card title="Label" size="small">
                    <Label
                        entityName="scr_Car"
                        propertyName="technicalCertificate"
                    />
                </Card>
                <Card title="tooltip" size="small">
                    <Tooltip title="Tooltip Title">
                        <Button type="link">Text with tooltip</Button>
                    </Tooltip>
                </Card>
                <Card title="ProgressBar">
                    <ProgressBar percent={50} />
                </Card>
                <CustomCard title="Card title"
                            className="custom-card">
                    <p>Card content</p>
                    <p>Card content</p>
                    <p>Card content</p>
                </CustomCard>
                <Card title="Grid">
                    <Row className={localStyles.rowItem}>
                        <Col span={24}>col</Col>
                    </Row>
                    <Row className={localStyles.rowItem}>
                        <Col span={12}>col-12</Col>
                        <Col span={12}>col-12</Col>
                    </Row>
                    <Row className={localStyles.rowItem}>
                        <Col span={8}>col-8</Col>
                        <Col span={8}>col-8</Col>
                        <Col span={8}>col-8</Col>
                    </Row>
                    <Row className={localStyles.rowItem}>
                        <Col span={6}>col-6</Col>
                        <Col span={6}>col-6</Col>
                        <Col span={6}>col-6</Col>
                        <Col span={6}>col-6</Col>
                    </Row>
                </Card>
                <Card title="DataTable">
                    <DataTable
                        loading={false}
                        onFilterChange={() => {}}
                        onSortOrderChange={() => {}}
                        onPaginationChange={() => {}}
                        entityName={'scr_Car'}
                        columnDefinitions={[
                            'manufacturer',
                            'model'
                        ]}
                        items={[
                            {manufacturer: 'AAA', model: '001', id: '1'},
                            {manufacturer: 'BBB', model: '002', id: '2'},
                        ]}
                        count={2}
                    />
                </Card>
                <Card title="Icons">
                    <PlusCircleOutlined />
                    <CheckCircleOutlined />
                </Card>
            </Space>
        </div>
    )
}
Example #16
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 #17
Source File: index.tsx    From nanolooker with MIT License 4 votes vote down vote up
BlockDetails: React.FC = () => {
  const { t } = useTranslation();
  const { theme, fiat } = React.useContext(PreferencesContext);
  const {
    marketStatistics: {
      currentPrice,
      priceStats: { bitcoin: { [fiat]: btcCurrentPrice = 0 } } = {
        bitcoin: { [fiat]: 0 },
      },
    },
    isInitialLoading: isMarketStatisticsInitialLoading,
  } = React.useContext(MarketStatisticsContext);
  const {
    blocks,
    blocksInfo,
    isLoading: isBlocksInfoLoading,
  } = React.useContext(BlocksInfoContext);
  const { knownAccounts } = React.useContext(KnownAccountsContext);
  const isSmallAndLower = !useMediaQuery("(min-width: 576px)");

  const skeletonProps = {
    active: true,
    paragraph: false,
    loading: isBlocksInfoLoading,
  };

  const blockInfo = blocksInfo?.blocks?.[blocks[0]];

  const {
    subtype,
    block_account: blockAccount,
    source_account: sourceAccount,
    height,
    contents: {
      type = "",
      representative = "",
      link = "",
      link_as_account: linkAsAccount = "",
      previous = "",
      signature = "",
      work = "",
    } = {},
    successor,
  } = blockInfo || {};

  const modifiedTimestamp = Number(blockInfo?.local_timestamp) * 1000;

  const amount = new BigNumber(rawToRai(blockInfo?.amount || 0)).toNumber();
  const fiatAmount = new BigNumber(amount)
    .times(currentPrice)
    .toFormat(CurrencyDecimal?.[fiat]);
  const btcAmount = new BigNumber(amount)
    .times(currentPrice)
    .dividedBy(btcCurrentPrice)
    .toFormat(12);

  const balance = new BigNumber(rawToRai(blockInfo?.balance || 0)).toNumber();
  const fiatBalance = new BigNumber(balance)
    .times(currentPrice)
    .toFormat(CurrencyDecimal?.[fiat]);
  const btcBalance = new BigNumber(balance)
    .times(currentPrice)
    .dividedBy(btcCurrentPrice)
    .toFormat(12);

  let linkAccountLabel = "";
  if (subtype === "send") {
    linkAccountLabel = t("pages.block.receiver");
  } else if (subtype === "receive") {
    linkAccountLabel = t("pages.block.sender");
  }

  const secondAccount = isValidAccountAddress(sourceAccount || "")
    ? sourceAccount
    : linkAsAccount;

  const blockAccountAlias = knownAccounts.find(
    ({ account: knownAccount }) => knownAccount === blockAccount,
  )?.alias;
  const secondAccountAlias = knownAccounts.find(
    ({ account: knownAccount }) => knownAccount === secondAccount,
  )?.alias;
  const representativeAlias = knownAccounts.find(
    ({ account: knownAccount }) => knownAccount === representative,
  )?.alias;

  const isConfirmed = toBoolean(blockInfo?.confirmed);

  return (
    <>
      {!isBlocksInfoLoading && !blockInfo ? (
        <Card bordered={false}>
          <Title level={3}>{t("pages.block.blockNotFound")}</Title>
          <Text>{t("pages.block.blockNotFoundInfo")}</Text>
        </Card>
      ) : null}
      {isBlocksInfoLoading || blockInfo ? (
        <>
          <Card
            size="small"
            bordered={false}
            className="detail-layout"
            style={{ marginBottom: "12px" }}
          >
            <Row gutter={6}>
              <Col xs={24}>
                <BlockHeader />
              </Col>
            </Row>
            <Row gutter={6}>
              {isSmallAndLower ? null : (
                <Col xs={24} sm={6} xl={4}>
                  {t("pages.block.blockSubtype")}
                </Col>
              )}
              <Col xs={24} sm={18} xl={20}>
                <Skeleton
                  {...skeletonProps}
                  title={{ width: isSmallAndLower ? "50%" : "20%" }}
                >
                  <Tooltip
                    placement={isSmallAndLower ? "right" : "top"}
                    title={t(
                      `pages.block.${
                        isConfirmed ? "confirmed" : "pending"
                      }Status`,
                    )}
                  >
                    <Tag
                      icon={
                        isConfirmed ? (
                          <CheckCircleOutlined />
                        ) : (
                          <SyncOutlined spin />
                        )
                      }
                      color={
                        // @ts-ignore
                        TwoToneColors[
                          `${(subtype || type).toUpperCase()}${
                            theme === Theme.DARK ? "_DARK" : ""
                          }`
                        ]
                      }
                      className={`tag-${subtype || type}`}
                    >
                      {t(`transaction.${subtype || type}`)}
                    </Tag>
                  </Tooltip>
                </Skeleton>
              </Col>
            </Row>
            <Row gutter={6}>
              <Col xs={24} sm={6} xl={4}>
                {t("common.account")}
              </Col>
              <Col xs={24} sm={18} xl={20}>
                <Skeleton {...skeletonProps}>
                  {blockAccountAlias ? (
                    <strong style={{ display: "block" }}>
                      {blockAccountAlias}
                    </strong>
                  ) : null}
                  <Link to={`/account/${blockAccount}`} className="break-word">
                    {blockAccount}
                  </Link>
                </Skeleton>
              </Col>
            </Row>
            <Row gutter={6}>
              <Col xs={24} sm={6} xl={4}>
                {t("transaction.amount")}
              </Col>
              <Col xs={24} sm={18} xl={20}>
                <LoadingStatistic
                  isLoading={skeletonProps.loading}
                  prefix="Ӿ"
                  value={
                    amount >= 1 ? amount : new BigNumber(amount).toFormat()
                  }
                />
                <Skeleton
                  {...skeletonProps}
                  loading={
                    skeletonProps.loading || isMarketStatisticsInitialLoading
                  }
                  title={{ width: isSmallAndLower ? "100%" : "33%" }}
                >
                  {`${CurrencySymbol?.[fiat]} ${fiatAmount} / ${btcAmount} BTC`}
                </Skeleton>
              </Col>
            </Row>
            <Row gutter={6}>
              <Col xs={24} sm={6} xl={4}>
                {t("common.balance")}
              </Col>
              <Col xs={24} sm={18} xl={20}>
                <Skeleton
                  {...skeletonProps}
                  title={{ width: isSmallAndLower ? "100%" : "33%" }}
                >
                  Ӿ {new BigNumber(balance).toFormat()}
                  <br />
                </Skeleton>
                <Skeleton
                  {...skeletonProps}
                  loading={
                    skeletonProps.loading || isMarketStatisticsInitialLoading
                  }
                  title={{ width: isSmallAndLower ? "100%" : "33%" }}
                >
                  {`${CurrencySymbol?.[fiat]} ${fiatBalance} / ${btcBalance} BTC`}
                </Skeleton>
              </Col>
            </Row>
            {linkAccountLabel ? (
              <Row gutter={6}>
                <Col xs={24} sm={6} xl={4}>
                  {linkAccountLabel}
                </Col>
                <Col xs={24} sm={18} xl={20}>
                  {secondAccountAlias ? (
                    <strong
                      style={{
                        display: "block",
                      }}
                    >
                      {secondAccountAlias}
                    </strong>
                  ) : null}
                  <Link to={`/account/${secondAccount}`} className="break-word">
                    {secondAccount}
                  </Link>
                </Col>
              </Row>
            ) : null}
            {representative ? (
              <Row gutter={6}>
                <Col xs={24} sm={6} xl={4}>
                  {t("common.representative")}
                </Col>
                <Col xs={24} sm={18} xl={20}>
                  {representativeAlias ? (
                    <strong
                      style={{
                        display: "block",
                      }}
                    >
                      {representativeAlias}
                    </strong>
                  ) : null}
                  <Link
                    to={`/account/${representative}`}
                    className="break-word"
                  >
                    {representative}
                  </Link>
                </Col>
              </Row>
            ) : null}
            <Row gutter={6}>
              <Col xs={24} sm={6} xl={4}>
                {t("pages.block.height")}
              </Col>
              <Col xs={24} sm={18} xl={20}>
                <Skeleton {...skeletonProps}>{height}</Skeleton>
              </Col>
            </Row>
            {modifiedTimestamp ? (
              <Row gutter={6}>
                <Col xs={24} sm={6} xl={4}>
                  {t("common.date")}
                </Col>
                <Col xs={24} sm={18} xl={20}>
                  {timestampToDate(modifiedTimestamp)}{" "}
                  <span className="color-muted" style={{ fontSize: "12px" }}>
                    (
                    <TimeAgo
                      locale={i18next.language}
                      datetime={modifiedTimestamp}
                      live={false}
                    />
                    )
                  </span>
                </Col>
              </Row>
            ) : null}
            <Row gutter={6}>
              <Col xs={24} sm={6} xl={4}>
                {t("pages.block.previousBlock")}
              </Col>
              <Col xs={24} sm={18} xl={20}>
                <Skeleton
                  {...skeletonProps}
                  title={{ width: isSmallAndLower ? "100%" : "50%" }}
                >
                  {isValidBlockHash(previous) ? (
                    <Link to={`/block/${previous}`} className="break-word">
                      {previous}
                    </Link>
                  ) : null}
                  {isNullAccountBlockHash(previous) ? (
                    <Text>{t("pages.block.openAccountBlock")}</Text>
                  ) : null}
                </Skeleton>
              </Col>
            </Row>
            <Row gutter={6}>
              <Col xs={24} sm={6} xl={4}>
                {t("pages.block.successorBlock")}
              </Col>
              <Skeleton
                {...skeletonProps}
                title={{ width: isSmallAndLower ? "100%" : "50%" }}
              ></Skeleton>
              <Col xs={24} sm={18} xl={20}>
                {isValidBlockHash(successor) ? (
                  <Link to={`/block/${successor}`} className="break-word">
                    {successor}
                  </Link>
                ) : null}
                {isNullAccountBlockHash(successor) ? (
                  <Text>{t("pages.block.lastAccountBlock")}</Text>
                ) : null}
              </Col>
            </Row>
            {link && subtype === "receive" ? (
              <Row gutter={6}>
                <Col xs={24} sm={6} xl={4}>
                  {t("pages.block.matchingSendBlock")}
                </Col>
                <Skeleton
                  {...skeletonProps}
                  title={{ width: isSmallAndLower ? "100%" : "50%" }}
                ></Skeleton>
                <Col xs={24} sm={18} xl={20}>
                  {isValidBlockHash(link) ? (
                    <Link to={`/block/${link}`} className="break-word">
                      {link}
                    </Link>
                  ) : (
                    t("pages.block.noMatchingSendBlock")
                  )}
                </Col>
              </Row>
            ) : null}
            <Row gutter={6}>
              <Col xs={24} sm={6} xl={4}>
                {t("pages.block.signature")}
              </Col>
              <Col xs={24} sm={18} xl={20}>
                <Skeleton {...skeletonProps}>
                  <span className="break-word">{signature}</span>
                </Skeleton>
              </Col>
            </Row>
            <Row gutter={6}>
              <Col xs={24} sm={6} xl={4}>
                {t("pages.block.work")}
              </Col>
              <Col xs={24} sm={18} xl={20}>
                <Skeleton
                  {...skeletonProps}
                  title={{ width: isSmallAndLower ? "100%" : "33%" }}
                >
                  {work}
                </Skeleton>
              </Col>
            </Row>
          </Card>

          <Title level={3}>{t("pages.block.originalBlockContent")}</Title>
          <Card size="small">
            <Skeleton {...skeletonProps} paragraph>
              <pre style={{ fontSize: "12px", marginBottom: 0 }}>
                {JSON.stringify(blockInfo, null, 2)}
              </pre>
            </Skeleton>
          </Card>
        </>
      ) : null}
    </>
  );
}
Example #18
Source File: index.tsx    From nanolooker with MIT License 4 votes vote down vote up
TransactionsTable = ({
  scrollTo,
  data,
  isLoading,
  showPaginate,
  isPaginated,
  pageSize,
  currentPage,
  totalPages,
  setCurrentPage,
  setCurrentHead,
}: TransactionsTableProps) => {
  const { t } = useTranslation();
  const { theme, natricons } = React.useContext(PreferencesContext);
  const { knownAccounts } = React.useContext(KnownAccountsContext);

  const isLargeAndHigher = useMediaQuery("(min-width: 992px)");
  const smallNatriconSize = !useMediaQuery("(min-width: 768px)");

  return (
    <Card size="small" className="transaction-card" id={scrollTo}>
      {isLoading ? (
        <div className="ant-spin-nested-loading">
          <div>
            <div className="ant-spin ant-spin-spinning">
              <span className="ant-spin-dot ant-spin-dot-spin">
                <i className="ant-spin-dot-item"></i>
                <i className="ant-spin-dot-item"></i>
                <i className="ant-spin-dot-item"></i>
                <i className="ant-spin-dot-item"></i>
              </span>
            </div>
          </div>
        </div>
      ) : null}
      {isLargeAndHigher ? (
        <Row
          gutter={[{ xs: 6, sm: 12, md: 12, lg: 12 }, 12]}
          className="row-header color-muted"
        >
          <Col xs={0} lg={2}>
            {t("transaction.type")}
          </Col>
          {natricons ? <Col xs={0} lg={2}></Col> : null}
          <Col xs={0} lg={natricons ? 12 : 14}>
            {t("transaction.accountAndBlock")}
          </Col>
          <Col xs={0} lg={5}>
            {t("transaction.amount")}
          </Col>
          <Col xs={0} lg={3} style={{ textAlign: "right" }}>
            {t("common.date")}
          </Col>
        </Row>
      ) : null}
      {data?.length ? (
        <>
          {data.map(
            (
              {
                subtype,
                type,
                account: historyAccount,
                amount,
                representative,
                hash,
                confirmed,
                local_timestamp: localTimestamp,
              }: History,
              index: number,
            ) => {
              const transactionType = subtype || type;
              const themeColor = `${transactionType.toUpperCase()}${
                theme === Theme.DARK ? "_DARK" : ""
              }`;
              // When transaction is a representative change, the account is the representative
              const account =
                transactionType === "change" ? representative : historyAccount;
              const knownAccount =
                account &&
                knownAccounts.find(
                  ({ account: knownAccount }) => account === knownAccount,
                );

              const modifiedTimestamp = Number(localTimestamp) * 1000;
              const modifiedDate = new Date(modifiedTimestamp);

              return (
                <Row
                  key={index}
                  justify="space-between"
                  align="middle"
                  gutter={[12, 12]}
                >
                  <Col
                    xs={natricons ? 12 : 24}
                    md={4}
                    lg={2}
                    className="gutter-row"
                    span={6}
                  >
                    <Tooltip
                      placement="right"
                      title={
                        typeof confirmed !== "undefined"
                          ? t(
                              `pages.block.${
                                toBoolean(confirmed) === false
                                  ? "pending"
                                  : "confirmed"
                              }Status`,
                            )
                          : null
                      }
                    >
                      <Tag
                        // @ts-ignore
                        color={TwoToneColors[themeColor]}
                        style={{ textTransform: "capitalize" }}
                        className={`tag-${subtype || type}`}
                        icon={
                          typeof confirmed !== "undefined" ? (
                            toBoolean(confirmed) === false ? (
                              <SyncOutlined spin />
                            ) : (
                              <CheckCircleOutlined />
                            )
                          ) : null
                        }
                      >
                        {t(`transaction.${transactionType}`)}
                      </Tag>
                    </Tooltip>
                  </Col>
                  {natricons ? (
                    <Col xs={12} md={2} style={{ textAlign: "right" }}>
                      <Natricon
                        account={account}
                        style={{
                          margin: "-12px -6px -18px -18px ",
                          width: `${smallNatriconSize ? 60 : 80}px`,
                          height: `${smallNatriconSize ? 60 : 80}px`,
                        }}
                      />
                    </Col>
                  ) : null}
                  <Col
                    xs={24}
                    md={natricons ? 18 : 20}
                    lg={natricons ? 12 : 14}
                  >
                    {knownAccount ? (
                      <div className="color-important">
                        {knownAccount.alias}
                      </div>
                    ) : null}
                    {account ? (
                      <Link
                        to={`/account/${account}`}
                        className="break-word color-normal"
                      >
                        {account}
                      </Link>
                    ) : (
                      t("common.notAvailable")
                    )}

                    <br />
                    <Link
                      to={`/block/${hash}`}
                      className="color-muted truncate"
                    >
                      {hash}
                    </Link>
                  </Col>
                  <Col xs={16} md={12} lg={5}>
                    <Text
                      // @ts-ignore
                      style={{ color: Colors[themeColor] }}
                      className="break-word"
                    >
                      {!amount || amount === "0"
                        ? t("common.notAvailable")
                        : ""}
                      {amount && amount !== "0"
                        ? `Ӿ ${new BigNumber(rawToRai(amount)).toFormat()}`
                        : ""}
                    </Text>
                  </Col>
                  <Col xs={8} md={12} lg={3} style={{ textAlign: "right" }}>
                    {Number(localTimestamp) ? (
                      <>
                        {modifiedDate.getFullYear()}/
                        {String(modifiedDate.getMonth() + 1).padStart(2, "0")}/
                        {String(modifiedDate.getDate()).padStart(2, "0")}
                        <br />
                        <TimeAgo
                          locale={i18next.language}
                          style={{ fontSize: "12px" }}
                          className="color-muted"
                          datetime={modifiedTimestamp}
                          live={false}
                        />
                      </>
                    ) : (
                      t("common.unknown")
                    )}
                  </Col>
                </Row>
              );
            },
          )}
          {showPaginate ? (
            <Row className="row-pagination">
              {isPaginated ? (
                <Col xs={24} style={{ textAlign: "right" }}>
                  <Pagination
                    size="small"
                    {...{
                      total: totalPages,
                      pageSize,
                      current: currentPage,
                      disabled: false,
                      onChange: (page: number) => {
                        if (scrollTo) {
                          const element = document.getElementById(scrollTo);
                          element?.scrollIntoView();
                        }

                        setCurrentPage?.(page);
                      },
                      showSizeChanger: false,
                    }}
                  />
                </Col>
              ) : null}
              {!isPaginated && setCurrentHead ? (
                <Col xs={24} style={{ textAlign: "center" }}>
                  <Button
                    // @ts-ignore
                    onClick={setCurrentHead}
                    type={theme === Theme.DARK ? "primary" : "default"}
                  >
                    {t("pages.account.loadMoreTransactions")}
                  </Button>
                </Col>
              ) : null}
            </Row>
          ) : null}
        </>
      ) : (
        <Empty
          image={Empty.PRESENTED_IMAGE_SIMPLE}
          style={{ padding: "12px" }}
        />
      )}
    </Card>
  );
}
Example #19
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 #20
Source File: index.tsx    From fe-v5 with Apache License 2.0 4 votes vote down vote up
export default function ImportAndDownloadModal(props: Props) {
  const { t } = useTranslation();
  const exportTextRef = useRef(null as any);
  const { status, title, exportData, description, onClose, onSubmit, crossCluster = true, onSuccess, label, fetchBuiltinFunc, submitBuiltinFunc, bgid } = props;
  const [form] = Form.useForm();
  const { clusters: clusterList } = useSelector<RootState, CommonStoreState>((state) => state.common);
  const [allList, setAllList] = useState<{ name: string }[]>([]);
  const [buildinList, setBuildinList] = useState<{ name: string }[]>([]);
  const [importResult, setImportResult] = useState<{ name: string; isTrue: boolean; msg: string }[]>();
  const columns = [
    {
      title: label,
      dataIndex: 'name',
    },
    {
      title: '导入结果',
      dataIndex: 'isTrue',
      render: (data) => {
        return data ? <CheckCircleOutlined style={{ color: '#389e0d', fontSize: '18px' }} /> : <CloseCircleOutlined style={{ color: '#d4380d', fontSize: '18px' }} />;
      },
    },
    {
      title: '错误消息',
      dataIndex: 'msg',
    },
  ];
  const builtinColumn = [
    {
      title: `${label}名称`,
      dataIndex: 'name',
    },
    {
      title: '操作',
      dataIndex: 'id',
      render(id, record) {
        return (
          <Button
            type='link'
            onClick={() => {
              submitBuiltinFunc &&
                submitBuiltinFunc(record.name, form.getFieldValue('cluster'), bgid!).then(({ dat }) => {
                  setImportResult(
                    Object.keys(dat).map((key) => {
                      return {
                        name: key,
                        key: key,
                        isTrue: !dat[key],
                        msg: dat[key],
                      };
                    }),
                  );
                });
            }}
          >
            导入
          </Button>
        );
      },
    },
  ];
  const handleClose = () => {
    onClose();
    importResult && importResult.some((item) => item.isTrue) && onSuccess && onSuccess();
  };
  useEffect(() => {
    if (status === ModalStatus.BuiltIn || status == ModalStatus.Import) {
      fetchBuiltinFunc &&
        fetchBuiltinFunc().then((res) => {
          let arr = res.dat.map((name) => ({ name }));
          setBuildinList(arr);
          setAllList(arr);
        });
    }
    setImportResult(undefined);
  }, [status]);

  const handleExportTxt = () => {
    download([exportData], 'download.json');
  };
  const computeTitle = isValidElement(title) ? title : status === ModalStatus.Export ? t('导出') + title : t('导入') + title;

  return (
    <Modal
      title={computeTitle}
      destroyOnClose={true}
      wrapClassName={isValidElement(title) ? 'import-modal-wrapper' : undefined}
      footer={
        status === ModalStatus.Import && (
          <>
            <Button key='delete' onClick={handleClose}>
              {t('取消')}
            </Button>
            {importResult ? (
              <Button type='primary' onClick={handleClose}>
                {t('关闭')}
              </Button>
            ) : (
              <Button
                key='submit'
                type='primary'
                onClick={async () => {
                  await form.validateFields();
                  const data = form.getFieldsValue();
                  try {
                    const importData = JSON.parse(data.import);
                    if (!Array.isArray(importData)) {
                      message.error(title + 'JSON需要时数组');
                      return;
                    }
                    const requstBody = importData.map((item) => {
                      return {
                        ...item,
                        cluster: crossCluster ? data.cluster : undefined,
                      };
                    });

                    const dat = await onSubmit(requstBody);
                    const dataSource = Object.keys(dat).map((key) => {
                      return {
                        name: key,
                        key: key,
                        isTrue: !dat[key],
                        msg: dat[key],
                      };
                    });
                    setImportResult(dataSource);
                    // 每个业务各自处理onSubmit
                  } catch (error) {
                    message.error(t('数据有误:') + error);
                  }
                }}
              >
                {t('确定')}
              </Button>
            )}
          </>
        )
      }
      onCancel={handleClose}
      afterClose={() => setImportResult(undefined)}
      visible={status !== 'hide'}
      width={600}
    >
      <div
        style={{
          color: '#999',
        }}
      >
        {description && <p>{description}</p>}
        {status === ModalStatus.Export && (
          <p>
            <a onClick={handleExportTxt}>Download.json</a>
            <a style={{ float: 'right' }} onClick={() => copyToClipBoard(exportData, t)}>
              <CopyOutlined />
              复制JSON内容到剪贴板
            </a>
          </p>
        )}
      </div>
      {(() => {
        switch (status) {
          case ModalStatus.Export:
            return (
              <div contentEditable='true' suppressContentEditableWarning={true} ref={exportTextRef} className='export-dialog code-area'>
                <pre>{exportData}</pre>
              </div>
            );

          case ModalStatus.BuiltIn:
            return (
              <>
                <Form form={form} preserve={false} layout='vertical'>
                  {crossCluster && (
                    <Form.Item
                      label={t('生效集群:')}
                      name='cluster'
                      initialValue={clusterList[0] || 'Default'}
                      rules={[
                        {
                          required: true,
                          message: t('生效集群不能为空'),
                        },
                      ]}
                    >
                      <Select suffixIcon={<CaretDownOutlined />}>
                        {clusterList?.map((item) => (
                          <Option value={item} key={item}>
                            {item}
                          </Option>
                        ))}
                      </Select>
                    </Form.Item>
                  )}
                </Form>
                <Input
                  placeholder={`请输入要查询的${label}名称`}
                  prefix={<SearchOutlined />}
                  style={{ marginBottom: '8px' }}
                  allowClear
                  onChange={(e) => {
                    let str = e.target.value;
                    let filterArr: { name: string }[] = [];
                    allList.forEach((el) => {
                      if (el.name.toLowerCase().indexOf(str.toLowerCase()) != -1) filterArr.push(el);
                    });
                    setBuildinList(filterArr);
                  }}
                />
                <Table className='samll_table' dataSource={buildinList} columns={builtinColumn} pagination={buildinList.length < 5 ? false : { pageSize: 5 }} size='small' />
                {importResult && (
                  <>
                    <Divider />
                    <Table className='samll_table' dataSource={importResult} columns={columns} size='small' pagination={importResult.length < 5 ? false : { pageSize: 5 }} />
                  </>
                )}
              </>
            );

          case ModalStatus.Import:
            return (
              <>
                <Form form={form} preserve={false} layout='vertical'>
                  {crossCluster ? (
                    <Form.Item
                      label={t('生效集群:')}
                      name='cluster'
                      initialValue={clusterList[0] || 'Default'}
                      rules={[
                        {
                          required: true,
                          message: t('生效集群不能为空'),
                        },
                      ]}
                    >
                      <Select suffixIcon={<CaretDownOutlined />}>
                        {clusterList?.map((item) => (
                          <Option value={item} key={item}>
                            {item}
                          </Option>
                        ))}
                      </Select>
                    </Form.Item>
                  ) : null}
                  <Form.Item
                    label={(!isValidElement(title) ? title : label) + t('JSON:')}
                    name='import'
                    rules={[
                      {
                        required: true,
                        message: t('请输入') + title,
                        validateTrigger: 'trigger',
                      },
                    ]}
                  >
                    <TextArea className='code-area' placeholder={t('请输入') + (!isValidElement(title) ? title : label)} rows={4}></TextArea>
                  </Form.Item>
                </Form>
                {importResult && (
                  <>
                    <Divider />
                    <Table className='samll_table' dataSource={importResult} columns={columns} pagination={false} size='small' />
                  </>
                )}
              </>
            );
        }
      })()}
    </Modal>
  );
}
Example #21
Source File: tasks.tsx    From leek with Apache License 2.0 4 votes vote down vote up
TasksPage: React.FC = () => {
  // STATE
  const service = new TaskService();
  const controlService = new ControlService();
  const { currentApp, currentEnv } = useApplication();

  // Filters
  const [filters, setFilters] = useState<any>();
  const [timeFilters, setTimeFilters] = useState<any>({
    timestamp_type: "timestamp",
    interval_type: "past",
    offset: 900000,
  });
  const [order, setOrder] = useState<string>("desc");

  // Data
  const columns = TaskDataColumns();
  const [pagination, setPagination] = useState<any>({
    pageSize: 20,
    current: 1,
  });
  const [loading, setLoading] = useState<boolean>();
  const [tasksRetrying, setTasksRetrying] = useState<boolean>();
  const [tasks, setTasks] = useState<any[]>([]);

  // API Calls
  function filterTasks(pager = { current: 1, pageSize: 20 }) {
    if (!currentApp) return;
    setLoading(true);
    let allFilters = {
      ...filters,
      ...timeFilters,
    };
    let from_ = (pager.current - 1) * pager.pageSize;
    service
      .filter(currentApp, currentEnv, pager.pageSize, from_, order, allFilters)
      .then(handleAPIResponse)
      .then((result: any) => {
        // Prepare pagination
        let p = fixPagination(result.hits.total.value, pager, filterTasks);
        if (p) setPagination(p);
        else return;
        // Result
        let tasksList: { any }[] = [];
        result.hits.hits.forEach(function (hit) {
          tasksList.push(hit._source);
        });
        setTasks(tasksList);
      }, handleAPIError)
      .catch(handleAPIError)
      .finally(() => setLoading(false));
  }

  // Hooks
  useEffect(() => {
    refresh(pagination);
  }, [currentApp, currentEnv, filters, timeFilters, order]);

  useEffect(() => {
    //console.log(tasks)
  }, [tasks]);

  // UI Callbacks
  function refresh(pager = { current: 1, pageSize: 20 }) {
    filterTasks(pager);
  }

  function handleShowTaskDetails(record) {
    window.open(
      `/task?app=${currentApp}&env=${currentEnv}&uuid=${record.uuid}`,
      "_blank"
    );
  }

  function handleRefresh() {
    refresh(pagination);
  }

  function handleShowTotal(total) {
    return `Total of ${total} tasks`;
  }

  function handleTableChange(pagination, filters, sorter) {
    refresh(pagination);
  }

  function handleFilterChange(values) {
    setFilters(values);
  }

  function prepareList(items) {
    return (
      <List
        header={
          <Row justify="center">
            <Text strong>Ineligible Tasks IDs</Text>
          </Row>
        }
        dataSource={items}
        style={{ maxHeight: 200, overflow: "auto" }}
        size="small"
        bordered
        renderItem={(item) => <List.Item>{item}</List.Item>}
      />
    );
  }

  function bulkRetryConfirmation(result) {
    if (result.eligible_tasks_count == 0) {
      message.warning("Found no eligible tasks for retrying!");
      return;
    }
    confirm({
      title: "Retry Filtered Tasks",
      icon: <ExclamationCircleOutlined />,
      content: (
        <>
          <Typography.Paragraph>
            Do you really want to retry filtered tasks?
            <ul>
              <li>
                {result.eligible_tasks_count} tasks are eligible to be retried.
              </li>
              <li>
                {result.ineligible_tasks_count} tasks are not eligible to be
                retried.
              </li>
            </ul>
          </Typography.Paragraph>
          {result.ineligible_tasks_count > 0 &&
            prepareList(result.ineligible_tasks_ids)}
        </>
      ),
      onOk() {
        return retryFiltered(false);
      },
    });
  }

  function pendingBulkRetry(result) {
    confirm({
      title: "Bulk tasks retry initiated!",
      icon: <CheckCircleOutlined style={{ color: "#00BFA6" }} />,
      content: (
        <>
          <Typography.Paragraph>
            Tasks queued to the broker, you can filter the retried tasks using
            the client name.
            <ul>
              <li>
                Client name:{" "}
                <Text copyable code>
                  {result.origin}
                </Text>
              </li>
              <li>{result.succeeded_retries_count} tasks set to retry.</li>
              <li>{result.failed_retries_count} tasks could not be retried.</li>
            </ul>
          </Typography.Paragraph>
          {result.failed_retries_count > 0 &&
            prepareList(result.failed_retries)}
        </>
      ),
      okText: "Ok",
      cancelButtonProps: { style: { display: "none" } },
    });
  }

  function retryFiltered(dryRun) {
    if (!currentApp || !currentEnv) return;
    setTasksRetrying(true);
    let allFilters = { ...filters, ...timeFilters };
    return controlService
      .retryTasksByQuery(currentApp, currentEnv, allFilters, dryRun)
      .then(handleAPIResponse)
      .then((result: any) => {
        if (dryRun) {
          bulkRetryConfirmation(result);
        } else {
          pendingBulkRetry(result);
        }
      }, handleAPIError)
      .catch(handleAPIError)
      .finally(() => setTasksRetrying(false));
  }

  function handleRetryFiltered() {
    retryFiltered(true);
  }

  return (
    <>
      <Helmet>
        <html lang="en" />
        <title>Tasks</title>
        <meta name="description" content="List of tasks" />
        <meta name="keywords" content="celery, tasks" />
      </Helmet>

      <Row style={{ marginBottom: "16px" }} gutter={[12, 12]}>
        <Col xxl={5} xl={6} md={7} lg={8} sm={24} xs={24}>
          <AttributesFilter
            onFilter={handleFilterChange}
            filters={timeFilters}
          />
        </Col>
        <Col xxl={19} xl={18} md={17} lg={16} sm={24} xs={24}>
          <Row justify="center" style={{ width: "100%" }}>
            <Card
              bodyStyle={{ paddingBottom: 0, paddingRight: 0, paddingLeft: 0 }}
              size="small"
              style={{ width: "100%" }}
              title={
                <Row align="middle">
                  <Col span={3}>
                    <Switch
                      defaultChecked={order == "desc"}
                      style={{ marginLeft: "10px" }}
                      onChange={(e) => {
                        setOrder(e ? "desc" : "asc");
                      }}
                      size="small"
                      checkedChildren={
                        <CaretUpOutlined style={{ color: "#333" }} />
                      }
                      unCheckedChildren={<CaretDownOutlined />}
                    />
                  </Col>
                  <Col span={18} style={{ textAlign: "center" }}>
                    <TimeFilter
                      timeFilter={timeFilters}
                      onTimeFilterChange={setTimeFilters}
                    />
                  </Col>
                  <Col span={3}>
                    <Space style={{ float: "right" }}>
                      {filters &&
                        filters.state &&
                        filters.state.length &&
                        filters.state.every((s) =>
                          TerminalStates.includes(s)
                        ) && (
                          <Button
                            ghost
                            type="primary"
                            size="small"
                            onClick={handleRetryFiltered}
                            loading={tasksRetrying}
                          >
                            Retry Filtered
                          </Button>
                        )}
                      <Button
                        size="small"
                        onClick={handleRefresh}
                        icon={<SyncOutlined />}
                      />
                    </Space>
                  </Col>
                </Row>
              }
            >
              <Table
                dataSource={tasks}
                columns={columns}
                pagination={{ ...pagination, showTotal: handleShowTotal }}
                loading={loading}
                size="small"
                rowKey="uuid"
                showHeader={false}
                onChange={handleTableChange}
                style={{ width: "100%" }}
                scroll={{ x: "100%" }}
                locale={{
                  emptyText: (
                    <div style={{ textAlign: "center" }}>
                      <Empty
                        image={Empty.PRESENTED_IMAGE_SIMPLE}
                        description={
                          <span>
                            No <a href="#API">tasks</a> found
                          </span>
                        }
                      />
                    </div>
                  ),
                }}
                onRow={(record, rowIndex) => {
                  return {
                    onClick: (event) => {
                      handleShowTaskDetails(record);
                    },
                  };
                }}
              />
            </Card>
          </Row>
        </Col>
      </Row>
    </>
  );
}
Example #22
Source File: control.tsx    From leek with Apache License 2.0 4 votes vote down vote up
ControlPage = () => {
  const [current, setCurrent] = useState(0);
  const [command, setCommand] = useState<string>("revoke");
  const { currentApp, currentEnv } = useApplication();

  const service = new ControlService();
  const metricsService = new MetricsService();
  const [broadcasting, setBroadcasting] = useState<boolean>();

  const [seenTasks, setSeenTasks] = useState([]);
  const [taskName, setTaskName] = useState<string>();
  const [terminate, setTerminate] = useState<boolean>(false);
  const [signal, setSignal] = useState<string>("SIGTERM");
  const [revocationCount, setRevocationCount] = useState<number>(0);

  const [seenTasksFetching, setSeenTasksFetching] = useState<boolean>();

  const next = () => {
    if (command === "revoke" && current === 1)
      revoke("true").then(() => {
        setCurrent(current + 1);
      });
    else setCurrent(current + 1);
  };

  const prev = () => {
    setCurrent(current - 1);
  };

  const memoizedTaskNameOptions = useMemo(() => {
    // memoize this because it's common to have many different task names, which causes the dropdown to be very laggy.
    // This is a known problem in Ant Design
    return seenTasks.map((task, key) => badgedOption(task));
  }, [seenTasks]);

  function revoke(dry_run) {
    if (!currentApp || !currentEnv || !taskName) return;
    setBroadcasting(true);
    return service
      .revokeTasksByName(
        currentApp,
        currentEnv,
        taskName,
        terminate,
        signal,
        dry_run
      )
      .then(handleAPIResponse)
      .then((result: any) => {
        setRevocationCount(result.revocation_count);
        if (dry_run !== "true") {
          setCurrent(0);
          pendingRevocation(result);
        }
      }, handleAPIError)
      .catch(handleAPIError)
      .finally(() => setBroadcasting(false));
  }

  function broadcastCommand() {
    if (command === "revoke") revoke("false");
  }

  function pendingRevocation(result) {
    confirm({
      title: "Tasks pending revocation!",
      icon: <CheckCircleOutlined style={{ color: "#00BFA6" }} />,
      content: (
        <>
          <Typography.Paragraph>
            Revocation command queued for {result.revocation_count} tasks!
          </Typography.Paragraph>
        </>
      ),
      okText: "Ok",
      cancelButtonProps: { style: { display: "none" } },
    });
  }

  function getSeenTasks(open) {
    if (!currentApp || !open) return;
    setSeenTasksFetching(true);
    metricsService
      .getSeenTasks(currentApp, currentEnv, {})
      .then(handleAPIResponse)
      .then((result: any) => {
        setSeenTasks(result.aggregations.seen_tasks.buckets);
      }, handleAPIError)
      .catch(handleAPIError)
      .finally(() => setSeenTasksFetching(false));
  }

  return (
    <>
      <Helmet>
        <html lang="en" />
        <title>Control</title>
        <meta name="description" content="Control commands" />
        <meta name="keywords" content="celery, commands" />
      </Helmet>

      {/* Steps */}
      <Row style={{ marginTop: 20 }}>
        <Card style={{ width: "100%" }}>
          <Steps current={current}>
            <Step title="Command" description="Choose command" />
            <Step title="Setup" description="Setup command args" />
            <Step title="Broadcast" description="Broadcast command" />
          </Steps>
        </Card>
      </Row>

      {/* Tabs Containers */}
      <Row style={{ marginTop: 20, marginBottom: 20 }}>
        <Card style={{ width: "100%", alignItems: "center" }}>
          {current == 0 && (
            <Row justify="center" style={{ width: "100%" }}>
              <Row style={{ width: "100%" }} justify="center">
                <Typography.Title level={5}>
                  What control command you want to broadcast?
                </Typography.Title>
              </Row>

              <Row style={{ width: "100%" }} justify="center">
                <Select
                  style={{ width: "200" }}
                  defaultValue="revoke"
                  onSelect={(value) => setCommand(value)}
                >
                  <Option value="revoke">Revoke</Option>
                </Select>
              </Row>
            </Row>
          )}

          {current == 1 && command === "revoke" && (
            <Row justify="center" style={{ width: "100%" }}>
              <Typography.Paragraph>
                Revoking tasks works by sending a broadcast message to all the
                workers, the workers then keep a list of revoked tasks in
                memory. When a worker receives a task in the list, it will skip
                executing the task.
              </Typography.Paragraph>

              <Select
                placeholder="Task name"
                style={{ width: "100%" }}
                allowClear
                showSearch
                dropdownMatchSelectWidth={false}
                onDropdownVisibleChange={getSeenTasks}
                notFoundContent={seenTasksFetching ? loadingIndicator : null}
                // @ts-ignore
                onSelect={(value) => setTaskName(value)}
              >
                {memoizedTaskNameOptions}
              </Select>

              <Row align="middle" style={{ marginTop: 16, width: "100%" }}>
                <Checkbox onChange={(e) => setTerminate(e.target.checked)}>
                  {" "}
                  Terminate already started tasks with
                </Checkbox>
                <Select
                  style={{ width: 90 }}
                  // @ts-ignore
                  onSelect={(value) => setSignal(value)}
                  defaultValue="SIGTERM"
                >
                  <Option value="SIGTERM">SIGTERM</Option>
                  <Option value="SIGKILL">SIGKILL</Option>
                </Select>
              </Row>

              <Row justify="start" style={{ width: "100%", marginTop: 10 }}>
                <Typography.Paragraph type="secondary">
                  The worker won’t terminate an already executing task unless
                  the terminate option is set.
                </Typography.Paragraph>
              </Row>

              <Divider />

              <Row justify="start" style={{ width: "100%" }}>
                <Typography.Text type="secondary">
                  <Typography.Text strong type="warning">
                    Caveats:
                  </Typography.Text>
                  <ul>
                    <li>
                      When a worker starts up it will synchronize revoked tasks
                      with other workers in the cluster unless you have disabled
                      synchronization using worker arg
                      <Typography.Text code>--without-mingle</Typography.Text>.
                    </li>
                    <li>
                      If The list of revoked tasks is in-memory and if all
                      workers restart the list of revoked ids will also vanish.
                      If you want to preserve this list between restarts you
                      need to specify a file for these to be stored in by using
                      the <Typography.Text code>–statedb</Typography.Text>{" "}
                      argument to celery worker.
                    </li>
                  </ul>
                </Typography.Text>
              </Row>
            </Row>
          )}

          {current == 2 && command === "revoke" && (
            <>
              <Row justify="center" style={{ width: "100%" }}>
                <Typography.Paragraph>
                  Found{" "}
                  <Typography.Text code>{revocationCount}</Typography.Text>{" "}
                  pending ( <TaskState state="QUEUED" />{" "}
                  <TaskState state="RECEIVED" /> <TaskState state="STARTED" />)
                  instances of task{" "}
                  <Typography.Text code>{taskName}</Typography.Text>. Are you
                  sure you want to revoke them all?
                </Typography.Paragraph>
              </Row>
              {terminate && (
                <Row justify="center" style={{ width: "100%" }}>
                  <Typography.Paragraph type="secondary">
                    If an instance is already <TaskState state="STARTED" /> it
                    will be terminated using{" "}
                    <Typography.Text code>{signal}</Typography.Text> signal!
                  </Typography.Paragraph>
                </Row>
              )}
            </>
          )}
        </Card>
      </Row>

      {/* Controls */}
      <Row justify="end">
        {current > 0 && (
          <Button style={{ margin: "0 8px" }} onClick={() => prev()}>
            Previous
          </Button>
        )}
        {current < 2 && (
          <Button type="primary" onClick={() => next()}>
            Next
          </Button>
        )}
        {current === 2 && (
          <Button
            type="primary"
            onClick={broadcastCommand}
            loading={broadcasting}
          >
            Broadcast
          </Button>
        )}
      </Row>
    </>
  );
}
Example #23
Source File: Stats.tsx    From leek with Apache License 2.0 4 votes vote down vote up
function Stats(stats: any) {
  return [
    {
      number: stats.SEEN_TASKS,
      text: "Total Tasks",
      icon: <UnorderedListOutlined />,
      tooltip: "Seen tasks names",
    },
    {
      number: stats.SEEN_WORKERS,
      text: "Total Workers",
      icon: <RobotFilled />,
      tooltip: "The total offline/online and beat workers",
    },
    {
      number: stats.PROCESSED_EVENTS,
      text: "Events Processed",
      icon: <ThunderboltOutlined />,
      tooltip: "The total processed events",
    },
    {
      number: stats.PROCESSED_TASKS,
      text: "Tasks Processed",
      icon: <SyncOutlined />,
      tooltip: "The total processed tasks",
    },
    {
      number: stats.QUEUED,
      text: "Tasks Queued",
      icon: <EllipsisOutlined />,
      tooltip: "The total tasks in the queues",
    },
    {
      number: stats.RETRY,
      text: "To Retry",
      icon: <RetweetOutlined style={{ color: STATES_COLORS.RETRY }} />,
      tooltip: "Tasks that are failed and waiting for retry",
    },
    {
      number: stats.RECEIVED,
      text: "Received",
      icon: <SendOutlined style={{ color: STATES_COLORS.RECEIVED }} />,
      tooltip: "Tasks were received by a worker. but not yet started",
    },
    {
      number: stats.STARTED,
      text: "Started",
      icon: <LoadingOutlined style={{ color: STATES_COLORS.STARTED }} />,
      tooltip:
        "Tasks that were started by a worker and still active, set (task_track_started) to True on worker level to report started tasks",
    },
    {
      number: stats.SUCCEEDED,
      text: "Succeeded",
      icon: <CheckCircleOutlined style={{ color: STATES_COLORS.SUCCEEDED }} />,
      tooltip: "Tasks that were succeeded",
    },
    {
      number: stats.RECOVERED,
      text: "Recovered",
      icon: <IssuesCloseOutlined style={{ color: STATES_COLORS.RECOVERED }} />,
      tooltip: "Tasks that were succeeded after retries.",
    },
    {
      number: stats.FAILED,
      text: "Failed",
      icon: <WarningOutlined style={{ color: STATES_COLORS.FAILED }} />,
      tooltip: "Tasks that were failed",
    },
    {
      number: stats.CRITICAL,
      text: "Critical",
      icon: <CloseCircleOutlined style={{ color: STATES_COLORS.CRITICAL }} />,
      tooltip: "Tasks that were failed after max retries.",
    },
    {
      number: stats.REJECTED,
      text: "Rejected",
      icon: <RollbackOutlined style={{ color: STATES_COLORS.REJECTED }} />,
      tooltip:
        "Tasks that were rejected by workers and requeued, or moved to a dead letter queue",
    },
    {
      number: stats.REVOKED,
      text: "Revoked",
      icon: <StopOutlined style={{ color: STATES_COLORS.REVOKED }} />,
      tooltip: "Tasks that were revoked by workers, but still in the queue.",
    },
  ];
}
Example #24
Source File: logModal.tsx    From ql with MIT License 4 votes vote down vote up
CronLogModal = ({
  cron,
  handleCancel,
  visible,
}: {
  cron?: any;
  visible: boolean;
  handleCancel: () => void;
}) => {
  const [value, setValue] = useState<string>('启动中...');
  const [loading, setLoading] = useState<any>(true);
  const [excuting, setExcuting] = useState<any>(true);
  const [isPhone, setIsPhone] = useState(false);

  const getCronLog = (isFirst?: boolean) => {
    if (isFirst) {
      setLoading(true);
    }
    request
      .get(`${config.apiPrefix}crons/${cron._id}/log`)
      .then((data: any) => {
        if (localStorage.getItem('logCron') === cron._id) {
          const log = data.data as string;
          setValue(log || '暂无日志');
          setExcuting(
            log && !log.includes('执行结束') && !log.includes('重启面板'),
          );
          if (log && !log.includes('执行结束') && !log.includes('重启面板')) {
            setTimeout(() => {
              getCronLog();
            }, 2000);
          }
          if (
            log &&
            log.includes('重启面板') &&
            cron.status === CrontabStatus.running
          ) {
            message.warning({ content: '系统将在5秒后自动刷新', duration: 5 });
            setTimeout(() => {
              window.location.reload();
            }, 5000);
          }
        }
      })
      .finally(() => {
        if (isFirst) {
          setLoading(false);
        }
      });
  };

  const cancel = () => {
    localStorage.removeItem('logCron');
    handleCancel();
  };

  const titleElement = () => {
    return (
      <>
        {excuting && <Loading3QuartersOutlined spin />}
        {!excuting && <CheckCircleOutlined />}
        <span style={{ marginLeft: 5 }}>日志-{cron && cron.name}</span>{' '}
      </>
    );
  };

  useEffect(() => {
    if (cron) {
      getCronLog(true);
    }
  }, [cron]);

  useEffect(() => {
    setIsPhone(document.body.clientWidth < 768);
  }, []);

  return (
    <Modal
      title={titleElement()}
      visible={visible}
      centered
      bodyStyle={{
        overflowY: 'auto',
        maxHeight: 'calc(80vh - var(--vh-offset, 0px))',
      }}
      forceRender
      onOk={() => cancel()}
      onCancel={() => cancel()}
    >
      {!loading && value && (
        <pre
          style={
            !isPhone
              ? { whiteSpace: 'break-spaces', lineHeight: '17px' }
              : {
                  whiteSpace: 'break-spaces',
                  lineHeight: '17px',
                  fontFamily: 'Source Code Pro',
                  width: 375,
                  zoom: 0.83,
                }
          }
        >
          {value}
        </pre>
      )}
    </Modal>
  );
}
Example #25
Source File: index.tsx    From ql with MIT License 4 votes vote down vote up
Crontab = () => {
  const columns = [
    {
      title: '任务名',
      dataIndex: 'name',
      key: 'name',
      align: 'center' as const,
      render: (text: string, record: any) => (
        <span>{record.name || record._id}</span>
      ),
    },
    {
      title: '任务',
      dataIndex: 'command',
      key: 'command',
      width: '40%',
      align: 'center' as const,
      render: (text: string, record: any) => {
        return (
          <span
            style={{
              textAlign: 'left',
              width: '100%',
              display: 'inline-block',
              wordBreak: 'break-all',
            }}
          >
            {text}
          </span>
        );
      },
    },
    {
      title: '任务定时',
      dataIndex: 'schedule',
      key: 'schedule',
      align: 'center' as const,
    },
    {
      title: '状态',
      key: 'status',
      dataIndex: 'status',
      align: 'center' as const,
      render: (text: string, record: any) => (
        <>
          {(!record.isDisabled || record.status !== CrontabStatus.idle) && (
            <>
              {record.status === CrontabStatus.idle && (
                <Tag icon={<ClockCircleOutlined />} color="default">
                  空闲中
                </Tag>
              )}
              {record.status === CrontabStatus.running && (
                <Tag
                  icon={<Loading3QuartersOutlined spin />}
                  color="processing"
                >
                  运行中
                </Tag>
              )}
              {record.status === CrontabStatus.queued && (
                <Tag icon={<FieldTimeOutlined />} color="default">
                  队列中
                </Tag>
              )}
            </>
          )}
          {record.isDisabled === 1 && record.status === CrontabStatus.idle && (
            <Tag icon={<CloseCircleOutlined />} color="error">
              已禁用
            </Tag>
          )}
        </>
      ),
    },
    {
      title: '操作',
      key: 'action',
      align: 'center' as const,
      render: (text: string, record: any, index: number) => (
        <Space size="middle">
          {record.status === CrontabStatus.idle && (
            <Tooltip title="运行">
              <a
                onClick={() => {
                  runCron(record, index);
                }}
              >
                <PlayCircleOutlined />
              </a>
            </Tooltip>
          )}
          {record.status !== CrontabStatus.idle && (
            <Tooltip title="停止">
              <a
                onClick={() => {
                  stopCron(record, index);
                }}
              >
                <PauseCircleOutlined />
              </a>
            </Tooltip>
          )}
          <Tooltip title="日志">
            <a
              onClick={() => {
                setLogCron({ ...record, timestamp: Date.now() });
              }}
            >
              <FileTextOutlined />
            </a>
          </Tooltip>
          <MoreBtn key="more" record={record} index={index} />
        </Space>
      ),
    },
  ];

  const [width, setWidth] = useState('100%');
  const [marginLeft, setMarginLeft] = useState(0);
  const [marginTop, setMarginTop] = useState(-72);
  const [value, setValue] = useState<any[]>([]);
  const [loading, setLoading] = useState(true);
  const [isModalVisible, setIsModalVisible] = useState(false);
  const [editedCron, setEditedCron] = useState();
  const [searchText, setSearchText] = useState('');
  const [isLogModalVisible, setIsLogModalVisible] = useState(false);
  const [logCron, setLogCron] = useState<any>();
  const [selectedRowIds, setSelectedRowIds] = useState<string[]>([]);
  const [currentPage, setCurrentPage] = useState(1);
  const [pageSize, setPageSize] = useState(20);

  const getCrons = () => {
    setLoading(true);
    request
      .get(`${config.apiPrefix}crons?searchValue=${searchText}`)
      .then((data: any) => {
        setValue(
          data.data.sort((a: any, b: any) => {
            const sortA = a.isDisabled ? 4 : a.status;
            const sortB = b.isDisabled ? 4 : b.status;
            return CrontabSort[sortA] - CrontabSort[sortB];
          }),
        );
      })
      .finally(() => setLoading(false));
  };

  const addCron = () => {
    setEditedCron(null as any);
    setIsModalVisible(true);
  };

  const editCron = (record: any, index: number) => {
    setEditedCron(record);
    setIsModalVisible(true);
  };

  const delCron = (record: any, index: number) => {
    Modal.confirm({
      title: '确认删除',
      content: (
        <>
          确认删除定时任务{' '}
          <Text style={{ wordBreak: 'break-all' }} type="warning">
            {record.name}
          </Text>{' '}
          吗
        </>
      ),
      onOk() {
        request
          .delete(`${config.apiPrefix}crons`, { data: [record._id] })
          .then((data: any) => {
            if (data.code === 200) {
              message.success('删除成功');
              const result = [...value];
              result.splice(index + pageSize * (currentPage - 1), 1);
              setValue(result);
            } else {
              message.error(data);
            }
          });
      },
      onCancel() {
        console.log('Cancel');
      },
    });
  };

  const runCron = (record: any, index: number) => {
    Modal.confirm({
      title: '确认运行',
      content: (
        <>
          确认运行定时任务{' '}
          <Text style={{ wordBreak: 'break-all' }} type="warning">
            {record.name}
          </Text>{' '}
          吗
        </>
      ),
      onOk() {
        request
          .put(`${config.apiPrefix}crons/run`, { data: [record._id] })
          .then((data: any) => {
            if (data.code === 200) {
              const result = [...value];
              result.splice(index + pageSize * (currentPage - 1), 1, {
                ...record,
                status: CrontabStatus.running,
              });
              setValue(result);
            } else {
              message.error(data);
            }
          });
      },
      onCancel() {
        console.log('Cancel');
      },
    });
  };

  const stopCron = (record: any, index: number) => {
    Modal.confirm({
      title: '确认停止',
      content: (
        <>
          确认停止定时任务{' '}
          <Text style={{ wordBreak: 'break-all' }} type="warning">
            {record.name}
          </Text>{' '}
          吗
        </>
      ),
      onOk() {
        request
          .put(`${config.apiPrefix}crons/stop`, { data: [record._id] })
          .then((data: any) => {
            if (data.code === 200) {
              const result = [...value];
              result.splice(index + pageSize * (currentPage - 1), 1, {
                ...record,
                pid: null,
                status: CrontabStatus.idle,
              });
              setValue(result);
            } else {
              message.error(data);
            }
          });
      },
      onCancel() {
        console.log('Cancel');
      },
    });
  };

  const enabledOrDisabledCron = (record: any, index: number) => {
    Modal.confirm({
      title: `确认${record.isDisabled === 1 ? '启用' : '禁用'}`,
      content: (
        <>
          确认{record.isDisabled === 1 ? '启用' : '禁用'}
          定时任务{' '}
          <Text style={{ wordBreak: 'break-all' }} type="warning">
            {record.name}
          </Text>{' '}
          吗
        </>
      ),
      onOk() {
        request
          .put(
            `${config.apiPrefix}crons/${
              record.isDisabled === 1 ? 'enable' : 'disable'
            }`,
            {
              data: [record._id],
            },
          )
          .then((data: any) => {
            if (data.code === 200) {
              const newStatus = record.isDisabled === 1 ? 0 : 1;
              const result = [...value];
              result.splice(index + pageSize * (currentPage - 1), 1, {
                ...record,
                isDisabled: newStatus,
              });
              setValue(result);
            } else {
              message.error(data);
            }
          });
      },
      onCancel() {
        console.log('Cancel');
      },
    });
  };

  const MoreBtn: React.FC<{
    record: any;
    index: number;
  }> = ({ record, index }) => (
    <Dropdown
      arrow
      trigger={['click']}
      overlay={
        <Menu onClick={({ key }) => action(key, record, index)}>
          <Menu.Item key="edit" icon={<EditOutlined />}>
            编辑
          </Menu.Item>
          <Menu.Item
            key="enableordisable"
            icon={
              record.isDisabled === 1 ? (
                <CheckCircleOutlined />
              ) : (
                <StopOutlined />
              )
            }
          >
            {record.isDisabled === 1 ? '启用' : '禁用'}
          </Menu.Item>
          {record.isSystem !== 1 && (
            <Menu.Item key="delete" icon={<DeleteOutlined />}>
              删除
            </Menu.Item>
          )}
        </Menu>
      }
    >
      <a>
        <EllipsisOutlined />
      </a>
    </Dropdown>
  );

  const action = (key: string | number, record: any, index: number) => {
    switch (key) {
      case 'edit':
        editCron(record, index);
        break;
      case 'enableordisable':
        enabledOrDisabledCron(record, index);
        break;
      case 'delete':
        delCron(record, index);
        break;
      default:
        break;
    }
  };

  const handleCancel = (cron?: any) => {
    setIsModalVisible(false);
    if (cron) {
      handleCrons(cron);
    }
  };

  const onSearch = (value: string) => {
    setSearchText(value);
  };

  const handleCrons = (cron: any) => {
    const index = value.findIndex((x) => x._id === cron._id);
    const result = [...value];
    if (index === -1) {
      result.push(cron);
    } else {
      result.splice(index, 1, {
        ...cron,
      });
    }
    setValue(result);
  };

  const getCronDetail = (cron: any) => {
    request
      .get(`${config.apiPrefix}crons/${cron._id}`)
      .then((data: any) => {
        console.log(value);
        const index = value.findIndex((x) => x._id === cron._id);
        console.log(index);
        const result = [...value];
        result.splice(index, 1, {
          ...cron,
          ...data.data,
        });
        setValue(result);
      })
      .finally(() => setLoading(false));
  };

  const onSelectChange = (selectedIds: any[]) => {
    setSelectedRowIds(selectedIds);
  };

  const rowSelection = {
    selectedRowIds,
    onChange: onSelectChange,
    selections: [
      Table.SELECTION_ALL,
      Table.SELECTION_INVERT,
      Table.SELECTION_NONE,
    ],
  };

  const delCrons = () => {
    Modal.confirm({
      title: '确认删除',
      content: <>确认删除选中的定时任务吗</>,
      onOk() {
        request
          .delete(`${config.apiPrefix}crons`, { data: selectedRowIds })
          .then((data: any) => {
            if (data.code === 200) {
              message.success('批量删除成功');
              setSelectedRowIds([]);
              getCrons();
            } else {
              message.error(data);
            }
          });
      },
      onCancel() {
        console.log('Cancel');
      },
    });
  };

  const operateCrons = (operationStatus: number) => {
    Modal.confirm({
      title: `确认${OperationName[operationStatus]}`,
      content: <>确认{OperationName[operationStatus]}选中的定时任务吗</>,
      onOk() {
        request
          .put(`${config.apiPrefix}crons/${OperationPath[operationStatus]}`, {
            data: selectedRowIds,
          })
          .then((data: any) => {
            if (data.code === 200) {
              getCrons();
            } else {
              message.error(data);
            }
          });
      },
      onCancel() {
        console.log('Cancel');
      },
    });
  };

  const onPageChange = (page: number, pageSize: number | undefined) => {
    setCurrentPage(page);
    setPageSize(pageSize as number);
    localStorage.setItem('pageSize', pageSize + '');
  };

  useEffect(() => {
    if (logCron) {
      localStorage.setItem('logCron', logCron._id);
      setIsLogModalVisible(true);
    }
  }, [logCron]);

  useEffect(() => {
    getCrons();
  }, [searchText]);

  useEffect(() => {
    if (document.body.clientWidth < 768) {
      setWidth('auto');
      setMarginLeft(0);
      setMarginTop(0);
    } else {
      setWidth('100%');
      setMarginLeft(0);
      setMarginTop(-72);
    }
    setPageSize(parseInt(localStorage.getItem('pageSize') || '20'));
  }, []);

  return (
    <PageContainer
      className="ql-container-wrapper crontab-wrapper"
      title="定时任务"
      extra={[
        <Search
          placeholder="请输入名称或者关键词"
          style={{ width: 'auto' }}
          enterButton
          loading={loading}
          onSearch={onSearch}
        />,
        <Button key="2" type="primary" onClick={() => addCron()}>
          添加定时
        </Button>,
      ]}
      header={{
        style: {
          padding: '4px 16px 4px 15px',
          position: 'sticky',
          top: 0,
          left: 0,
          zIndex: 20,
          marginTop,
          width,
          marginLeft,
        },
      }}
    >
      {selectedRowIds.length > 0 && (
        <div style={{ marginBottom: 16 }}>
          <Button type="primary" style={{ marginBottom: 5 }} onClick={delCrons}>
            批量删除
          </Button>
          <Button
            type="primary"
            onClick={() => operateCrons(0)}
            style={{ marginLeft: 8, marginBottom: 5 }}
          >
            批量启用
          </Button>
          <Button
            type="primary"
            onClick={() => operateCrons(1)}
            style={{ marginLeft: 8, marginRight: 8 }}
          >
            批量禁用
          </Button>
          <Button
            type="primary"
            style={{ marginRight: 8 }}
            onClick={() => operateCrons(2)}
          >
            批量运行
          </Button>
          <Button type="primary" onClick={() => operateCrons(3)}>
            批量停止
          </Button>
          <span style={{ marginLeft: 8 }}>
            已选择
            <a>{selectedRowIds?.length}</a>项
          </span>
        </div>
      )}
      <Table
        columns={columns}
        pagination={{
          hideOnSinglePage: true,
          current: currentPage,
          onChange: onPageChange,
          pageSize: pageSize,
          showSizeChanger: true,
          defaultPageSize: 20,
          showTotal: (total: number, range: number[]) =>
            `第 ${range[0]}-${range[1]} 条/总共 ${total} 条`,
        }}
        dataSource={value}
        rowKey="_id"
        size="middle"
        scroll={{ x: 768 }}
        loading={loading}
        rowSelection={rowSelection}
      />
      <CronLogModal
        visible={isLogModalVisible}
        handleCancel={() => {
          getCronDetail(logCron);
          setIsLogModalVisible(false);
        }}
        cron={logCron}
      />
      <CronModal
        visible={isModalVisible}
        handleCancel={handleCancel}
        cron={editedCron}
      />
    </PageContainer>
  );
}
Example #26
Source File: index.tsx    From ql with MIT License 4 votes vote down vote up
Config = () => {
  const columns = [
    {
      title: '序号',
      align: 'center' as const,
      render: (text: string, record: any, index: number) => {
        return <span style={{ cursor: 'text' }}>{index + 1} </span>;
      },
    },
    {
      title: '昵称',
      dataIndex: 'nickname',
      key: 'nickname',
      align: 'center' as const,
      width: '15%',
      render: (text: string, record: any, index: number) => {
        const match = record.value.match(/pt_pin=([^; ]+)(?=;?)/);
        const val = (match && match[1]) || '未匹配用户名';
        return (
          <span style={{ cursor: 'text' }}>{record.nickname || val} </span>
        );
      },
    },
    {
      title: '值',
      dataIndex: 'value',
      key: 'value',
      align: 'center' as const,
      width: '50%',
      render: (text: string, record: any) => {
        return (
          <span
            style={{
              textAlign: 'left',
              display: 'inline-block',
              wordBreak: 'break-all',
              cursor: 'text',
            }}
          >
            {text}
          </span>
        );
      },
    },
    {
      title: '状态',
      key: 'status',
      dataIndex: 'status',
      align: 'center' as const,
      width: '15%',
      render: (text: string, record: any, index: number) => {
        return (
          <Space size="middle" style={{ cursor: 'text' }}>
            <Tag
              color={StatusColor[record.status] || StatusColor[3]}
              style={{ marginRight: 0 }}
            >
              {Status[record.status]}
            </Tag>
            {record.status !== Status.已禁用 && (
              <Tooltip title="刷新">
                <a onClick={() => refreshStatus(record, index)}>
                  <SyncOutlined />
                </a>
              </Tooltip>
            )}
          </Space>
        );
      },
    },
    {
      title: '操作',
      key: 'action',
      align: 'center' as const,
      render: (text: string, record: any, index: number) => (
        <Space size="middle">
          <Tooltip title="编辑">
            <a onClick={() => editCookie(record, index)}>
              <EditOutlined />
            </a>
          </Tooltip>
          <Tooltip title={record.status === Status.已禁用 ? '启用' : '禁用'}>
            <a onClick={() => enabledOrDisabledCookie(record, index)}>
              {record.status === Status.已禁用 ? (
                <CheckCircleOutlined />
              ) : (
                <StopOutlined />
              )}
            </a>
          </Tooltip>
          <Tooltip title="删除">
            <a onClick={() => deleteCookie(record, index)}>
              <DeleteOutlined />
            </a>
          </Tooltip>
        </Space>
      ),
    },
  ];
  const [width, setWidth] = useState('100%');
  const [marginLeft, setMarginLeft] = useState(0);
  const [marginTop, setMarginTop] = useState(-72);
  const [value, setValue] = useState<any[]>([]);
  const [loading, setLoading] = useState(true);
  const [isModalVisible, setIsModalVisible] = useState(false);
  const [editedCookie, setEditedCookie] = useState();
  const [selectedRowIds, setSelectedRowIds] = useState<string[]>([]);

  const getCookies = () => {
    setLoading(true);
    request
      .get(`${config.apiPrefix}cookies`)
      .then((data: any) => {
        setValue(data.data);
      })
      .finally(() => setLoading(false));
  };

  const refreshStatus = (record: any, index: number) => {
    request
      .get(`${config.apiPrefix}cookies/${record._id}/refresh`)
      .then(async (data: any) => {
        if (data.data && data.data.value) {
          (value as any).splice(index, 1, data.data);
          setValue([...(value as any)] as any);
        } else {
          message.error('更新状态失败');
        }
      });
  };

  const enabledOrDisabledCookie = (record: any, index: number) => {
    Modal.confirm({
      title: `确认${record.status === Status.已禁用 ? '启用' : '禁用'}`,
      content: (
        <>
          确认{record.status === Status.已禁用 ? '启用' : '禁用'}
          Cookie{' '}
          <Text style={{ wordBreak: 'break-all' }} type="warning">
            {record.value}
          </Text>{' '}
          吗
        </>
      ),
      onOk() {
        request
          .put(
            `${config.apiPrefix}cookies/${
              record.status === Status.已禁用 ? 'enable' : 'disable'
            }`,
            {
              data: [record._id],
            },
          )
          .then((data: any) => {
            if (data.code === 200) {
              message.success(
                `${record.status === Status.已禁用 ? '启用' : '禁用'}成功`,
              );
              const newStatus =
                record.status === Status.已禁用 ? Status.未获取 : Status.已禁用;
              const result = [...value];
              result.splice(index, 1, {
                ...record,
                status: newStatus,
              });
              setValue(result);
            } else {
              message.error(data);
            }
          });
      },
      onCancel() {
        console.log('Cancel');
      },
    });
  };

  const addCookie = () => {
    setEditedCookie(null as any);
    setIsModalVisible(true);
  };

  const editCookie = (record: any, index: number) => {
    setEditedCookie(record);
    setIsModalVisible(true);
  };

  const deleteCookie = (record: any, index: number) => {
    Modal.confirm({
      title: '确认删除',
      content: (
        <>
          确认删除Cookie{' '}
          <Text style={{ wordBreak: 'break-all' }} type="warning">
            {record.value}
          </Text>{' '}
          吗
        </>
      ),
      onOk() {
        request
          .delete(`${config.apiPrefix}cookies`, { data: [record._id] })
          .then((data: any) => {
            if (data.code === 200) {
              message.success('删除成功');
              const result = [...value];
              result.splice(index, 1);
              setValue(result);
            } else {
              message.error(data);
            }
          });
      },
      onCancel() {
        console.log('Cancel');
      },
    });
  };

  const handleCancel = (cookies?: any[]) => {
    setIsModalVisible(false);
    if (cookies && cookies.length > 0) {
      handleCookies(cookies);
    }
  };

  const handleCookies = (cookies: any[]) => {
    const result = [...value];
    for (let i = 0; i < cookies.length; i++) {
      const cookie = cookies[i];
      const index = value.findIndex((x) => x._id === cookie._id);
      if (index === -1) {
        result.push(cookie);
      } else {
        result.splice(index, 1, {
          ...cookie,
        });
      }
    }
    setValue(result);
  };

  const components = {
    body: {
      row: DragableBodyRow,
    },
  };

  const moveRow = useCallback(
    (dragIndex, hoverIndex) => {
      if (dragIndex === hoverIndex) {
        return;
      }
      const dragRow = value[dragIndex];
      const newData = [...value];
      newData.splice(dragIndex, 1);
      newData.splice(hoverIndex, 0, dragRow);
      setValue([...newData]);
      request
        .put(`${config.apiPrefix}cookies/${dragRow._id}/move`, {
          data: { fromIndex: dragIndex, toIndex: hoverIndex },
        })
        .then((data: any) => {
          if (data.code !== 200) {
            message.error(data);
          }
        });
    },
    [value],
  );

  const onSelectChange = (selectedIds: any[]) => {
    setSelectedRowIds(selectedIds);
  };

  const rowSelection = {
    selectedRowIds,
    onChange: onSelectChange,
  };

  const delCookies = () => {
    Modal.confirm({
      title: '确认删除',
      content: <>确认删除选中的Cookie吗</>,
      onOk() {
        request
          .delete(`${config.apiPrefix}cookies`, { data: selectedRowIds })
          .then((data: any) => {
            if (data.code === 200) {
              message.success('批量删除成功');
              setSelectedRowIds([]);
              getCookies();
            } else {
              message.error(data);
            }
          });
      },
      onCancel() {
        console.log('Cancel');
      },
    });
  };

  const operateCookies = (operationStatus: number) => {
    Modal.confirm({
      title: `确认${OperationName[operationStatus]}`,
      content: <>确认{OperationName[operationStatus]}选中的Cookie吗</>,
      onOk() {
        request
          .put(`${config.apiPrefix}cookies/${OperationPath[operationStatus]}`, {
            data: selectedRowIds,
          })
          .then((data: any) => {
            if (data.code === 200) {
              getCookies();
            } else {
              message.error(data);
            }
          });
      },
      onCancel() {
        console.log('Cancel');
      },
    });
  };

  useEffect(() => {
    if (document.body.clientWidth < 768) {
      setWidth('auto');
      setMarginLeft(0);
      setMarginTop(0);
    } else {
      setWidth('100%');
      setMarginLeft(0);
      setMarginTop(-72);
    }
    getCookies();
  }, []);

  return (
    <PageContainer
      className="session-wrapper"
      title="Session管理"
      extra={[
        <Button key="2" type="primary" onClick={() => addCookie()}>
          添加Cookie
        </Button>,
      ]}
      header={{
        style: {
          padding: '4px 16px 4px 15px',
          position: 'sticky',
          top: 0,
          left: 0,
          zIndex: 20,
          marginTop,
          width,
          marginLeft,
        },
      }}
    >
      {selectedRowIds.length > 0 && (
        <div style={{ marginBottom: 16 }}>
          <Button
            type="primary"
            style={{ marginBottom: 5 }}
            onClick={delCookies}
          >
            批量删除
          </Button>
          <Button
            type="primary"
            onClick={() => operateCookies(0)}
            style={{ marginLeft: 8, marginBottom: 5 }}
          >
            批量启用
          </Button>
          <Button
            type="primary"
            onClick={() => operateCookies(1)}
            style={{ marginLeft: 8, marginRight: 8 }}
          >
            批量禁用
          </Button>
          <span style={{ marginLeft: 8 }}>
            已选择
            <a>{selectedRowIds?.length}</a>项
          </span>
        </div>
      )}
      <DndProvider backend={HTML5Backend}>
        <Table
          columns={columns}
          rowSelection={rowSelection}
          pagination={false}
          dataSource={value}
          rowKey="_id"
          size="middle"
          scroll={{ x: 768 }}
          components={components}
          loading={loading}
          onRow={(record, index) => {
            return {
              index,
              moveRow,
            } as any;
          }}
        />
      </DndProvider>
      <CookieModal
        visible={isModalVisible}
        handleCancel={handleCancel}
        cookie={editedCookie}
      />
    </PageContainer>
  );
}
Example #27
Source File: index.tsx    From posthog-foss with MIT License 4 votes vote down vote up
export function AsyncMigrations(): JSX.Element {
    const { user } = useValues(userLogic)
    const { asyncMigrations, asyncMigrationsLoading, activeTab, asyncMigrationSettings } =
        useValues(asyncMigrationsLogic)
    const { triggerMigration, forceStopMigration, loadAsyncMigrations, setActiveTab } = useActions(asyncMigrationsLogic)

    const columns = [
        {
            title: '',
            render: function RenderTriggerButton(asyncMigration: AsyncMigration): JSX.Element {
                const status = asyncMigration.status
                return (
                    <Tooltip title={tooltipMessageForStatus[status]}>
                        {status === 0 ? (
                            <PlayCircleOutlined
                                className="migration-btn success"
                                onClick={() => triggerMigration(asyncMigration.id)}
                            />
                        ) : status === 1 ? (
                            <StopOutlined
                                className="migration-btn danger"
                                onClick={() => forceStopMigration(asyncMigration.id)}
                            />
                        ) : status === 2 ? (
                            <CheckCircleOutlined className="success" />
                        ) : status === 3 || status === 4 ? (
                            <RedoOutlined
                                className="migration-btn warning"
                                onClick={() => triggerMigration(asyncMigration.id)}
                            />
                        ) : status === 5 ? (
                            <Spinner size="sm" />
                        ) : null}
                    </Tooltip>
                )
            },
        },
        {
            title: 'Migration name',
            dataIndex: 'name',
        },
        {
            title: 'Description',
            render: function RenderError(asyncMigration: AsyncMigration): JSX.Element {
                const description = asyncMigration.description
                return (
                    <small>
                        <span>{description.slice(0, 40)}</span>
                        {description.length > 40 ? (
                            <a
                                onClick={() => {
                                    Modal.info({
                                        title: `'${asyncMigration.name}' description`,
                                        content: <pre>{description}</pre>,
                                        icon: <InfoCircleOutlined />,
                                        okText: 'Close',
                                        width: '80%',
                                    })
                                }}
                            >
                                {` [...]`}
                            </a>
                        ) : null}
                    </small>
                )
            },
        },
        {
            title: 'Progress',
            dataIndex: 'progress',
            render: function RenderMigrationProgress(progress: number): JSX.Element {
                return (
                    <div>
                        <Progress percent={progress} />
                    </div>
                )
            },
        },
        {
            title: 'Status',
            dataIndex: 'status',
            render: function RenderMigrationStatus(status: number): JSX.Element {
                return <div>{migrationStatusNumberToMessage[status]}</div>
            },
        },
        {
            title: 'Error',
            render: function RenderError(asyncMigration: AsyncMigration): JSX.Element {
                const error = asyncMigration.last_error || ''
                return (
                    <small>
                        <span>{error.slice(0, 40)}</span>
                        {error.length > 40 ? (
                            <a
                                onClick={() => {
                                    Modal.info({
                                        title: `Error on migration '${asyncMigration.name}'`,
                                        content: <pre>{error}</pre>,
                                        icon: <InfoCircleOutlined />,
                                        okText: 'Close',
                                        width: '80%',
                                    })
                                }}
                            >
                                {` [...]`}
                            </a>
                        ) : null}
                    </small>
                )
            },
        },
        {
            title: 'Last operation index',
            dataIndex: 'current_operation_index',
        },
        {
            title: 'Last query ID',
            dataIndex: 'current_query_id',
            render: function RenderQueryId(queryId: string): JSX.Element {
                return (
                    <div>
                        <small>{queryId}</small>
                    </div>
                )
            },
        },
        {
            title: 'Celery task ID',
            dataIndex: 'celery_task_id',
            render: function RenderCeleryTaskId(celeryTaskId: string): JSX.Element {
                return (
                    <div>
                        <small>{celeryTaskId}</small>
                    </div>
                )
            },
        },
        {
            title: 'Started at',
            dataIndex: 'started_at',
            render: function RenderStartedAt(startedAt: string): JSX.Element {
                return <div>{humanFriendlyDetailedTime(startedAt)}</div>
            },
        },
        {
            title: 'Finished at',
            dataIndex: 'finished_at',
            render: function RenderFinishedAt(finishedAt: string): JSX.Element {
                return <div>{humanFriendlyDetailedTime(finishedAt)}</div>
            },
        },
    ]
    return (
        <div className="async-migrations-scene">
            {user?.is_staff ? (
                <>
                    <PageHeader
                        title="Async Migrations"
                        caption={
                            <>
                                <p>Manage async migrations in your instance.</p>
                                <p>
                                    Read about async migrations on our{' '}
                                    <a href="https://posthog.com/docs/self-host/configure/async-migrations">
                                        dedicated docs page
                                    </a>
                                    .
                                </p>
                            </>
                        }
                    />

                    <Tabs activeKey={activeTab} onChange={(t) => setActiveTab(t as AsyncMigrationsTab)}>
                        <TabPane tab="Management" key={AsyncMigrationsTab.Management} />
                        <TabPane tab="Settings" key={AsyncMigrationsTab.Settings} />
                    </Tabs>

                    {activeTab === AsyncMigrationsTab.Management ? (
                        <>
                            <div className="mb float-right">
                                <Button
                                    icon={asyncMigrationsLoading ? <Spinner size="sm" /> : <RedoOutlined />}
                                    onClick={loadAsyncMigrations}
                                >
                                    Refresh
                                </Button>
                            </div>
                            <Space />
                            <Table
                                pagination={false}
                                loading={asyncMigrationsLoading}
                                columns={columns}
                                dataSource={asyncMigrations}
                            />
                        </>
                    ) : activeTab === AsyncMigrationsTab.Settings ? (
                        <>
                            <br />
                            {asyncMigrationSettings.map((setting) => {
                                return (
                                    <div key={setting.key}>
                                        <SettingUpdateField setting={setting} />
                                    </div>
                                )
                            })}
                        </>
                    ) : null}
                </>
            ) : (
                <PageHeader
                    title="Async Migrations"
                    caption={
                        <>
                            <p>
                                Only users with staff access can manage async migrations. Please contact your instance
                                admin.
                            </p>
                            <p>
                                If you're an admin and don't have access, set <code>is_staff=true</code> for your user
                                on the PostgreSQL <code>posthog_user</code> table.
                            </p>
                        </>
                    }
                />
            )}
        </div>
    )
}
Example #28
Source File: OnboardingSetup.tsx    From posthog-foss with MIT License 4 votes vote down vote up
export function OnboardingSetup(): JSX.Element {
    const {
        stepProjectSetup,
        stepInstallation,
        projectModalShown,
        stepVerification,
        currentSection,
        teamInviteAvailable,
        progressPercentage,
        slackCalled,
    } = useValues(onboardingSetupLogic)
    const { switchToNonDemoProject, setProjectModalShown, completeOnboarding, callSlack } =
        useActions(onboardingSetupLogic)
    const { showInviteModal } = useActions(inviteLogic)

    const { currentTeam, currentTeamLoading } = useValues(teamLogic)
    const { updateCurrentTeam } = useActions(teamLogic)
    const { currentOrganizationLoading } = useValues(organizationLogic)

    const UTM_TAGS = 'utm_medium=in-product&utm_campaign=onboarding-setup-2822'

    return (
        <div className="onboarding-setup">
            {currentSection ? (
                <>
                    <Row gutter={16}>
                        <Col span={18}>
                            <PageHeader
                                title="Setup"
                                caption="Get your PostHog instance up and running with all the bells and whistles"
                            />
                        </Col>
                        <Col span={6} style={{ display: 'flex', alignItems: 'center' }}>
                            <Progress percent={progressPercentage} strokeColor="var(--purple)" strokeWidth={16} />
                        </Col>
                    </Row>

                    <Collapse defaultActiveKey={currentSection} expandIconPosition="right" accordion>
                        <Panel
                            header={
                                <PanelHeader
                                    title="Event Ingestion"
                                    caption="First things first, you need to connect PostHog to your website. You’ll be able to add more sources later."
                                    stepNumber={1}
                                />
                            }
                            key="1"
                        >
                            <div className="step-list">
                                <OnboardingStep
                                    label="Set up project"
                                    icon={<ProjectOutlined />}
                                    title="Step 1"
                                    identifier="set-up-project"
                                    completed={stepProjectSetup}
                                    handleClick={() => setProjectModalShown(true)}
                                />
                                <OnboardingStep
                                    label="Install PostHog"
                                    icon={<CodeOutlined />}
                                    title="Step 2"
                                    identifier="install-posthog"
                                    disabled={!stepProjectSetup}
                                    completed={stepInstallation}
                                    handleClick={() => switchToNonDemoProject('/ingestion')}
                                />
                                <OnboardingStep
                                    label="Verify your events"
                                    icon={<CheckOutlined />}
                                    title="Step 3"
                                    identifier="verify-events"
                                    disabled={!stepProjectSetup || !stepInstallation}
                                    completed={stepVerification}
                                    handleClick={() => switchToNonDemoProject('/ingestion/verify')}
                                />
                            </div>
                        </Panel>
                        <Panel
                            header={
                                <PanelHeader
                                    title="Configuration"
                                    caption="Tune the settings of PostHog to make sure it works best for you and your team."
                                    stepNumber={2}
                                />
                            }
                            key="2"
                            collapsible={currentSection < 2 ? 'disabled' : undefined}
                        >
                            <div className="step-list">
                                <OnboardingStep
                                    title="Enable session recording"
                                    icon={<PlaySquareOutlined />}
                                    identifier="session-recording"
                                    handleClick={() =>
                                        updateCurrentTeam({
                                            session_recording_opt_in: !currentTeam?.session_recording_opt_in,
                                        })
                                    }
                                    caption={
                                        <>
                                            Play user interactions as if you were right there with them.{' '}
                                            <Link
                                                to={`https://posthog.com/docs/features/session-recording?${UTM_TAGS}`}
                                                rel="noopener"
                                                target="_blank"
                                            >
                                                Learn more
                                            </Link>
                                            .
                                        </>
                                    }
                                    customActionElement={
                                        <div style={{ fontWeight: 'bold' }}>
                                            {currentTeam?.session_recording_opt_in ? (
                                                <span style={{ color: 'var(--success)' }}>Enabled</span>
                                            ) : (
                                                <span style={{ color: 'var(--danger)' }}>Disabled</span>
                                            )}
                                            <Switch
                                                checked={currentTeam?.session_recording_opt_in}
                                                loading={currentTeamLoading}
                                                style={{ marginLeft: 6 }}
                                            />
                                        </div>
                                    }
                                    analyticsExtraArgs={{
                                        new_session_recording_enabled: !currentTeam?.session_recording_opt_in,
                                    }}
                                />
                                <OnboardingStep
                                    title="Join us on Slack"
                                    icon={<SlackOutlined />}
                                    identifier="slack"
                                    handleClick={() => {
                                        callSlack()
                                        window.open(`https://posthog.com/slack?s=app&${UTM_TAGS}`, '_blank')
                                    }}
                                    caption="Fastest way to reach the PostHog team and the community."
                                    customActionElement={
                                        <Button type={slackCalled ? 'default' : 'primary'} icon={<SlackOutlined />}>
                                            Join us
                                        </Button>
                                    }
                                />
                                {teamInviteAvailable && (
                                    <OnboardingStep
                                        title="Invite your team members"
                                        icon={<UsergroupAddOutlined />}
                                        identifier="invite-team"
                                        handleClick={showInviteModal}
                                        caption="Spread the knowledge, share insights with everyone in your team."
                                        customActionElement={
                                            <Button type="primary" icon={<PlusOutlined />}>
                                                Invite my team
                                            </Button>
                                        }
                                    />
                                )}
                            </div>
                            <div className="text-center" style={{ marginTop: 32 }}>
                                <Button
                                    type="default"
                                    onClick={completeOnboarding}
                                    loading={currentOrganizationLoading}
                                    data-attr="onboarding-setup-complete"
                                >
                                    Finish setup
                                </Button>
                            </div>
                        </Panel>
                    </Collapse>
                    <CreateProjectModal
                        isVisible={projectModalShown}
                        onClose={() => setProjectModalShown(false)}
                        title="Set up your first project"
                        caption={
                            <div className="mb">
                                <div>
                                    Enter a <b>name</b> for your first project
                                </div>
                                <div className="text-muted">
                                    It's helpful to separate your different apps in multiple projects. Read more about
                                    our recommendations and{' '}
                                    <Link
                                        to={`https://posthog.com/docs/features/organizations?${UTM_TAGS}`}
                                        rel="noopener"
                                        target="_blank"
                                    >
                                        best practices <IconOpenInNew />
                                    </Link>
                                </div>
                            </div>
                        }
                    />
                </>
            ) : (
                <div className="already-completed">
                    <CheckCircleOutlined className="completed-icon" />{' '}
                    <h2 className="">Your organization is set up!</h2>
                    <div className="text-muted">
                        Looks like your organization is good to go. If you still need some help, check out{' '}
                        <Link
                            to={`https://posthog.com/docs?${UTM_TAGS}&utm_message=onboarding-completed`}
                            target="_blank"
                        >
                            our docs <IconOpenInNew />
                        </Link>
                    </div>
                    <div style={{ marginTop: 32 }}>
                        <LinkButton type="primary" to="/" data-attr="onbording-completed-insights">
                            Go to insights <ArrowRightOutlined />
                        </LinkButton>
                    </div>
                </div>
            )}
        </div>
    )
}
Example #29
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>
  );
}