@ant-design/icons#PlayCircleOutlined TypeScript Examples
The following examples show how to use
@ant-design/icons#PlayCircleOutlined.
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: BrickCollectionInstanceExecution.tsx From next-basics with GNU General Public License v3.0 | 6 votes |
export function BrickCollectionInstanceExecution(
props: BrickCollectionInstanceExecutionProps
): React.ReactElement {
const { t } = useTranslation(NS_PRESENTATIONAL_BRICKS);
const buttonText = t(K.COLLECTION_INSTANCE_EXECUTE);
return (
<Button disabled={props.ids.length === 0} onClick={props.onClick}>
<PlayCircleOutlined /> {buttonText}
</Button>
);
}
Example #2
Source File: multiRecordingButton.tsx From posthog-foss with MIT License | 5 votes |
export function MultiRecordingButton({ sessionRecordings, onOpenRecording }: MultiRecordingButtonProps): JSX.Element {
const [areRecordingsShown, setAreRecordingsShown] = useState(false)
const isSingleRecording = sessionRecordings.length === 1
/** A wrapper for the button, that handles differing behavior based on the number of recordings available:
* When there's only one recording, clicking opens the recording.
* When there are more recordings, clicking shows the dropdown.
*/
const ButtonWrapper: (props: { setRef: (ref: HTMLElement | null) => void; children: ReactNode }) => JSX.Element =
useCallback(
({ setRef, children }) => {
return isSingleRecording ? (
<div ref={setRef}>
<Link
onClick={(event) => {
event.stopPropagation()
onOpenRecording(sessionRecordings[0])
}}
>
{children}
</Link>
</div>
) : (
<div
ref={setRef}
onClick={(event) => {
event.stopPropagation()
setAreRecordingsShown((previousValue) => !previousValue)
}}
>
{children}
</div>
)
},
[sessionRecordings, setAreRecordingsShown]
)
return (
<Popup
visible={areRecordingsShown}
placement="bottom-end"
fallbackPlacements={['top-end']}
className="session-recordings-popup"
overlay={sessionRecordings.map((sessionRecording, index) => (
<Link
key={sessionRecording.session_id}
onClick={(event) => {
event.stopPropagation()
setAreRecordingsShown(false)
onOpenRecording(sessionRecording)
}}
>
<div className="session-recordings-popup-row">
<PlayCircleOutlined />
Recording {index + 1}
</div>
</Link>
))}
onClickOutside={() => {
setAreRecordingsShown(false)
}}
>
{({ setRef }) => (
<ButtonWrapper setRef={setRef}>
<Button
className={'session-recordings-button'}
data-attr="session-recordings-button"
icon={<PlayCircleOutlined />}
>
Watch recording
{isSingleRecording ? <ArrowRightOutlined /> : <DownOutlined />}
</Button>
</ButtonWrapper>
)}
</Popup>
)
}
Example #3
Source File: index.tsx From config-generator with MIT License | 5 votes |
public render() {
const { destinationId } = this.state;
const { destinationsListStore, messagesStore } = this.props;
const { destinations } = destinationsListStore;
const destination = destinations.find(
destination => destination.id === destinationId,
);
if (destination) {
return (
<Container>
<Flex flexDirection="row" spaceBetween>
<PageTitle>Destination Details</PageTitle>
<div onClick={() => { messagesStore.setIsAnimating(true) }}>
<Tooltip title={"Please try Rudderstack Control Plane for this feature"}>
<Button disabled >
<PlayCircleOutlined />
Live events
</Button>
</Tooltip>
</div>
</Flex>
<CardsView>
<Spacing>
<DestinationView
destination={destination}
deleteDestination={this.deleteDestination}
/>
</Spacing>
<Spacing>
<SourceView
sources={destination!.sources}
destination={destination}
deleteConnection={this.deleteConnection}
/>
</Spacing>
<Spacing></Spacing>
</CardsView>
</Container>
);
}
return null;
}
Example #4
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 #5
Source File: PluginJobConfiguration.tsx From posthog-foss with MIT License | 4 votes |
export function PluginJobConfiguration({
jobName,
jobSpec,
pluginConfigId,
pluginId,
}: PluginJobConfigurationProps): JSX.Element {
if (jobName === HISTORICAL_EXPORT_JOB_NAME) {
jobSpec.payload = {
dateFrom: { type: 'date' },
dateTo: { type: 'date' },
}
}
const logicProps = { jobName, pluginConfigId, pluginId, jobSpecPayload: jobSpec.payload }
const { setIsJobModalOpen, runJob, playButtonOnClick } = useActions(interfaceJobsLogic(logicProps))
const { runJobAvailable, isJobModalOpen } = useValues(interfaceJobsLogic(logicProps))
const jobHasEmptyPayload = Object.keys(jobSpec.payload || {}).length === 0
const [form] = Form.useForm()
const configureOrRunJobTooltip = runJobAvailable
? jobHasEmptyPayload
? `Run job`
: `Configure and run job`
: `You already ran this job recently.`
return (
<>
<span
style={{
marginLeft: 10,
marginRight: 5,
}}
onClick={() => playButtonOnClick(form, jobHasEmptyPayload)}
>
<Tooltip title={configureOrRunJobTooltip}>
{jobHasEmptyPayload ? (
<PlayCircleOutlined
className={runJobAvailable ? 'plugin-run-job-button' : 'plugin-run-job-button-disabled'}
/>
) : (
<SettingOutlined
className={runJobAvailable ? 'plugin-run-job-button' : 'plugin-run-job-button-disabled'}
/>
)}
</Tooltip>
</span>
<Modal
visible={isJobModalOpen}
onCancel={() => setIsJobModalOpen(false)}
onOk={() => runJob(form)}
okText={'Run job now'}
title={`Configuring job '${jobName}'`}
>
{jobSpec.payload ? (
<Form form={form} layout="vertical">
{Object.entries(jobSpec.payload).map(([key, options]) => (
<span key={key}>
<Form.Item
style={{ marginBottom: 15 }}
name={key}
required={!!options.required}
rules={
options.required
? [
requiredRule,
...(options.type === 'json'
? [{ validator: validateJsonFormItem }]
: []),
]
: []
}
label={key}
>
{options.type === 'string' ? (
<Input />
) : options.type === 'number' ? (
<InputNumber />
) : options.type === 'json' ? (
<MonacoEditor
options={{ codeLens: false }}
className="plugin-job-json-editor"
language="json"
height={200}
/>
) : options.type === 'boolean' ? (
<Radio.Group id="propertyValue" buttonStyle="solid">
<Radio.Button value={true} defaultChecked>
<CheckOutlined /> True
</Radio.Button>
<Radio.Button value={false}>
<CloseOutlined /> False
</Radio.Button>
</Radio.Group>
) : options.type === 'date' ? (
<DatePicker
popupStyle={{ zIndex: 1061 }}
allowClear
placeholder="Today"
className="retention-date-picker"
suffixIcon={null}
use12Hours
showTime
/>
) : null}
</Form.Item>
</span>
))}
</Form>
) : null}
</Modal>
</>
)
}
Example #6
Source File: SessionRecordingsTable.tsx From posthog-foss with MIT License | 4 votes |
export function SessionRecordingsTable({ personUUID, isPersonPage = false }: SessionRecordingsTableProps): JSX.Element {
const sessionRecordingsTableLogicInstance = sessionRecordingsTableLogic({ personUUID })
const {
sessionRecordings,
sessionRecordingsResponseLoading,
sessionRecordingId,
entityFilters,
propertyFilters,
hasNext,
hasPrev,
fromDate,
toDate,
durationFilter,
showFilters,
} = useValues(sessionRecordingsTableLogicInstance)
const {
openSessionPlayer,
closeSessionPlayer,
setEntityFilters,
setPropertyFilters,
loadNext,
loadPrev,
setDateRange,
setDurationFilter,
enableFilter,
} = useActions(sessionRecordingsTableLogicInstance)
const { preflight } = useValues(preflightLogic)
const columns: LemonTableColumns<SessionRecordingType> = [
{
title: 'Start time',
render: function RenderStartTime(_: any, sessionRecording: SessionRecordingType) {
return <TZLabel time={sessionRecording.start_time} formatString="MMMM DD, YYYY h:mm" />
},
},
{
title: 'Duration',
render: function RenderDuration(_: any, sessionRecording: SessionRecordingType) {
return <span>{humanFriendlyDuration(sessionRecording.recording_duration)}</span>
},
},
{
title: 'Person',
key: 'person',
render: function RenderPersonLink(_: any, sessionRecording: SessionRecordingType) {
return <PersonHeader withIcon person={sessionRecording.person} />
},
},
{
render: function RenderPlayButton(_: any, sessionRecording: SessionRecordingType) {
return (
<div className="play-button-container">
<Button
className={sessionRecording.viewed ? 'play-button viewed' : 'play-button'}
data-attr="session-recordings-button"
icon={<PlayCircleOutlined />}
>
Watch recording
</Button>
</div>
)
},
},
]
return (
<div className="session-recordings-table" data-attr="session-recordings-table">
<Row className="filter-row">
<div className="filter-container" style={{ display: showFilters ? undefined : 'none' }}>
<div>
<Typography.Text strong>
{`Filter by events and actions `}
<Tooltip title="Show recordings where all of the events or actions listed below happen.">
<InfoCircleOutlined className="info-icon" />
</Tooltip>
</Typography.Text>
<ActionFilter
fullWidth={true}
filters={entityFilters}
setFilters={(payload) => {
setEntityFilters(payload)
}}
typeKey={isPersonPage ? `person-${personUUID}` : 'session-recordings'}
hideMathSelector={true}
buttonCopy="Add another filter"
horizontalUI
stripeActionRow={false}
propertyFilterWrapperClassName="session-recording-action-property-filter"
customRowPrefix=""
hideRename
showOr
renderRow={(props) => <FilterRow {...props} />}
showNestedArrow={false}
actionsTaxonomicGroupTypes={[
TaxonomicFilterGroupType.Actions,
TaxonomicFilterGroupType.Events,
]}
propertiesTaxonomicGroupTypes={[
TaxonomicFilterGroupType.EventProperties,
TaxonomicFilterGroupType.Elements,
]}
/>
</div>
{!isPersonPage && preflight?.is_clickhouse_enabled && (
<div className="mt-2">
<Typography.Text strong>
{`Filter by persons and cohorts `}
<Tooltip title="Show recordings by persons who match the set criteria">
<InfoCircleOutlined className="info-icon" />
</Tooltip>
</Typography.Text>
<PropertyFilters
popoverPlacement="bottomRight"
pageKey={isPersonPage ? `person-${personUUID}` : 'session-recordings'}
taxonomicGroupTypes={[
TaxonomicFilterGroupType.PersonProperties,
TaxonomicFilterGroupType.Cohorts,
]}
propertyFilters={propertyFilters}
onChange={(properties) => {
setPropertyFilters(properties)
}}
/>
</div>
)}
</div>
<Button
style={{ display: showFilters ? 'none' : undefined }}
onClick={() => {
enableFilter()
if (isPersonPage) {
const entityFilterButtons = document.querySelectorAll('.entity-filter-row button')
if (entityFilterButtons.length > 0) {
;(entityFilterButtons[0] as HTMLElement).click()
}
}
}}
>
<FilterOutlined /> Filter recordings
</Button>
<Row className="time-filter-row">
<Row className="time-filter">
<DateFilter
makeLabel={(key) => (
<>
<CalendarOutlined />
<span> {key}</span>
</>
)}
defaultValue="Last 7 days"
bordered={true}
dateFrom={fromDate ?? undefined}
dateTo={toDate ?? undefined}
onChange={(changedDateFrom, changedDateTo) => {
setDateRange(changedDateFrom, changedDateTo)
}}
dateOptions={{
Custom: { values: [] },
'Last 24 hours': { values: ['-24h'] },
'Last 7 days': { values: ['-7d'] },
'Last 21 days': { values: ['-21d'] },
}}
/>
</Row>
<Row className="time-filter">
<Typography.Text className="filter-label">Duration</Typography.Text>
<DurationFilter
onChange={(newFilter) => {
setDurationFilter(newFilter)
}}
initialFilter={durationFilter}
pageKey={isPersonPage ? `person-${personUUID}` : 'session-recordings'}
/>
</Row>
</Row>
</Row>
<LemonTable
dataSource={sessionRecordings}
columns={columns}
loading={sessionRecordingsResponseLoading}
onRow={(sessionRecording) => ({
onClick: (e) => {
// Lets the link to the person open the person's page and not the session recording
if (!(e.target as HTMLElement).closest('a')) {
openSessionPlayer(sessionRecording.id, RecordingWatchedSource.RecordingsList)
}
},
})}
rowClassName="cursor-pointer"
data-attr="session-recording-table"
/>
{(hasPrev || hasNext) && (
<Row className="pagination-control">
<Button
type="link"
disabled={!hasPrev}
onClick={() => {
loadPrev()
window.scrollTo(0, 0)
}}
>
<LeftOutlined /> Previous
</Button>
<Button
type="link"
disabled={!hasNext}
onClick={() => {
loadNext()
window.scrollTo(0, 0)
}}
>
Next <RightOutlined />
</Button>
</Row>
)}
<div style={{ marginBottom: 64 }} />
{!!sessionRecordingId && <SessionPlayerDrawer isPersonPage={isPersonPage} onClose={closeSessionPlayer} />}
</div>
)
}
Example #7
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>
);
}
Example #8
Source File: DevicePage.tsx From iot-center-v2 with MIT License | 4 votes |
DevicePage: FunctionComponent<
RouteComponentProps<PropsRoute> & Props
> = ({match, location, helpCollapsed, mqttEnabled}) => {
const deviceId = match.params.deviceId ?? VIRTUAL_DEVICE
const [loading, setLoading] = useState(true)
const [message, setMessage] = useState<Message | undefined>()
const [deviceData, setDeviceData] = useState<DeviceData | undefined>()
const [dataStamp, setDataStamp] = useState(0)
const [progress, setProgress] = useState(-1)
const writeAllowed =
deviceId === VIRTUAL_DEVICE ||
new URLSearchParams(location.search).get('write') === 'true'
const isVirtualDevice = deviceId === VIRTUAL_DEVICE
// fetch device configuration and data
useEffect(() => {
const fetchData = async () => {
setLoading(true)
try {
const deviceConfig = await fetchDeviceConfig(deviceId)
setDeviceData(await fetchDeviceData(deviceConfig))
} catch (e) {
console.error(e)
setMessage({
title: 'Cannot load device data',
description: String(e),
type: 'error',
})
} finally {
setLoading(false)
}
}
fetchData()
}, [dataStamp, deviceId])
async function writeData() {
const onProgress: ProgressFn = (percent /*, current, total */) => {
// console.log(
// `writeData ${current}/${total} (${Math.trunc(percent * 100) / 100}%)`
// );
setProgress(percent)
}
try {
if (!deviceData) return
const missingDataTimeStamps = mqttEnabled
? await fetchDeviceMissingDataTimeStamps(deviceData.config)
: undefined
const count = await writeEmulatedData(
deviceData,
onProgress,
missingDataTimeStamps
)
if (count) {
notification.success({
message: (
<>
<b>{count}</b> measurement point{count > 1 ? 's were' : ' was'}{' '}
written to InfluxDB.
</>
),
})
setDataStamp(dataStamp + 1) // reload device data
} else {
notification.info({
message: `No new data were written to InfluxDB, the current measurement is already written.`,
})
}
} catch (e) {
console.error(e)
setMessage({
title: 'Cannot write data',
description: String(e),
type: 'error',
})
} finally {
setProgress(-1)
}
}
const writeButtonDisabled = progress !== -1 || loading
const pageControls = (
<>
{writeAllowed ? (
<Tooltip title="Write Missing Data for the last 7 days" placement="top">
<Button
type="primary"
onClick={writeData}
disabled={writeButtonDisabled}
icon={<IconWriteData />}
/>
</Tooltip>
) : undefined}
<Tooltip title="Reload" placement="topRight">
<Button
disabled={loading}
loading={loading}
onClick={() => setDataStamp(dataStamp + 1)}
icon={<IconRefresh />}
/>
</Tooltip>
<Tooltip title="Go to device realtime dashboard" placement="topRight">
<Button
type={mqttEnabled ? 'default' : 'ghost'}
icon={<PlayCircleOutlined />}
href={`/realtime/${deviceId}`}
></Button>
</Tooltip>
<Tooltip title="Go to device dashboard" placement="topRight">
<Button
icon={<IconDashboard />}
href={`/dashboard/${deviceId}`}
></Button>
</Tooltip>
</>
)
const columnDefinitions: ColumnsType<measurementSummaryRow> = [
{
title: 'Field',
dataIndex: '_field',
},
{
title: 'min',
dataIndex: 'minValue',
render: (val: number) => +val.toFixed(2),
align: 'right',
},
{
title: 'max',
dataIndex: 'maxValue',
render: (val: number) => +val.toFixed(2),
align: 'right',
},
{
title: 'max time',
dataIndex: 'maxTime',
},
{
title: 'entry count',
dataIndex: 'count',
align: 'right',
},
{
title: 'sensor',
dataIndex: 'sensor',
},
]
return (
<PageContent
title={
isVirtualDevice ? (
<>
{'Virtual Device'}
<Tooltip title="This page writes temperature measurements for the last 7 days from an emulated device, the temperature is reported every minute.">
<InfoCircleFilled style={{fontSize: '1em', marginLeft: 5}} />
</Tooltip>
</>
) : (
`Device ${deviceId}`
)
}
message={message}
spin={loading}
titleExtra={pageControls}
>
{deviceId === VIRTUAL_DEVICE ? (
<>
<div style={{visibility: progress >= 0 ? 'visible' : 'hidden'}}>
<Progress
percent={progress >= 0 ? Math.trunc(progress) : 0}
strokeColor={COLOR_LINK}
/>
</div>
</>
) : undefined}
<GridDescription
title="Device Configuration"
column={
helpCollapsed ? {xxl: 3, xl: 2, md: 1, sm: 1} : {xxl: 2, md: 1, sm: 1}
}
descriptions={[
{
label: 'Device ID',
value: deviceData?.config.id,
},
{
label: 'Registration Time',
value: deviceData?.config.createdAt,
},
{
label: 'InfluxDB URL',
value: deviceData?.config.influx_url,
},
{
label: 'InfluxDB Organization',
value: deviceData?.config.influx_org,
},
{
label: 'InfluxDB Bucket',
value: deviceData?.config.influx_bucket,
},
{
label: 'InfluxDB Token',
value: deviceData?.config.influx_token ? '***' : 'N/A',
},
...(mqttEnabled
? [
{
label: 'Mqtt URL',
value: deviceData?.config?.mqtt_url,
},
{
label: 'Mqtt topic',
value: deviceData?.config?.mqtt_topic,
},
]
: []),
{
label: 'Device type',
value: (
<InputConfirm
value={deviceData?.config?.device}
tooltip={'Device type is used for dynamic dashboard filtering'}
onValueChange={async (newValue) => {
try {
await fetchSetDeviceType(deviceId, newValue)
setDataStamp(dataStamp + 1)
} catch (e) {
console.error(e)
setMessage({
title: 'Cannot load device data',
description: String(e),
type: 'error',
})
}
}}
/>
),
},
]}
/>
<Title>Measurements</Title>
<Table
dataSource={deviceData?.measurements}
columns={columnDefinitions}
pagination={false}
rowKey={measurementTableRowKey}
/>
<div style={{height: 20}} />
{isVirtualDevice && mqttEnabled ? (
<RealTimeSettings onBeforeStart={writeData} />
) : undefined}
</PageContent>
)
}
Example #9
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 #10
Source File: FunctionDebuggerSidebar.tsx From next-basics with GNU General Public License v3.0 | 4 votes |
export function FunctionDebuggerSidebar({
functionName,
functionModified,
activeTab,
tests,
onActiveTabSwitch,
onRunAllTests,
onAddTest,
}: FunctionDebuggerSidebarProps): React.ReactElement {
const [currentTab, setCurrentTab] = useState<string>(activeTab ?? "function");
useEffect(() => {
setCurrentTab(activeTab ?? "function");
}, [activeTab]);
const groups: SidebarGroup[] = useMemo(() => {
const refinedTests = Array.isArray(tests) ? tests : [];
return [
{
label: "Function",
value: "function",
items: [
{
label: functionName,
value: "function",
icon: <CodeOutlined />,
modified: functionModified,
},
],
},
{
label: "Debug",
value: "debug",
items: [
{
label: "Debug",
value: "debug",
icon: <BugOutlined />,
},
],
},
{
label: `Tests (${refinedTests.length})`,
value: "tests",
items: refinedTests.map((test, index) => ({
label: test.name ?? `Case ${index + 1}`,
value: `test:${String(index)}`,
modified: test.testModified,
...(test.testMatched
? {
icon: <CheckOutlined />,
className: styles.matched,
}
: test.testMatched === false
? {
icon: <CloseOutlined />,
className: styles.notMatched,
}
: {
icon: <QuestionOutlined />,
}),
})),
},
];
}, [functionModified, functionName, tests]);
const switchActiveTab = useCallback(
(tab: string) => {
if (currentTab !== tab) {
setCurrentTab(tab);
onActiveTabSwitch?.(tab);
}
},
[currentTab, onActiveTabSwitch]
);
return (
<div
className={`${styles.sidebarContainer} ${sharedStyles.customScrollbarContainer}`}
data-override-theme="dark"
>
<ul className={styles.sidebarGroups}>
{groups.map((group) => (
<li key={group.label}>
<div className={styles.sidebarGroupLabel}>
<span className={styles.groupText}>{group.label}</span>
{group.value === "tests" && (
<div className={styles.groupIconContainer}>
{group.items.length > 0 && (
<span
className={styles.groupIcon}
title="Run All Tests"
onClick={onRunAllTests}
>
<PlayCircleOutlined />
</span>
)}
<span
className={styles.groupIcon}
title="Add Test"
onClick={onAddTest}
>
<PlusCircleOutlined />
</span>
</div>
)}
</div>
<ul className={styles.sidebarItems}>
{group.items.map((item) => (
<li
key={item.label}
className={classNames({
[styles.active]: item.value === currentTab,
})}
onClick={() => switchActiveTab(item.value)}
>
<span className={classNames(styles.icon, item.className)}>
{item.icon}
</span>
<span className={styles.text}>{item.label}</span>
{item.modified && <span className={styles.modified}></span>}
</li>
))}
</ul>
</li>
))}
</ul>
</div>
);
}
Example #11
Source File: FunctionDebuggerToolbar.tsx From next-basics with GNU General Public License v3.0 | 4 votes |
export function FunctionDebuggerToolbar({
type,
status,
saveDisabled,
onButtonClick,
}: FunctionDebuggerToolbarProps): React.ReactElement {
const refinedType = type ?? "input";
const isInput = refinedType === "input" || refinedType === "test-input";
const handleRunClick = useCallback(() => {
onButtonClick?.({ action: "run" });
}, [onButtonClick]);
const handleSaveClick = useCallback(() => {
if (!saveDisabled) {
onButtonClick?.({ action: "save" });
}
}, [onButtonClick, saveDisabled]);
const handleDeleteClick = useCallback(() => {
onButtonClick?.({ action: "delete" });
}, [onButtonClick]);
return (
<div
className={classNames(
styles.debuggerToolbar,
status && styles[status],
refinedType === "input" || refinedType === "output"
? styles.debug
: styles.test,
isInput ? styles.input : styles.output
)}
data-override-theme="dark"
>
<div className={styles.header}>
{refinedType === "input"
? "Input"
: refinedType === "test-input"
? "Test Input"
: refinedType === "test-output"
? "Expect Output"
: "Output"}
{isInput && (
<span className={styles.headerSuffix}>
(argument list in JSON format)
</span>
)}
</div>
{isInput ? (
<div className={styles.buttons}>
<Tooltip title="Run">
<div className={styles.debuggerButton} onClick={handleRunClick}>
<PlayCircleOutlined />
</div>
</Tooltip>
<Tooltip
title={refinedType === "input" ? "Add as a test case" : "Update"}
>
<div
className={classNames(styles.debuggerButton, {
[styles.disabled]: saveDisabled,
})}
onClick={handleSaveClick}
>
{refinedType === "input" ? (
<PlusCircleOutlined />
) : (
<SaveOutlined />
)}
</div>
</Tooltip>
{refinedType === "test-input" && (
<Tooltip title="Delete">
<div
className={styles.debuggerButton}
onClick={handleDeleteClick}
>
<DeleteOutlined />
</div>
</Tooltip>
)}
</div>
) : (
refinedType === "test-output" && (
<div className={styles.secondHeader}>
{status === "ok" ? (
<>
<span className={styles.secondHeaderIcon}>
<CheckOutlined />
</span>
<span>Test: passed</span>
</>
) : status === "failed" ? (
<>
<span className={styles.secondHeaderIcon}>
<CloseOutlined />
</span>
<span>Test: failed</span>
</>
) : (
<>
<span className={styles.secondHeaderIcon}>
<QuestionOutlined />
</span>
<span>Test: expired</span>
</>
)}
</div>
)
)}
</div>
);
}
Example #12
Source File: index.tsx From metaplex with Apache License 2.0 | 4 votes |
export function Notifications() {
const {
metadata,
whitelistedCreatorsByCreator,
store,
vaults,
safetyDepositBoxesByVaultAndIndex,
pullAllSiteData,
} = useMeta();
const possiblyBrokenAuctionManagerSetups = useAuctions(
AuctionViewState.Defective,
);
const upcomingAuctions = useAuctions(AuctionViewState.Upcoming);
const connection = useConnection();
const wallet = useWallet();
const notifications: NotificationCard[] = [];
const walletPubkey = wallet.publicKey?.toBase58() || '';
useCollapseWrappedSol({ connection, wallet, notifications });
useSettlementAuctions({ connection, wallet, notifications });
const vaultsNeedUnwinding = useMemo(
() =>
Object.values(vaults).filter(
v =>
v.info.authority === walletPubkey &&
v.info.state !== VaultState.Deactivated &&
v.info.tokenTypeCount > 0,
),
[vaults, walletPubkey],
);
vaultsNeedUnwinding.forEach(v => {
notifications.push({
id: v.pubkey,
title: 'You have items locked in a defective auction!',
description: (
<span>
During an auction creation process that probably had some issues, you
lost an item. Reclaim it now.
</span>
),
action: async () => {
try {
await unwindVault(
connection,
wallet,
v,
safetyDepositBoxesByVaultAndIndex,
);
} catch (e) {
console.error(e);
return false;
}
return true;
},
});
});
notifications.push({
id: 'none',
title: 'Search for other auctions.',
description: (
<span>
Load all auctions (including defectives) by pressing here. Then you can
close them.
</span>
),
action: async () => {
try {
await pullAllSiteData();
} catch (e) {
console.error(e);
return false;
}
return true;
},
});
possiblyBrokenAuctionManagerSetups
.filter(v => v.auctionManager.authority === walletPubkey)
.forEach(v => {
notifications.push({
id: v.auctionManager.pubkey,
title: 'You have items locked in a defective auction!',
description: (
<span>
During an auction creation process that probably had some issues,
you lost an item. Reclaim it now.
</span>
),
action: async () => {
try {
await decommAuctionManagerAndReturnPrizes(
connection,
wallet,
v,
safetyDepositBoxesByVaultAndIndex,
);
} catch (e) {
console.error(e);
return false;
}
return true;
},
});
});
const metaNeedsApproving = useMemo(
() =>
metadata.filter(m => {
return (
m.info.data.creators &&
(whitelistedCreatorsByCreator[m.info.updateAuthority]?.info
?.activated ||
store?.info.public) &&
m.info.data.creators.find(
c => c.address === walletPubkey && !c.verified,
)
);
}),
[metadata, whitelistedCreatorsByCreator, walletPubkey],
);
metaNeedsApproving.forEach(m => {
notifications.push({
id: m.pubkey,
title: 'You have a new artwork to approve!',
description: (
<span>
{whitelistedCreatorsByCreator[m.info.updateAuthority]?.info?.name ||
m.pubkey}{' '}
wants you to approve that you helped create their art{' '}
<Link to={`/art/${m.pubkey}`}>here.</Link>
</span>
),
action: async () => {
try {
await sendSignMetadata(connection, wallet, m.pubkey);
} catch (e) {
console.error(e);
return false;
}
return true;
},
});
});
upcomingAuctions
.filter(v => v.auctionManager.authority === walletPubkey)
.forEach(v => {
notifications.push({
id: v.auctionManager.pubkey,
title: 'You have an auction which is not started yet!',
description: <span>You can activate it now if you wish.</span>,
action: async () => {
try {
await startAuctionManually(connection, wallet, v);
} catch (e) {
console.error(e);
return false;
}
return true;
},
});
});
const content = notifications.length ? (
<div
style={{ width: '300px', color: 'white' }}
className={'notifications-container'}
>
<List
itemLayout="vertical"
size="small"
dataSource={notifications.slice(0, 10)}
renderItem={(item: NotificationCard) => (
<List.Item
extra={
<>
<RunAction
id={item.id}
action={item.action}
icon={<PlayCircleOutlined />}
/>
{item.dismiss && (
<RunAction
id={item.id}
action={item.dismiss}
icon={<PlayCircleOutlined />}
/>
)}
</>
}
>
<List.Item.Meta
title={<span>{item.title}</span>}
description={
<span>
<i>{item.description}</i>
</span>
}
/>
</List.Item>
)}
/>
</div>
) : (
<span>No notifications</span>
);
const justContent = (
<Popover placement="bottomLeft" content={content} trigger="click">
<img src={'/bell.svg'} style={{ cursor: 'pointer' }} />
{!!notifications.length && (
<div className="mobile-notification">{notifications.length - 1}</div>
)}
</Popover>
);
if (notifications.length === 0) return justContent;
else
return (
<Badge
count={notifications.length - 1}
style={{ backgroundColor: 'white', color: 'black' }}
>
{justContent}
</Badge>
);
}
Example #13
Source File: detail.tsx From fe-v5 with Apache License 2.0 | 4 votes |
EventDetailPage: React.FC = () => {
const { busiId, eventId } = useParams<{ busiId: string; eventId: string }>();
const { busiGroups } = useSelector<RootState, CommonStoreState>((state) => state.common);
useEffect(() => {}, [busiGroups]);
const handleNavToWarningList = (id) => {
if (busiGroups.find((item) => item.id === id)) {
history.push(`/alert-rules?id=${id}`);
} else {
message.error('该业务组已删除或无查看权限');
}
};
const history = useHistory();
const [isHistory, setIsHistory] = useState<boolean>(history.location.pathname.includes('alert-his-events'));
const [eventDetail, setEventDetail] = useState<any>();
const [descriptionInfo, setDescriptionInfo] = useState([
{
label: '规则标题',
key: 'rule_name',
render(content, { rule_id }) {
return (
<Button
size='small'
type='link'
className='rule-link-btn'
onClick={() => {
history.push(`/alert-rules/edit/${rule_id}`);
}}
>
{content}
</Button>
);
},
},
{
label: '业务组',
key: 'group_name',
render(content, { group_id }) {
return (
<Button size='small' type='link' className='rule-link-btn' onClick={() => handleNavToWarningList(group_id)}>
{content}
</Button>
);
},
},
{ label: '规则备注', key: 'rule_note' },
{ label: '所属集群', key: 'cluster' },
{
label: '告警级别',
key: 'severity',
render: (severity) => {
return <Tag color={priorityColor[severity - 1]}>S{severity}</Tag>;
},
},
{
label: '事件状态',
key: 'is_recovered',
render(isRecovered) {
return <Tag color={isRecovered ? 'green' : 'red'}>{isRecovered ? 'Recovered' : 'Triggered'}</Tag>;
},
},
{
label: '事件标签',
key: 'tags',
render(tags) {
return tags
? tags.map((tag) => (
<Tag color='blue' key={tag}>
{tag}
</Tag>
))
: '';
},
},
{ label: '对象备注', key: 'target_note' },
{
label: '触发时间',
key: 'trigger_time',
render(time) {
return moment(time * 1000).format('YYYY-MM-DD HH:mm:ss');
},
},
{ label: '触发时值', key: 'trigger_value' },
{
label: '恢复时间',
key: 'recover_time',
render(time) {
return moment((time || 0) * 1000).format('YYYY-MM-DD HH:mm:ss');
},
},
{
label: '告警方式',
key: 'rule_algo',
render(text) {
if (text) {
return '异常检测';
}
return '阈值告警';
},
},
{
label: '使用算法',
key: 'rule_algo',
visible(_text, record) {
return record.rule_algo;
},
render(text) {
return text;
},
},
{
label: 'PromQL',
key: 'prom_ql',
render(promql) {
return (
<Row className='promql-row'>
<Col span={20}>
<PromQLInput value={promql} url='/api/n9e/prometheus' readonly />
</Col>
<Col span={4}>
<Button
className='run-btn'
type='link'
onClick={() => {
window.open(`${location.origin}/metric/explorer?promql=${encodeURIComponent(promql)}`);
}}
>
<PlayCircleOutlined className='run-con' />
</Button>
</Col>
</Row>
);
},
},
{
label: '执行频率',
key: 'prom_eval_interval',
render(content) {
return `${content} 秒`;
},
},
{
label: '持续时长',
key: 'prom_for_duration',
render(content) {
return `${content} 秒`;
},
},
{
label: '通知媒介',
key: 'notify_channels',
render(channels) {
return channels.join(' ');
},
},
{
label: '告警接收组',
key: 'notify_groups_obj',
render(groups) {
return groups ? groups.map((group) => <Tag color='blue'>{group.name}</Tag>) : '';
},
},
{
label: '回调地址',
key: 'callbacks',
render(callbacks) {
return callbacks
? callbacks.map((callback) => (
<Tag>
<Paragraph copyable style={{ margin: 0 }}>
{callback}
</Paragraph>
</Tag>
))
: '';
},
},
{
label: '预案链接',
key: 'runbook_url',
render(url) {
return (
<a href={url} target='_balank'>
{url}
</a>
);
},
},
]);
const [range, setRange] = useState<Range>({
num: 1,
unit: 'hour',
description: '',
});
const [step, setStep] = useState<number | null>(15);
const [series, setSeries] = useState<any[]>([]);
useEffect(() => {
const requestPromise = isHistory ? getHistoryEventsById(busiId, eventId) : getAlertEventsById(busiId, eventId);
requestPromise.then((res) => {
setEventDetail(res.dat);
});
}, [busiId, eventId]);
useEffect(() => {
if (eventDetail && eventDetail.rule_algo) {
let { start, end } = formatPickerDate(range);
let _step = step;
if (!step) _step = Math.max(Math.floor((end - start) / 250), 1);
getBrainData({
rid: eventDetail.rule_id,
uuid: getUUIDByTags(eventDetail.tags),
start,
end,
step: _step,
}).then((res) => {
setSeries(
_.map(
_.filter(res.data, (item) => {
return item.metric.value_type !== 'predict';
}),
(item) => {
const type = item.metric.value_type;
return {
name: `${type}`,
data: item.values,
color: serieColorMap[type],
lineDash: type === 'origin' || type === 'anomaly' ? [] : [4, 4],
};
},
),
);
});
}
}, [JSON.stringify(eventDetail), JSON.stringify(range), step]);
return (
<PageLayout title='告警详情' showBack hideCluster>
<div className='event-detail-container'>
<Spin spinning={!eventDetail}>
<Card
className='desc-container'
title='告警事件详情'
actions={[
<div className='action-btns'>
<Space>
<Button
type='primary'
onClick={() => {
history.push('/alert-mutes/add', {
cluster: eventDetail.cluster,
tags: eventDetail.tags
? eventDetail.tags.map((tag) => {
const [key, value] = tag.split('=');
return {
func: '==',
key,
value,
};
})
: [],
});
}}
>
屏蔽
</Button>
{!isHistory && (
<Button
danger
onClick={() => {
if (eventDetail.group_id) {
deleteAlertEventsModal(eventDetail.group_id, [Number(eventId)], () => {
history.replace('/alert-cur-events');
});
} else {
message.warn('该告警未返回业务组ID');
}
}}
>
删除
</Button>
)}
</Space>
</div>,
]}
>
{eventDetail && (
<div>
{eventDetail.rule_algo && (
<div>
<Space>
<DateRangePicker value={range} onChange={setRange} />
<Resolution value={step} onChange={(v) => setStep(v)} initialValue={step} />
</Space>
<Graph series={series} />
</div>
)}
{descriptionInfo
.filter((item) => {
if (typeof item.visible === 'function') {
return item.visible(eventDetail[item.key], eventDetail);
}
return eventDetail.is_recovered ? true : item.key !== 'recover_time';
})
.map(({ label, key, render }, i) => {
return (
<div className='desc-row' key={key + i}>
<div className='desc-label'>{label}:</div>
<div className='desc-content'>{render ? render(eventDetail[key], eventDetail) : eventDetail[key]}</div>
</div>
);
})}
</div>
)}
</Card>
</Spin>
</div>
</PageLayout>
);
}
Example #14
Source File: App.tsx From pcap2socks-gui with MIT License | 4 votes |
render() {
return (
<Layout className="layout">
<Content className="content-wrapper">
<div className="content">
{(() => {
switch (this.state.stage) {
case STAGE_WELCOME:
return this.renderWelcome();
case STAGE_INTERFACE:
return this.renderInterface();
case STAGE_DEVICE:
return this.renderDevice();
case STAGE_PROXY:
return this.renderProxy();
case STAGE_RUNNING:
return this.renderRunning();
default:
return;
}
})()}
</div>
<div className="footer">
{(() => {
if (this.state.stage > STAGE_WELCOME && this.state.stage <= STAGE_PROXY) {
return (
<Button
className="button"
disabled={this.state.loading > 0}
icon={<LeftOutlined />}
onClick={() => this.setState({ stage: this.state.stage - 1 })}
>
上一步
</Button>
);
}
})()}
{(() => {
if (this.state.stage === STAGE_INTERFACE) {
return (
<Button
className="button"
disabled={this.state.loading > 0 && this.state.loading !== 1}
icon={<ReloadOutlined />}
onClick={this.updateInterfaces}
>
刷新网卡列表
</Button>
);
}
})()}
{(() => {
if (this.state.stage === STAGE_PROXY) {
return (
<Button
className="button"
disabled={this.state.loading > 0}
icon={<FolderOpenOutlined />}
onClick={() => {
const node = document.getElementById("open");
if (node) {
node.click();
}
}}
>
导入代理配置
<input id="open" type="file" onChange={this.import} style={{ display: "none" }} />
</Button>
);
}
})()}
{(() => {
if (this.state.stage === STAGE_PROXY) {
return (
<Button className="button" icon={<ExportOutlined />} onClick={this.export}>
导出代理配置
</Button>
);
}
})()}
{(() => {
if (this.state.stage === STAGE_PROXY) {
return (
<Button
className="button"
disabled={this.state.loading > 0 && this.state.loading !== 2}
loading={this.state.loading === 2}
icon={<ExperimentOutlined />}
onClick={this.test}
>
测试代理服务器
</Button>
);
}
})()}
{(() => {
if (this.state.stage === STAGE_WELCOME && this.state.ready) {
return (
<Tooltip title={this.state.destination}>
<Button
className="button"
type="primary"
disabled={this.state.loading > 0 && this.state.loading !== 3}
loading={this.state.loading === 3}
icon={<PlayCircleOutlined />}
onClick={this.run}
>
以上次的配置运行
</Button>
</Tooltip>
);
}
})()}
{(() => {
if (this.state.stage >= STAGE_WELCOME && this.state.stage < STAGE_PROXY) {
return (
<Button
className="button"
disabled={this.state.loading > 0}
icon={<RightOutlined />}
type="primary"
onClick={() => this.setState({ stage: this.state.stage + 1 })}
>
下一步
</Button>
);
}
})()}
{(() => {
if (this.state.stage === STAGE_PROXY) {
return (
<Button
className="button"
type="primary"
disabled={this.state.loading > 0 && this.state.loading !== 3}
loading={this.state.loading === 3}
icon={<PoweroffOutlined />}
onClick={this.run}
>
运行
</Button>
);
}
})()}
{(() => {
if (this.state.stage === STAGE_RUNNING) {
return (
<Button className="button" icon={<GlobalOutlined />} onClick={this.notifyNetwork}>
显示网络设置
</Button>
);
}
})()}
{(() => {
if (this.state.stage === STAGE_RUNNING) {
return (
<Button
className="button"
type="primary"
danger
disabled={this.state.loading > 0 && this.state.loading !== 4}
loading={this.state.loading === 4}
icon={<PoweroffOutlined />}
onClick={this.stopConfirm}
>
停止
</Button>
);
}
})()}
</div>
</Content>
</Layout>
);
}