@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 |
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 |
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 |
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 |
/**
* 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 |
/**
* 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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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>
);
}