@ant-design/icons#InfoCircleOutlined TypeScript Examples
The following examples show how to use
@ant-design/icons#InfoCircleOutlined.
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: 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 #2
Source File: StickerWidget.tsx From leek with Apache License 2.0 | 6 votes |
export default function ({ icon, number, text, tooltip }) {
return (
<StickerWidgetWrapper className="leekStickerWidget">
<div className="leekIconWrapper">{icon}</div>
<div className="leekContentWrapper">
<Statistic title={text} value={number} />
</div>
<div style={{ fontSize: "18px", padding: "7px" }}>
<Tooltip title={tooltip}>
<InfoCircleOutlined />
</Tooltip>
</div>
</StickerWidgetWrapper>
);
}
Example #3
Source File: info.tsx From metaplex with Apache License 2.0 | 6 votes |
Info = (props: {
text: React.ReactElement;
style?: React.CSSProperties;
}) => {
return (
<Popover
trigger="hover"
content={<div style={{ width: 300 }}>{props.text}</div>}
>
<Button type="text" shape="circle">
<InfoCircleOutlined style={props.style} />
</Button>
</Popover>
);
}
Example #4
Source File: index.tsx From fe-v5 with Apache License 2.0 | 6 votes |
export default function BlankBusinessPlaceholder(props: Props) {
const { t } = useTranslation();
const { text } = props;
return (
<div className='blank-busi-holder'>
<p style={{ textAlign: 'left', fontWeight: 'bold' }}>
<InfoCircleOutlined style={{ color: '#1473ff' }} /> {t('提示信息')}
</p>
<p>
{text}需要归属某个业务组,请先
<Link to='/busi-groups'>创建业务组</Link>
</p>
</div>
);
}
Example #5
Source File: common.tsx From posthog-foss with MIT License | 6 votes |
export function GlobalFiltersTitle({
unit = 'series',
title = 'Filters',
}: {
unit?: string
title?: string
}): JSX.Element {
return (
<h4 className="secondary">
{title}{' '}
<Tooltip
title={
<>
These filters will apply to <b>all</b> the {unit} in this graph.
</>
}
>
<InfoCircleOutlined className="info-indicator" />
</Tooltip>
</h4>
)
}
Example #6
Source File: index.tsx From imove with MIT License | 6 votes |
hijackMap: { [key: string]: any } = {
log: {
bgColor: '#272823',
textColor: '#ffffff',
borderColor: 'rgba(128, 128, 128, 0.35)',
icon: <div className={styles.logIcon} />,
originMethod: console.log,
},
info: {
bgColor: '#272823',
textColor: '#ffffff',
borderColor: 'rgba(128, 128, 128, 0.35)',
icon: <InfoCircleOutlined className={styles.logIcon} />,
originMethod: console.info,
},
warn: {
bgColor: 'rgb(51, 42, 0)',
textColor: 'rgb(245, 211, 150)',
borderColor: 'rgb(102, 85, 0)',
icon: <WarningOutlined className={styles.logIcon} />,
originMethod: console.warn,
},
debug: {
bgColor: '#272823',
textColor: 'rgb(77, 136, 255)',
borderColor: 'rgba(128, 128, 128, 0.35)',
icon: <BugOutlined className={styles.logIcon} />,
originMethod: console.debug,
},
error: {
bgColor: 'rgb(40, 0, 0)',
textColor: 'rgb(254, 127, 127)',
borderColor: 'rgb(91, 0, 0)',
icon: <CloseCircleOutlined className={styles.logIcon} />,
originMethod: console.error,
},
}
Example #7
Source File: PluginCard.tsx From posthog-foss with MIT License | 6 votes |
export function PluginAboutButton({ url, disabled = false }: { url: string; disabled?: boolean }): JSX.Element {
return (
<Space>
<Tooltip title="About">
<LinkButton to={url} target="_blank" rel="noopener noreferrer" disabled={disabled}>
<InfoCircleOutlined />
</LinkButton>
</Tooltip>
</Space>
)
}
Example #8
Source File: index.tsx From RareCamp with Apache License 2.0 | 6 votes |
export default function PageHeading({
title,
description,
renderEdit,
}: {
title?: string
description?: string
renderEdit?: any
}) {
return (
<Space>
<PageTitle title={title} />
{description ? (
<Tooltip placement="bottom" title={description}>
<InfoCircleOutlined />
</Tooltip>
) : null}
{renderEdit ? renderEdit() : null}
</Space>
)
}
Example #9
Source File: FunnelBarGraph.tsx From posthog-foss with MIT License | 6 votes |
function DuplicateStepIndicator(): JSX.Element {
return (
<span style={{ marginLeft: 4 }}>
<Tooltip
title={
<>
<b>Sequential & Repeated Events</b>
<p>
When an event is repeated across funnel steps, it is interpreted as a sequence. For example,
a three-step funnel consisting of pageview events is interpretted as first pageview,
followed by second pageview, followed by a third pageview.
</p>
</>
}
>
<InfoCircleOutlined className="info-indicator" />
</Tooltip>
</span>
)
}
Example #10
Source File: TableComponents.tsx From datart with Apache License 2.0 | 6 votes |
TableColumnTitle = props => {
const { desc, title, uid } = props;
return (
<TableColumnTitleStyle key={uid}>
<span className="titleStyle" key={uid + 'title'}>
{title}
</span>
{desc && (
<Tooltip placement="top" key={uid + 'desc'} title={desc}>
<InfoCircleOutlined />
</Tooltip>
)}
</TableColumnTitleStyle>
);
}
Example #11
Source File: ToolboxPane.tsx From next-basics with GNU General Public License v3.0 | 6 votes |
export function ToolboxPane({
title,
tooltips,
children,
}: React.PropsWithChildren<ToolboxPaneProps>): React.ReactElement {
const { t } = useTranslation(NS_NEXT_BUILDER);
const getPopupContainer = React.useCallback(
(triggerNode: HTMLElement) => triggerNode.parentElement,
[]
);
return (
<div className={styles.toolboxPane}>
<div className={styles.toolboxPaneHeading}>
<div className={styles.toolboxPaneTitle}>{title}</div>
{tooltips && (
<div className={styles.toolboxPaneTooltips}>
<Popover
content={tooltips}
title={t(K.TIPS)}
getPopupContainer={getPopupContainer}
overlayStyle={{ maxWidth: 320 }}
>
<InfoCircleOutlined />
</Popover>
</div>
)}
</div>
<div className={styles.toolboxPaneBody}>{children}</div>
</div>
);
}
Example #12
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 #13
Source File: InfoMessage.tsx From posthog-foss with MIT License | 6 votes |
/** An informative message. */
export function InfoMessage({
children,
style,
}: {
children: string | JSX.Element
style?: React.CSSProperties
}): JSX.Element {
return (
<div className="info-message" style={style}>
<InfoCircleOutlined />
<div>{children}</div>
</div>
)
}
Example #14
Source File: Tile.tsx From ant-extensions with MIT License | 5 votes |
Tile: React.FC<ITileConfig> = React.memo((item) => {
const { isEditing, editWidget, renderWidget, findWidget } = useContext(Context);
const style = useMemo(
() => ({
color: item.color || "inherit"
}),
[item.color]
);
const [expanded, setExpanded] = useState(false);
const widget = useMemo(() => findWidget(item.widgetId), [findWidget, item.widgetId]);
return (
<Item item={item} expanded={!isEditing && expanded}>
<div className="ant-ext-pm__tileHead">
<span style={style}>{item.iconCls && <i className={item.iconCls} />}</span>
<label style={style}>{item.title}</label>
<div>
{item.info && (
<Tooltip
overlay={<pre dangerouslySetInnerHTML={{ __html: item.info }} />}
overlayClassName="ant-ext-pm__tileInfo"
>
<button>
<InfoCircleOutlined />
</button>
</Tooltip>
)}
{!isEditing && item.expandable && (
<button className="ant-ext-pm__tileExpander" onClick={() => setExpanded(!expanded)}>
{expanded ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
</button>
)}
{isEditing && (
<button onClick={() => editWidget(item.widgetId)}>
<EditOutlined />
</button>
)}
</div>
</div>
<div className="ant-ext-pm__tileBody">
{!isEditing && renderWidget(item.widgetId)}
{isEditing && widget && (
<div style={{ placeSelf: "center", textAlign: "center" }}>
{widget.icon}
<div>{widget.title}</div>
</div>
)}
</div>
</Item>
);
})
Example #15
Source File: BooleanArguments.tsx From yugong with MIT License | 5 votes |
BooleanArguments: React.FC<Props> = ({
typeArguments,
flexible,
onChange,
}) => {
const [argumentsState, setArgumentsState] = useState<ArgumentsItem>();
useEffect(() => {
setArgumentsState(typeArguments);
}, [typeArguments]);
const onChangeValue = useCallback(
(key: string) => (e: any) => {
const result: anyObj = { ...argumentsState };
result.data[key] = e.target.value;
if (onChange instanceof Function) {
onChange(result as ArgumentsItem);
}
setArgumentsState(result as ArgumentsItem);
},
[argumentsState, onChange]
);
const onChangeCondition = useCallback((e) => {
const result: anyObj = { ...argumentsState };
result.data.method = e
if (onChange instanceof Function) {
onChange(result as ArgumentsItem);
}
setArgumentsState(result as ArgumentsItem);
}, [argumentsState, onChange]);
const data: any = argumentsState?.data || {
comparableAverageA: null,
comparableAverageB: null,
method: "===",
};
return (
<>
<Row gutter={4}>
<Col span={8}>
<Input
onChange={onChangeValue("comparableAverageA")}
placeholder="条件A"
type="text"
value={data.comparableAverageA}
/>
</Col>
<Col span={6}>
<Select className={s.selected} value={data.method} onChange={onChangeCondition}>
{methodOptions.map((item) => (
<Select.Option key={item.value} value={item.value}>{item.name}</Select.Option>
))}
</Select>
</Col>
<Col span={8} className={s.btn}>
<Input
onChange={onChangeValue("comparableAverageB")}
placeholder="条件B"
type="text"
value={data.comparableAverageB}
/>
</Col>
<Col span={2} style={{lineHeight: '30px'}}>
<Tooltip
placement="topRight"
title={<span>{`${argumentsState && getBooleanData(argumentsState?.data) ? '当前状态:开启' : '当前状态:关闭'}`}<br />(条件成立时开启)</span>}
>
<InfoCircleOutlined />
</Tooltip>
</Col>
</Row>
</>
);
}
Example #16
Source File: index.tsx From posthog-foss with MIT License | 5 votes |
columns = [
{
title: 'Active',
render: function renderActive(license: any) {
return isLicenseExpired(license) ? 'expired' : 'active'
},
},
{
title: 'Valid until',
render: function renderActive(license: any) {
return humanFriendlyDetailedTime(license.valid_until)
},
},
{
title: 'Plan',
dataIndex: 'plan',
},
{
title: function Render() {
return (
<Tooltip
placement="right"
title="Maximum number of team members that you can have across all organizations with your current license."
>
Max # of team members
<InfoCircleOutlined className="info-indicator" />
</Tooltip>
)
},
render: function renderMaxUsers(license: any) {
return license.max_users === null ? 'Unlimited' : license.max_users
},
},
{
title: 'Key',
render: function renderActive(license: any) {
return <CodeSnippet>{license.key}</CodeSnippet>
},
},
{
title: 'License added on',
render: function renderActive(license: any) {
return humanFriendlyDetailedTime(license.created_at)
},
},
]
Example #17
Source File: Tabs.tsx From foodie with MIT License | 5 votes |
Tabs: React.FC<IProps> = ({ username, isOwnProfile, followersCount, followingCount }) => {
const { pathname } = useLocation();
const [activeNav, setActiveNav] = useState('');
useEffect(() => {
const splitPath = pathname.split('/');
const currentNav = splitPath[splitPath.length - 1];
setActiveNav(currentNav);
}, [pathname]);
return (
<ul className="flex items-center justify-between tablet:justify-evenly flex-wrap laptop:justify-start space-x-1 laptop:space-x-4 px-4 bg-indigo-100 dark:bg-indigo-1000 laptop:dark:bg-transparent laptop:bg-transparent laptop:p-0">
<li>
<Link
to={`/user/${username}/`}
className={`${linkStyleName} ${(activeNav === username || activeNav === '') && 'border-indigo-700 dark:border-indigo-400 border-b-4 text-gray-800 dark:text-white '}`}
>
<span className="hidden laptop:inline-block">Posts</span>
<FormOutlined className="laptop:hidden text-2xl" />
</Link>
</li>
<li>
<Link
to={`/user/${username}/info`}
className={`${linkStyleName} ${activeNav === 'info' && 'border-indigo-700 dark:border-indigo-400 border-b-4'}`}
>
<span className="hidden laptop:inline-block">Info</span>
<InfoCircleOutlined className="laptop:hidden text-2xl" />
</Link>
</li>
<li>
<Link
to={`/user/${username}/followers`}
className={`${linkStyleName} ${activeNav === 'followers' && 'border-indigo-700 dark:border-indigo-400 border-b-4'}`}
>
<span className="laptop:text-lg text-indigo-700 dark:text-indigo-400">{followersCount}</span>
<span className="hidden laptop:inline-block">{followersCount > 1 ? 'Followers' : 'Follower'}</span>
<TeamOutlined className="laptop:hidden text-2xl" />
</Link>
</li>
<li>
<Link
to={`/user/${username}/following`}
className={`${linkStyleName} ${activeNav === 'following' && 'border-indigo-700 dark:border-indigo-400 border-b-4'}`}
>
<span className="laptop:text-lg text-indigo-700 dark:text-indigo-400">{followingCount}</span>
<span className="hidden laptop:inline-block">Following</span>
<UserAddOutlined className="laptop:hidden text-2xl" />
</Link>
</li>
{isOwnProfile && (
<li>
<Link
to={`/user/${username}/bookmarks`}
className={`${linkStyleName} ${activeNav === 'bookmarks' && 'border-indigo-700 dark:border-indigo-400 border-b-4'}`}
>
<span className="hidden laptop:inline-block">Bookmarks</span>
<StarOutlined className="laptop:hidden text-2xl" />
</Link>
</li>
)}
</ul>
);
}
Example #18
Source File: PrintButton.tsx From next-basics with GNU General Public License v3.0 | 5 votes |
export function PrintButton(props: PrintButtonProps): React.ReactElement {
const [visible, setVisible] = useState(false);
const content = (
<span>
查看{" "}
<a onClick={preRemind}>
帮助{" "}
<InfoCircleOutlined
style={{ transform: "translateY(1px)" }}
></InfoCircleOutlined>
</a>
</span>
);
const handleVisible = (isVisible: boolean) => {
setVisible(isVisible);
};
function preRemind() {
const padding = 32;
const pngWidth = 800;
Modal.info({
className: styles.printModalBody,
maskClosable: true,
title: "打印操作指引",
width: pngWidth + padding * 2,
okText: "关闭",
content: (
<div style={{ overflowY: "scroll", width: "100%", height: "500px" }}>
<img src={printHelperUrl} alt="打印操作指导图片" />
</div>
),
});
}
function invokePrint() {
const originTitle = window.parent.document.title;
// in iframe, maybe
window.parent.document.title =
props.prefixTitle +
"-" +
new Date().toISOString().substr(0, 10).replace(/-/g, "");
window.print();
window.parent.document.title = originTitle;
}
return (
<div>
<Popover
title={null}
content={content}
visible={visible}
onVisibleChange={handleVisible}
overlayClassName="print-hide"
placement="left"
>
<Button
className="print-hide"
icon={<DownloadOutlined />}
style={{
backgroundColor: props.backgroundColor,
color: props.color,
border: props.border,
width: props.size || 24,
height: props.size || 24,
}}
onClick={invokePrint}
></Button>
</Popover>
</div>
);
}
Example #19
Source File: InsightDisplayConfig.tsx From posthog-foss with MIT License | 5 votes |
export function InsightDisplayConfig({ filters, activeView, disableTable }: InsightDisplayConfigProps): JSX.Element {
const showFunnelBarOptions = activeView === InsightType.FUNNELS
const showPathOptions = activeView === InsightType.PATHS
const dateFilterDisabled = showFunnelBarOptions && isFunnelEmpty(filters)
return (
<div className="display-config-inner">
<div className="display-config-inner-row">
{showDateFilter[activeView] && !disableTable && (
<span className="filter">
<span className="head-title-item">Date range</span>
<InsightDateFilter
defaultValue="Last 7 days"
disabled={dateFilterDisabled}
bordered
makeLabel={(key) => (
<>
<CalendarOutlined /> {key}
{key == 'All time' && (
<Tooltip title={`Only events dated after 2015 will be shown`}>
<InfoCircleOutlined className="info-indicator" />
</Tooltip>
)}
</>
)}
/>
</span>
)}
{showIntervalFilter(activeView, filters) && (
<span className="filter">
<span className="head-title-item">
<span className="hide-lte-md">grouped </span>by
</span>
<IntervalFilter view={activeView} />
</span>
)}
{activeView === InsightType.RETENTION && (
<>
<RetentionDatePicker />
<RetentionReferencePicker />
</>
)}
{showPathOptions && (
<span className="filter">
<PathStepPicker />
</span>
)}
{showComparePrevious[activeView] && (
<span className="filter">
<CompareFilter />
</span>
)}
</div>
<div className="display-config-inner-row">
{showChartFilter(activeView) && (
<span className="filter">
<span className="head-title-item">Chart type</span>
<ChartFilter filters={filters} disabled={filters.insight === InsightType.LIFECYCLE} />
</span>
)}
{showFunnelBarOptions && filters.funnel_viz_type === FunnelVizType.Steps && (
<>
<span className="filter">
<FunnelDisplayLayoutPicker />
</span>
</>
)}
{showFunnelBarOptions && filters.funnel_viz_type === FunnelVizType.TimeToConvert && (
<span className="filter">
<FunnelBinsPicker />
</span>
)}
</div>
</div>
)
}
Example #20
Source File: index.tsx From fe-v5 with Apache License 2.0 | 5 votes |
export default function index(props: IProps) {
const { preNamePrefix = [], namePrefix = ['options', 'standardOptions'] } = props;
return (
<Panel header='高级设置'>
<>
<Form.Item
label={
<div>
单位{' '}
<Tooltip
overlayInnerStyle={{
width: 500,
}}
getTooltipContainer={() => document.body}
title={
<div>
<div>默认会做 SI Prefixes 处理,如不想默认的处理可选择 none 关闭</div>
<div>Data(SI): 基数为 1000, 单位为 B、kB、MB、GB、TB、PB、EB、ZB、YB</div>
<div>Data(IEC): 基数为 1024, 单位为 B、KiB、MiB、GiB、TiB、PiB、EiB、ZiB、YiB</div>
<div>bits: b</div>
<div>bytes: B</div>
</div>
}
>
<InfoCircleOutlined />
</Tooltip>
</div>
}
name={[...namePrefix, 'util']}
>
<Select suffixIcon={<CaretDownOutlined />} placeholder='auto' allowClear>
<Option value='none'>none</Option>
<OptGroup label='Data(SI)'>
<Option value='bitsSI'>bits(SI)</Option>
<Option value='bytesSI'>bytes(SI)</Option>
</OptGroup>
<OptGroup label='Data(IEC)'>
<Option value='bitsIEC'>bits(IEC)</Option>
<Option value='bytesIEC'>bytes(IEC)</Option>
</OptGroup>
<OptGroup label='百分比'>
<Option value='percent'>百分比(0-100)</Option>
<Option value='percentUnit'>百分比(0.0-1.0)</Option>
</OptGroup>
<OptGroup label='时间'>
<Option value='seconds'>seconds</Option>
<Option value='milliseconds'>milliseconds</Option>
<Option value='humantimeSeconds'>humanize(seconds)</Option>
<Option value='humantimeMilliseconds'>humanize(milliseconds)</Option>
</OptGroup>
</Select>
</Form.Item>
<Row gutter={10}>
<Col span={8}>
<Form.Item label='最小值' name={[...namePrefix, 'min']}>
<InputNumber placeholder='auto' style={{ width: '100%' }} />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label='最大值' name={[...namePrefix, 'max']}>
<InputNumber placeholder='auto' style={{ width: '100%' }} />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label='小数点' name={[...namePrefix, 'decimals']}>
<InputNumber placeholder='auto' style={{ width: '100%' }} />
</Form.Item>
</Col>
</Row>
</>
</Panel>
);
}
Example #21
Source File: FunnelCanvasLabel.tsx From posthog-foss with MIT License | 5 votes |
export function FunnelCanvasLabel(): JSX.Element | null {
const { insightProps, filters, activeView } = useValues(insightLogic)
const { conversionMetrics, clickhouseFeaturesEnabled, aggregationTargetLabel } = useValues(
funnelLogic(insightProps)
)
const { setChartFilter } = useActions(chartFilterLogic(insightProps))
if (activeView !== InsightType.FUNNELS) {
return null
}
const labels = [
...(filters.funnel_viz_type === FunnelVizType.Steps
? [
<>
<span className="text-muted-alt">
<Tooltip
title={`Overall conversion rate for all ${aggregationTargetLabel.plural} on the entire funnel.`}
>
<InfoCircleOutlined className="info-indicator left" />
</Tooltip>
Total conversion rate
</span>
<span className="text-muted-alt mr-025">:</span>
<span className="l4">{formatDisplayPercentage(conversionMetrics.totalRate)}%</span>
</>,
]
: []),
...(filters.funnel_viz_type !== FunnelVizType.Trends
? [
<>
<span className="text-muted-alt">
<Tooltip
title={`Average (arithmetic mean) of the total time each ${aggregationTargetLabel.singular} spent in the entire funnel.`}
>
<InfoCircleOutlined className="info-indicator left" />
</Tooltip>
Average time to convert{' '}
</span>
{filters.funnel_viz_type === FunnelVizType.TimeToConvert && <FunnelStepsPicker />}
<span className="text-muted-alt mr-025">:</span>
<Button
type="link"
onClick={() => setChartFilter(FunnelVizType.TimeToConvert)}
disabled={
!clickhouseFeaturesEnabled || filters.funnel_viz_type === FunnelVizType.TimeToConvert
}
>
<span className="l4">{humanFriendlyDuration(conversionMetrics.averageTime)}</span>
</Button>
</>,
]
: []),
]
return (
<Row className="funnel-canvas-label" align="middle">
{labels.map((label, i) => (
<React.Fragment key={i}>
{i > 0 && <span style={{ margin: '2px 8px', borderLeft: '1px solid var(--border)', height: 14 }} />}
{label}
</React.Fragment>
))}
</Row>
)
}
Example #22
Source File: Tabs.tsx From datart with Apache License 2.0 | 5 votes |
function CloseIcon({ touched, stage, error }: CloseIconProps) {
const [hovering, setHovering] = useState(false);
const onEnter = useCallback(() => {
setHovering(true);
}, []);
const onLeave = useCallback(() => {
setHovering(false);
}, []);
let icon;
switch (stage) {
case ViewViewModelStages.Loading:
case ViewViewModelStages.Running:
case ViewViewModelStages.Saving:
icon = <LoadingOutlined />;
break;
default:
if (!hovering) {
if (error) {
icon = <InfoCircleOutlined css={errorColor} />;
} else if (touched) {
icon = <Editing />;
} else {
icon = <CloseOutlined />;
}
} else {
icon = <CloseOutlined />;
}
break;
}
return (
<CloseIconWrapper onMouseEnter={onEnter} onMouseLeave={onLeave}>
{icon}
</CloseIconWrapper>
);
}
Example #23
Source File: index.tsx From leek with Apache License 2.0 | 4 votes |
IndexPage = () => {
const { currentApp, currentEnv } = useApplication();
const [stats, setStats] = useState<any>({});
const stats_widgets = StatsWidgets(stats);
// Metadata
const metricsService = new MetricsService();
const [seenWorkers, setSeenWorkers] = useState<
MetricsContextData["seenWorkers"]
>([]);
const [seenTasks, setSeenTasks] = useState<MetricsContextData["seenTasks"]>(
[]
);
const [processedEvents, setProcessedEvents] =
useState<MetricsContextData["processedEvents"]>(0);
const [processedTasks, setProcessedTasks] =
useState<MetricsContextData["processedTasks"]>(0);
const [seenStates, setSeenStates] = useState<
MetricsContextData["seenStates"]
>([]);
const [seenTaskStates, setSeenTaskStates] = useState<
MetricsContextData["seenStates"]
>([]);
const [seenRoutingKeys, setSeenRoutingKeys] = useState<
MetricsContextData["seenRoutingKeys"]
>([]);
const [seenQueues, setSeenQueues] = useState<
MetricsContextData["seenQueues"]
>([]);
const [searchDriftLoading, setSearchDriftLoading] = useState<boolean>(true);
const [searchDrift, setSearchDrift] = useState<any>(null);
const [timeFilters, setTimeFilters] = useState<any>({
timestamp_type: "timestamp",
interval_type: "past",
offset: 900000,
});
function getSearchDrift() {
if (!currentApp || !currentEnv) return;
setSearchDriftLoading(true);
metricsService
.getSearchDrift(currentApp, currentEnv)
.then(handleAPIResponse)
.then((result: any) => {
setSearchDrift(result);
}, handleAPIError)
.catch(handleAPIError)
.finally(() => setSearchDriftLoading(false));
}
function getMetrics() {
if (!currentApp) return;
metricsService
.getBasicMetrics(currentApp, currentEnv, timeFilters)
.then(handleAPIResponse)
.then((result: any) => {
setProcessedEvents(result.aggregations.processed_events.value);
const processed = result.aggregations.seen_states.buckets.reduce(
(result, item) => {
if (!workerStates.includes(item.key)) {
return result + item.doc_count;
}
return result;
},
0
);
setProcessedTasks(processed);
setSeenWorkers(result.aggregations.seen_workers.buckets);
setSeenTasks(result.aggregations.seen_tasks.buckets);
setSeenStates(result.aggregations.seen_states.buckets);
setSeenTaskStates(
tasksStatesDefaults
.map(
(obj) =>
result.aggregations.seen_states.buckets.find(
(o) => o.key === obj.key
) || obj
)
.filter((item) => !workerStates.includes(item.key))
);
setSeenRoutingKeys(result.aggregations.seen_routing_keys.buckets);
setSeenQueues(result.aggregations.seen_queues.buckets);
}, handleAPIError)
.catch(handleAPIError);
}
useEffect(() => {
let adapted = {
SEEN_TASKS: seenTasks.length,
SEEN_WORKERS: seenWorkers.length,
PROCESSED_EVENTS: processedEvents,
PROCESSED_TASKS: processedTasks,
TASKS: 0,
EVENTS: 0,
// Tasks
QUEUED: 0,
RECEIVED: 0,
STARTED: 0,
SUCCEEDED: 0,
FAILED: 0,
REJECTED: 0,
REVOKED: 0,
IGNORED: 0,
RETRY: 0,
RECOVERED: 0,
CRITICAL: 0,
// Worker
ONLINE: 0,
HEARTBEAT: 0,
OFFLINE: 0,
};
seenStates.map((task, _) => (adapted[task.key] = task.doc_count));
setStats(adapted);
}, [seenTasks, seenWorkers, seenStates]);
useEffect(() => {
getMetrics();
getSearchDrift();
return () => {
clearInterval(metricsInterval);
};
}, []);
useEffect(() => {
// Stop refreshing metadata
if (metricsInterval) clearInterval(metricsInterval);
// If no application specified, return
if (!currentApp) return;
// Else, get metrics every 10 seconds
getMetrics();
getSearchDrift();
metricsInterval = setInterval(() => {
getMetrics();
getSearchDrift();
}, 10000);
}, [currentApp, currentEnv, timeFilters]);
return (
<>
<Helmet>
<html lang="en" />
<title>Metrics</title>
<meta name="description" content="Events metrics" />
<meta name="keywords" content="celery, tasks" />
</Helmet>
<Row justify="space-between" align="middle" style={{ marginBottom: 16 }}>
<Statistic
loading={searchDriftLoading}
title={
<Tooltip title="The time of the latest event processed by leek.">
<span>Latest Event </span>
<InfoCircleOutlined />
</Tooltip>
}
value={
searchDrift && searchDrift.latest_event_timestamp
? moment(searchDrift.latest_event_timestamp).format(
"MMM D HH:mm:ss Z"
)
: ""
}
valueStyle={{ fontSize: 17.5 }}
prefix={<FieldTimeOutlined />}
/>
<Affix
style={{
position: "fixed",
left: "50%",
transform: "translate(-50%, 0)",
}}
>
<Row>
<TimeFilter
timeFilter={timeFilters}
onTimeFilterChange={setTimeFilters}
/>
</Row>
</Affix>
<Statistic
loading={searchDriftLoading}
title={
<Tooltip title="How many events in the queue waiting to be indexed.">
<span>Current Drift </span>
<InfoCircleOutlined />
</Tooltip>
}
value={
searchDrift && searchDrift.messages_count
? searchDrift.messages_count
: "0"
}
valueStyle={{ fontSize: 17.5 }}
prefix={<EyeInvisibleOutlined />}
/>
</Row>
<Row gutter={16} justify="center" align="middle">
{stats_widgets.map((widget, idx) => (
<Col
lg={12}
md={12}
sm={12}
xs={24}
key={idx}
style={{ marginBottom: "16px" }}
>
<StickerWidget
number={widget.number}
text={widget.text}
icon={widget.icon}
tooltip={widget.tooltip}
/>
</Col>
))}
</Row>
</>
);
}
Example #24
Source File: index.tsx From fe-v5 with Apache License 2.0 | 4 votes |
export default function index(props: IProps) {
const { preNamePrefix = [], namePrefix = ['options', 'valueMappings'] } = props;
return (
<Panel header='值映射'>
<Form.List name={namePrefix}>
{(fields, { add, remove }) => (
<>
<Button
style={{ width: '100%', marginBottom: 10 }}
onClick={() => {
add({
type: 'special',
});
}}
>
添加
</Button>
{_.isEmpty(fields) ? null : (
<Row gutter={10}>
<Col flex='290px'>
<Tooltip
overlayInnerStyle={{
width: 300,
}}
title={
<div>
<div>范围值说明: from >= value <= to</div>
<div>范围值默认值: from=-Infinity; to=Infinity </div>
<div>特殊值Null说明: 匹配值为 null 或 undefined 或 no data</div>
</div>
}
>
条件 <InfoCircleOutlined />
</Tooltip>
</Col>
<Col flex='210'>显示文字</Col>
<Col flex='45'>颜色</Col>
<Col flex='50'>操作</Col>
</Row>
)}
{fields.map(({ key, name, ...restField }) => {
return (
<Row key={key} gutter={10} style={{ marginBottom: 10 }}>
<Col flex='290px'>
<Row gutter={10}>
<Col flex='80px'>
<Form.Item noStyle {...restField} name={[name, 'type']}>
<Select suffixIcon={<CaretDownOutlined />} style={{ width: 80 }}>
<Select.Option value='special'>固定值</Select.Option>
<Select.Option value='range'>范围值</Select.Option>
<Select.Option value='specialValue'>特殊值</Select.Option>
</Select>
</Form.Item>
</Col>
<Col flex='1'>
<Form.Item noStyle {...restField} shouldUpdate>
{({ getFieldValue }) => {
const type = getFieldValue([...preNamePrefix, ...namePrefix, name, 'type']);
if (type === 'special') {
return (
<Form.Item noStyle {...restField} name={[name, 'match', 'special']}>
<InputNumber style={{ width: '100%' }} />
</Form.Item>
);
}
if (type === 'range') {
return (
<Row gutter={10}>
<Col span={12}>
<Form.Item noStyle {...restField} name={[name, 'match', 'from']}>
<InputNumber placeholder='from' />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item noStyle {...restField} name={[name, 'match', 'to']}>
<InputNumber placeholder='to' />
</Form.Item>
</Col>
</Row>
);
}
if (type === 'specialValue') {
return (
<Form.Item noStyle {...restField} name={[name, 'match', 'specialValue']}>
<Select suffixIcon={<CaretDownOutlined />} style={{ width: '100%' }}>
<Select.Option value='null'>Null</Select.Option>
<Select.Option value='empty'>Empty string</Select.Option>
</Select>
</Form.Item>
);
}
return null;
}}
</Form.Item>
</Col>
</Row>
</Col>
<Col flex='210'>
<Form.Item noStyle {...restField} name={[name, 'result', 'text']}>
<Input placeholder='可选' />
</Form.Item>
</Col>
<Col flex='45'>
<Form.Item noStyle {...restField} name={[name, 'result', 'color']}>
<ColorPicker />
</Form.Item>
</Col>
<Col flex='50'>
<Button
onClick={() => {
remove(name);
}}
icon={<DeleteOutlined />}
/>
</Col>
</Row>
);
})}
</>
)}
</Form.List>
</Panel>
);
}
Example #25
Source File: PageSetting.tsx From yugong with MIT License | 4 votes |
Pagesetting: React.FC<Props> = () => {
const appData = useSelector((state: RootState) => state.appData);
const pageData = useSelector((state: RootState) => state.pageData);
const updatePage = useDispatch<Dispatch>().pageData.updatePage;
const [showRunningTimes, setShowRunningTimes] = useState(false);
const runningTimes = useSelector((state: RootState) => state.runningTimes);
// const ref = useRef();
// 监听App页面数据,同步到编辑器数据
const sendMessage = usePostMessage((data) => {
const { tag, value } = data;
if (tag === "updatePage") {
updatePage(value);
}
});
// 本地存储编辑数据
const [, setPagedataLocalStorage] = useLocalStorage("pageData", null);
const handleUpdatePage = useCallback(
(pageData) => {
// 1、更新redux数据
updatePage(pageData);
// 2、将页面数据本地缓存
setPagedataLocalStorage(pageData);
// 3、向下游发送数据
const win = (document.getElementById("wrapiframe") as HTMLIFrameElement)
.contentWindow;
if (win) {
sendMessage(
{
tag: "updatePage",
value: pageData,
},
win
);
}
},
[sendMessage, setPagedataLocalStorage, updatePage]
);
const onChangeEnv = useCallback(
(envinfo, data) => {
const optPageData = produce(pageData, draft => {
if (envinfo.name === "mount") {
draft.mountEnvents = data;
}
if (envinfo.name === "unmount") {
draft.unmountEnvents = data;
}
}, createDesc('页面', `修改${envinfo.name}事件`));
handleUpdatePage(optPageData);
},
[handleUpdatePage, pageData]
);
const onChange = useCallback(
(
result: any,
type: StyleType
) => {
if (type === 'backgroundGroup') {
const optPageData = produce(pageData, draft => {
draft.style = {
backgroundGroup: result
}
}, createDesc('页面', '修改背景样式'));
handleUpdatePage(optPageData);
}
},
[handleUpdatePage, pageData]
);
const onChangeUnit = useCallback(
(type: "unit" | "toUnit") => (e: any) => {
const optPageData = produce(pageData, draft => {
if (type === "unit") {
draft.unit = e;
}
if (type === "toUnit") {
draft.toUnit = e;
}
if (draft.unit !== "rem" && draft.toUnit !== "rem") {
delete draft.UIWidth;
delete draft.baseFont;
} else {
draft.UIWidth = undefined;
draft.baseFont = undefined;
}
}, createDesc('页面', '修改全局单位'));
handleUpdatePage(optPageData);
},
[handleUpdatePage, pageData]
);
const onChangeStatisticsId = useCallback(
(e) => {
const optPageData = produce(pageData, draft => {
draft.statisticsId = e.target.value;
}, createDesc('页面', '设置百度统计'));
handleUpdatePage(optPageData);
},
[handleUpdatePage, pageData]
);
const onChangeUIWidth = useCallback(
(e) => {
const optPageData = produce(pageData, draft => {
draft.UIWidth = e;
}, createDesc('页面', '设置UI宽度'));
handleUpdatePage(optPageData);
},
[handleUpdatePage, pageData]
);
const onChangeBaseFont = useCallback(
(e) => {
const optPageData = produce(pageData, draft => {
draft.baseFont = e;
}, createDesc('页面', '设置UI基准字体'));
handleUpdatePage(optPageData);
},
[handleUpdatePage, pageData]
);
const onChangeApi = useCallback(
(data) => {
const optPageData = produce(pageData, draft => {
draft.onLoadApi = data;
}, createDesc('页面', '修改Api'));
handleUpdatePage(optPageData);
},
[handleUpdatePage, pageData]
);
const onRemoveApi = useCallback(
(_, data: ApiType) => {
const optPageData = produce(pageData, draft => {
draft.onLoadApi = reject(draft.onLoadApi, {
apiId: data.apiId,
});
}, createDesc('页面', '删除Api'));
handleUpdatePage(optPageData);
},
[handleUpdatePage, pageData]
);
const onPlus = useCallback(() => {
const optPageData = produce(pageData, draft => {
draft.onLoadApi?.push({
name: `ApiBeforMounted`,
apiId: nanoid(),
});
}, createDesc('页面', '新增Api'));
handleUpdatePage(optPageData);
}, [handleUpdatePage, pageData]);
const onChangeRowHeight = useCallback(
(e) => {
const optPageData = produce(pageData, draft => {
draft.rowHeight = e.target.value;
}, createDesc('页面', '修改删格行高'));
handleUpdatePage(optPageData);
},
[handleUpdatePage, pageData]
);
const onChangeCols = useCallback(
(e) => {
const optPageData = produce(pageData, draft => {
draft.cols = e.target.value;
}, createDesc('页面', '修改删格列宽'));
handleUpdatePage(optPageData);
},
[handleUpdatePage, pageData]
);
const onChangeSpace = useCallback(
(e) => {
const optPageData = produce(pageData, draft => {
draft.space = e.target.value;
}, createDesc('页面', '修改删格间距'));
handleUpdatePage(optPageData);
},
[handleUpdatePage, pageData]
);
const onChangePageTitle = useCallback(
(e) => {
const optPageData = produce(pageData, draft => {
draft.pageTitle = e.target.value;
}, createDesc('页面', '修改标题'));
handleUpdatePage(optPageData);
},
[handleUpdatePage, pageData]
);
const onShowRunningTimes = useCallback((e) => {
e.stopPropagation();
setShowRunningTimes(true);
}, []);
const getDefaultData = useCallback(
(type: StyleType) => pageData.style?.backgroundGroup || {},
[pageData.style?.backgroundGroup]
);
return (
<>
<Collapse accordion bordered={false} defaultActiveKey="baseset">
<Panel
header="基本信息"
key="baseset"
extra={
<Tooltip title="查看全局发布变量">
<ClusterOutlined onClick={onShowRunningTimes} />
</Tooltip>
}
>
<Row gutter={4} className={s.row}>
<Col className={s.label} span={4}>
页面名称:
</Col>
<Col span={19}>
<Input
placeholder="请输入页面名称"
value={pageData.pageTitle}
onChange={onChangePageTitle}
className={s.num}
/>
</Col>
<Col span={1} />
</Row>
<Row gutter={4} className={s.row}>
<Col className={s.label} span={4}>
栅格列数:
</Col>
<Col span={7}>
<Input
value={pageData.cols}
onChange={onChangeCols}
className={s.num}
placeholder="输入栅格列数"
/>
</Col>
<Col className={s.info} span={1}>
<Tooltip title={<div>屏幕栅格列数>0 (默认12列)</div>}>
<InfoCircleOutlined />
</Tooltip>
</Col>
<Col className={s.label} span={4}>
栅格行高:
</Col>
<Col span={7}>
<Input
value={pageData.rowHeight}
onChange={onChangeRowHeight}
placeholder="输入栅格行高"
className={s.num}
/>
</Col>
<Col className={s.info} span={1}>
<Tooltip
title={
<div>屏幕栅格行高>0(默认20px),可使用运行时window计算高度</div>
}
>
<InfoCircleOutlined />
</Tooltip>
</Col>
</Row>
<Row gutter={4} className={s.row}>
<Col className={s.label} span={4}>
栅格间距:
</Col>
<Col span={7}>
<Input
value={pageData.space}
onChange={onChangeSpace}
className={s.num}
placeholder="输入栅格间距"
/>
</Col>
<Col className={s.info} span={1}>
<Tooltip title={<div>栅格间距(默认0px)</div>}>
<InfoCircleOutlined />
</Tooltip>
</Col>
</Row>
<Row gutter={4} className={s.row}>
<Col className={s.label} span={4}>
基准单位:
</Col>
<Col span={19}>
<Select
placeholder="请选择"
className={s.select}
value={pageData.toUnit}
onChange={onChangeUnit("toUnit")}
>
{units.map((item) => (
<Option key={item} value={item}>
{item}
</Option>
))}
</Select>
</Col>
<Col className={s.info} span={1}>
<Tooltip title={<div>页面的基准单位,用于单位换算;设置为rem时需要设置UI宽度和基准像素</div>}>
<InfoCircleOutlined />
</Tooltip>
</Col>
</Row>
{pageData.toUnit === "rem" || pageData.unit === "rem" ? (
<Row gutter={4} className={s.row}>
<Col className={s.label} span={4}>
UI宽度:
</Col>
<Col span={7}>
<InputNumber
value={pageData.UIWidth}
onChange={onChangeUIWidth}
placeholder="px"
className={s.num}
/>
</Col>
<Col className={s.info} span={1}>
<Tooltip title={<div>UI设计的屏幕宽度(px)</div>}>
<InfoCircleOutlined />
</Tooltip>
</Col>
<Col className={s.label} span={4}>
基准像素:
</Col>
<Col span={7}>
<InputNumber
min={5}
value={pageData.baseFont}
onChange={onChangeBaseFont}
placeholder="px"
className={s.num}
/>
</Col>
<Col className={s.info} span={1}>
<Tooltip title={<div>UI设计下,1rem=1基准像素</div>}>
<InfoCircleOutlined />
</Tooltip>
</Col>
</Row>
) : null}
<StyleContext.Provider
value={{
onChange,
getDefaultData
}}
>
<Row gutter={4} className={s.row}>
<Col span={24}>
<div className={s.bg}>
<BackgroundGroup />
</div>
</Col>
<Col span={1} />
</Row>
</StyleContext.Provider>
</Panel>
<Panel header="初始化Api" key="pagemount">
<div className={s.apiwrap}>
<h4 className={s.apititle}>
<Button size="small" icon={<PlusOutlined onClick={onPlus} />} />
</h4>
<ApiConfig
sortable
onRemove={onRemoveApi}
apiData={pageData.onLoadApi}
defaultApiData={cloneDeep(pageData.onLoadApi)}
onChange={onChangeApi}
/>
</div>
</Panel>
<Panel header="页面事件" key="pageevent">
<div className={s.events}>
<>
{Output.exposeEvents?.map((item, index) => (
<EventGroup
key={index}
eventName={item.name}
value={
item.name === "mount"
? pageData.mountEnvents || []
: pageData.unmountEnvents || []
}
curentEventInfomation={item}
onPlay={() => {}}
onChange={onChangeEnv}
/>
))}
</>
</div>
</Panel>
<Panel header="百度统计" key="pagecounter">
<Row className={s.row}>
<Col className={s.label} span={4}>
统计Id:
</Col>
<Col span={20}>
<Input
placeholder="请在百度账号下创建站点,获取统计Id"
className={s.num}
value={pageData.statisticsId}
onChange={onChangeStatisticsId}
/>
</Col>
</Row>
</Panel>
<Panel header="数据视图" key="pagedata">
<ReactJson src={{pageData, appData}} collapsed={1} name="project" />
</Panel>
</Collapse>
<RunningTimesModal
visible={showRunningTimes}
data={runningTimes}
onCancel={() => setShowRunningTimes(false)}
/>
</>
);
}
Example #26
Source File: index.tsx From fe-v5 with Apache License 2.0 | 4 votes |
export default function index(props: IProps) {
const { preNamePrefix = [], namePrefix = ['options', 'valueMappings'] } = props;
return (
<Panel header='值映射'>
<Form.List name={namePrefix}>
{(fields, { add, remove }) => (
<>
<Button
style={{ width: '100%', marginBottom: 10 }}
onClick={() => {
add({
type: 'special',
});
}}
>
添加
</Button>
{_.isEmpty(fields) ? null : (
<Row gutter={10}>
<Col flex='290px'>
<Tooltip
overlayInnerStyle={{
width: 300,
}}
title={
<div>
<div>范围值说明: from >= value <= to</div>
<div>范围值默认值: from=-Infinity; to=Infinity </div>
<div>特殊值Null说明: 匹配值为 null 或 undefined 或 no data</div>
</div>
}
>
条件 <InfoCircleOutlined />
</Tooltip>
</Col>
<Col flex='210'>显示文字</Col>
<Col flex='45'>颜色</Col>
<Col flex='50'>操作</Col>
</Row>
)}
{fields.map(({ key, name, ...restField }) => {
return (
<Row key={key} gutter={10} style={{ marginBottom: 10 }}>
<Col flex='290px'>
<Row gutter={10}>
<Col flex='80px'>
<Form.Item noStyle {...restField} name={[name, 'type']}>
<Select suffixIcon={<CaretDownOutlined />} style={{ width: 80 }}>
<Select.Option value='special'>固定值</Select.Option>
<Select.Option value='range'>范围值</Select.Option>
<Select.Option value='specialValue'>特殊值</Select.Option>
</Select>
</Form.Item>
</Col>
<Col flex='1'>
<Form.Item noStyle {...restField} shouldUpdate={(prevValues, curValues) => _.get(prevValues, [name, 'type']) !== _.get(curValues, [name, 'type'])}>
{({ getFieldValue }) => {
const type = getFieldValue([...preNamePrefix, ...namePrefix, name, 'type']);
if (type === 'special') {
return (
<Form.Item noStyle {...restField} name={[name, 'match', 'special']}>
<InputNumber style={{ width: '100%' }} />
</Form.Item>
);
}
if (type === 'range') {
return (
<Row gutter={10}>
<Col span={12}>
<Form.Item noStyle {...restField} name={[name, 'match', 'from']}>
<InputNumber placeholder='from' />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item noStyle {...restField} name={[name, 'match', 'to']}>
<InputNumber placeholder='to' />
</Form.Item>
</Col>
</Row>
);
}
if (type === 'specialValue') {
return (
<Form.Item noStyle {...restField} name={[name, 'match', 'specialValue']}>
<Select suffixIcon={<CaretDownOutlined />}>
<Select.Option value='null'>Null</Select.Option>
<Select.Option value='empty'>Empty string</Select.Option>
</Select>
</Form.Item>
);
}
return null;
}}
</Form.Item>
</Col>
</Row>
</Col>
<Col flex='210'>
<Form.Item noStyle {...restField} name={[name, 'result', 'text']}>
<Input placeholder='可选' />
</Form.Item>
</Col>
<Col flex='45'>
<Form.Item noStyle {...restField} name={[name, 'result', 'color']}>
<ColorPicker />
</Form.Item>
</Col>
<Col flex='50'>
<Button
onClick={() => {
remove(name);
}}
icon={<DeleteOutlined />}
/>
</Col>
</Row>
);
})}
</>
)}
</Form.List>
</Panel>
);
}
Example #27
Source File: ArgumentsSetting.tsx From yugong with MIT License | 4 votes |
ArgumentsSetting: React.FC<Props> = ({
visible,
argumentsData,
initArgumentData,
onOk,
onCancel,
title,
dataFlexible = false,
headerFlexible = false,
forceUpdate,
visiableRunningTimeIcon = true,
}) => {
const runningTimes = useSelector((state: RootState) => state.runningTimes);
const [argumentState, setArgumentState] = useState<ArgumentsItem[]>([]);
const [showRunningTimes, setShowRunningTimes] = useState(false);
const forceUpdateByStateTag =
useDispatch<Dispatch>().controller.forceUpdateByStateTag;
// 将argument数据接管
useEffect(() => {
let data: ArgumentsItem[] = [...(argumentsData || [])];
// 不可自定义参数且数据为空时,使用组件初始数据
if (data.length === 0) {
data = [...(initArgumentData || [])];
}
setArgumentState(data);
}, [argumentsData, headerFlexible, initArgumentData]);
// 弹窗确定收集编辑完毕的argument数据
const onModalOk = useCallback(() => {
if (onOk instanceof Function) {
// todo 确定页面为何强制更新??
if (forceUpdate) {
forceUpdateByStateTag();
}
onOk(argumentState);
}
}, [onOk, forceUpdateByStateTag, argumentState, forceUpdate]);
// number
const onChangeInput = useCallback(
(index: number, isSelect?: boolean) => (e: any) => {
const result = cloneDeep(argumentState);
result[index].data = isSelect ? e : e.target.value;
setArgumentState(result);
},
[argumentState],
);
const onChangeRunningTime = useCallback(
(index: number) => (e: any) => {
const result = [...argumentState];
result[index].data = e;
setArgumentState(result);
},
[argumentState],
);
const onChangeObjType = useCallback(
(index: number) => (data: ArgumentsItem) => {
const result = [...argumentState];
result[index] = data;
setArgumentState(result);
},
[argumentState],
);
const onChangeFieldName = useCallback(
(index: number) => (e: any) => {
const result = [...argumentState];
result[index].fieldName = e.target.value;
result[index].name = e.target.value;
setArgumentState(result);
},
[argumentState],
);
const onChangeDescribe = useCallback(
(index: number) => (e: any) => {
const result = [...argumentState];
result[index].describe = e.target.value;
setArgumentState(result);
},
[argumentState],
);
// 移除字段
const onRemove = useCallback(
(index: number) => () => {
let result = [...argumentState];
result = result.filter((_, i) => i !== index);
setArgumentState(result);
},
[argumentState],
);
// 新增字段
const onAddField = useCallback(() => {
const result = [...argumentState];
result.push({
describe: undefined,
name: '未命名',
fieldName: '',
type: 'string',
data: '',
});
setArgumentState(result);
}, [argumentState]);
// 修改字段类型
const onChangeArgType = useCallback(
(index: number) => (e: any) => {
const result = [...argumentState];
result[index].type = e;
switch (e) {
case 'runningTime':
case 'string':
case 'number':
result[index].data = '';
break;
case 'array':
result[index].data = [];
break;
case 'object':
result[index].data = {};
break;
case 'boolean':
result[index].data = {
comparableAverageA: null,
comparableAverageB: null,
method: '===',
};
break;
default:
break;
}
setArgumentState(result);
},
[argumentState],
);
const onClickShowGloabVar = useCallback(() => {
console.log(runningTimes);
}, [runningTimes]);
const renderNumberString = (
item: ArgumentsString | ArgumentsNumber,
index: number,
) => {
// 下拉选择形式
if (item?.select) {
const { select } = item;
const keys = Object.keys(select);
console.log('select', select);
console.log('keys', keys);
return (
<Select
onChange={onChangeInput(index, true)}
value={item.data}
className={s.select}
placeholder={`请输入值,${item.describe || ''}`}
>
{keys.map((value) => (
<Select.Option key={value} value={value}>
{select[value]}
</Select.Option>
))}
</Select>
);
}
// 输入框形式
return (
<Input
onChange={onChangeInput(index)}
placeholder={`请输入值,${item.describe || ''}`}
value={item.data}
type="text"
suffix={!!item.html ? <HtmlSuffix /> : null}
/>
);
};
return (
<>
<Modal
title={
<div className={s.title}>
<h4>
{title}{' '}
{visiableRunningTimeIcon ? <Button
type="text"
onClick={onClickShowGloabVar}
icon={
<Tooltip title="查看全局发布变量">
<ClusterOutlined
onClick={() => setShowRunningTimes(true)}
/>
</Tooltip>
}
/> : null}
</h4>
<div className={s.right}>
{headerFlexible ? (
<Button onClick={onAddField}>新增</Button>
) : null}
</div>
</div>
}
visible={visible}
onOk={onModalOk}
onCancel={onCancel}
bodyStyle={{ padding: '10px' }}
okText="确定"
cancelText="取消"
>
{argumentState.map((item, index) => {
const initItem = initArgumentData?.length
? initArgumentData[index]
: undefined;
return (
<Card
className={classNames(s.card, {
[s.mixedcard]: item.type === 'mixed',
})}
key={`${index}`}
title={
<div className={s.cardtitle}>
<div className={s.cardtitleinfo}>
{!headerFlexible ? (
<>
<span className={s.label}>名称:</span>
{item.name || initItem?.name || ''}
<Tooltip
title={parse(
item.describe || initItem?.describe || '',
)}
>
<InfoCircleOutlined
style={{
color: 'rgba(0,0,0,.45)',
}}
/>
</Tooltip>
</>
) : (
<>
<span className={s.label}>字段:</span>
<Input
className={s.title}
value={item.fieldName || initItem?.fieldName || ''}
placeholder="限数字或字母"
onChange={onChangeFieldName(index)}
suffix={
<Tooltip
title={
<Input
className={s.desc}
placeholder="新增字段描述"
value={item.describe}
style={{
width: '200px',
}}
onChange={onChangeDescribe(index)}
/>
}
>
<InfoCircleOutlined
style={{
color: 'rgba(0,0,0,.45)',
}}
/>
</Tooltip>
}
/>
</>
)}
<span className={s.divide} />
<span className={s.label}>类型:</span>
{headerFlexible ? (
<Select
className={s.type}
value={item.type}
onChange={onChangeArgType(index)}
>
<Select.Option value="string">string</Select.Option>
<Select.Option value="number">number</Select.Option>
<Select.Option value="boolean">boolean</Select.Option>
<Select.Option value="object">object</Select.Option>
<Select.Option value="array">array</Select.Option>
<Select.Option value="mixed">mixed</Select.Option>
<Select.Option value="runningTime">
runningTime
</Select.Option>
</Select>
) : (
item.type
)}
</div>
<div>
{headerFlexible ? (
<Button onClick={onRemove(index)}>移除</Button>
) : null}
</div>
</div>
}
>
<div>
{item.type === 'number' || item.type === 'string'
? renderNumberString(item, index)
: null}
{item.type === 'runningTime' ? (
<Select
className={s.select}
placeholder="请选择"
showSearch
value={item.data}
optionFilterProp="children"
filterOption={
(input, option) => {
const str = option?.children?.join('').toLowerCase();
if (str?.indexOf(input) !== -1) {
return true;
}
return false;
}
// option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
onChange={onChangeRunningTime(index)}
>
{Object.keys(runningTimes)?.map(
(optionsIitem, optionsIitemIndex) => (
<Select.Option
key={optionsIitemIndex}
value={optionsIitem}
>
{optionsIitem}
</Select.Option>
),
)}
</Select>
) : null}
{item.type === 'object' ? (
<ObjectArguments
describe={item.describe}
htmlInput={!!item.html}
onChange={onChangeObjType(index)}
typeArguments={item}
flexible={!!dataFlexible}
/>
) : null}
{item.type === 'array' ? (
<ArrayArguments
htmlInput={!!item.html}
describe={item.describe}
onChange={onChangeObjType(index)}
typeArguments={item}
flexible={!!dataFlexible}
/>
) : null}
{item.type === 'boolean' ? (
<BooleanArguments
onChange={onChangeObjType(index)}
typeArguments={item}
flexible={!!dataFlexible}
/>
) : null}
{item.type === 'mixed' ? (
<MixedArguments
onChange={onChangeObjType(index)}
typeArguments={item}
flexible={!!dataFlexible}
/>
) : null}
</div>
</Card>
);
})}
</Modal>
<RunningTimesModal
visible={showRunningTimes}
data={runningTimes}
onCancel={() => setShowRunningTimes(false)}
/>
</>
);
}
Example #28
Source File: groups.tsx From fe-v5 with Apache License 2.0 | 4 votes |
Resource: React.FC = () => { const { t } = useTranslation(); const { type } = useParams<{ type: string; }>(); const [activeKey, setActiveKey] = useState<UserType>(UserType.Team); const [visible, setVisible] = useState<boolean>(false); const [action, setAction] = useState<ActionType>(); const [userId, setUserId] = useState<string>(''); const [teamId, setTeamId] = useState<string>(''); const [memberId, setMemberId] = useState<string>(''); const [memberList, setMemberList] = useState<User[]>([]); const [allMemberList, setAllMemberList] = useState<User[]>([]); const [teamInfo, setTeamInfo] = useState<Team>(); const [teamList, setTeamList] = useState<Team[]>([]); const [memberLoading, setMemberLoading] = useState<boolean>(false); const [searchValue, setSearchValue] = useState<string>(''); const [searchMemberValue, setSearchMemberValue] = useState<string>(''); const userRef = useRef(null as any); let { profile } = useSelector<RootState, accountStoreState>((state) => state.account); const userColumn: ColumnsType<User> = [ { title: t('用户名'), dataIndex: 'username', ellipsis: true, }, { title: t('显示名'), dataIndex: 'nickname', ellipsis: true, render: (text: string, record) => record.nickname || '-', }, { title: t('邮箱'), dataIndex: 'email', render: (text: string, record) => record.email || '-', }, { title: t('手机'), dataIndex: 'phone', render: (text: string, record) => record.phone || '-', }, ]; const teamMemberColumns: ColumnsType<User> = [ ...userColumn, { title: t('操作'), width: '100px', render: ( text: string, record, // <DelPopover ) => ( // teamId={teamId} // memberId={record.id} // userType='member' // onClose={() => handleClose()} // ></DelPopover> <a style={{ color: 'red', }} onClick={() => { let params = { ids: [record.id], }; confirm({ title: t('是否删除该成员'), onOk: () => { deleteMember(teamId, params).then((_) => { message.success(t('成员删除成功')); handleClose('updateMember'); }); }, onCancel: () => {}, }); }} > {t('删除')} </a> ), }, ]; useEffect(() => { getList(true); }, []); //teamId变化触发 useEffect(() => { if (teamId) { getTeamInfoDetail(teamId); } }, [teamId]); const getList = (isDeleteOrAdd = false) => { getTeamList('', isDeleteOrAdd); }; // 获取团队列表 const getTeamList = (search?: string, isDelete?: boolean) => { getTeamInfoList({ query: search || '' }).then((data) => { setTeamList(data.dat || []); if ((!teamId || isDelete) && data.dat.length > 0) { setTeamId(data.dat[0].id); } }); }; // 获取团队详情 const getTeamInfoDetail = (id: string) => { setMemberLoading(true); getTeamInfo(id).then((data: TeamInfo) => { setTeamInfo(data.user_group); setMemberList(data.users); setAllMemberList(data.users); setMemberLoading(false); }); }; const handleSearch = (type?: string, val?: string) => { if (type === 'team') { getTeamList(val); } else { if (!val) { getTeamInfoDetail(teamId); } else { setMemberLoading(true); let newList = allMemberList.filter( (item) => item.username.indexOf(val) !== -1 || item.nickname.indexOf(val) !== -1 || item.id.toString().indexOf(val) !== -1 || item.phone.indexOf(val) !== -1 || item.email.indexOf(val) !== -1, ); setMemberList(newList); setMemberLoading(false); } } }; const handleClick = (type: ActionType, id?: string, memberId?: string) => { if (id) { setTeamId(id); } else { setTeamId(''); } if (memberId) { setMemberId(memberId); } else { setMemberId(''); } setAction(type); setVisible(true); }; // 弹窗关闭回调 const handleClose = (isDeleteOrAdd: boolean | string = false) => { setVisible(false); if (searchValue) { handleSearch('team', searchValue); } else { // 添加、删除成员 不用获取列表 if (isDeleteOrAdd !== 'updateMember') { getList(isDeleteOrAdd !== 'updateName'); // 修改名字,不用选中第一个 } } if (teamId && (isDeleteOrAdd === 'update' || isDeleteOrAdd === 'updateMember' || isDeleteOrAdd === 'updateName')) { getTeamInfoDetail(teamId); } }; return ( <PageLayout title={t('团队管理')} icon={<UserOutlined />} hideCluster> <div className='user-manage-content'> <div style={{ display: 'flex', height: '100%' }}> <div className='left-tree-area'> <div className='sub-title'> {t('团队列表')} <Button style={{ height: '30px', }} size='small' type='link' onClick={() => { handleClick(ActionType.CreateTeam); }} > {t('新建团队')} </Button> </div> <div style={{ display: 'flex', margin: '5px 0px 12px' }}> <Input prefix={<SearchOutlined />} value={searchValue} onChange={(e) => { setSearchValue(e.target.value); }} placeholder={t('搜索团队名称')} onPressEnter={(e) => { // @ts-ignore getTeamList(e.target.value); }} onBlur={(e) => { // @ts-ignore getTeamList(e.target.value); }} /> </div> <List style={{ marginBottom: '12px', flex: 1, overflow: 'auto', }} dataSource={teamList} size='small' renderItem={(item) => ( <List.Item key={item.id} className={teamId === item.id ? 'is-active' : ''} onClick={() => setTeamId(item.id)}> {item.name} </List.Item> )} /> </div> {teamList.length > 0 ? ( <div className='resource-table-content'> <Row className='team-info'> <Col span='24' style={{ color: '#000', fontSize: '14px', fontWeight: 'bold', display: 'inline', }} > {teamInfo && teamInfo.name} <EditOutlined title={t('刷新')} style={{ marginLeft: '8px', fontSize: '14px', }} onClick={() => handleClick(ActionType.EditTeam, teamId)} ></EditOutlined> <DeleteOutlined style={{ marginLeft: '8px', fontSize: '14px', }} onClick={() => { confirm({ title: t('是否删除该团队'), onOk: () => { deleteTeam(teamId).then((_) => { message.success(t('团队删除成功')); handleClose(true); }); }, onCancel: () => {}, }); }} /> </Col> <Col style={{ marginTop: '8px', color: '#666', }} > {t('备注')}:{teamInfo && teamInfo.note ? teamInfo.note : '-'} </Col> </Row> <Row justify='space-between' align='middle'> <Col span='12'> <Input prefix={<SearchOutlined />} value={searchMemberValue} className={'searchInput'} onChange={(e) => setSearchMemberValue(e.target.value)} placeholder={t('用户名、显示名、邮箱或手机')} onPressEnter={(e) => handleSearch('member', searchMemberValue)} /> </Col> <Button type='primary' ghost onClick={() => { handleClick(ActionType.AddUser, teamId); }} > {t('添加成员')} </Button> </Row> <Table rowKey='id' columns={teamMemberColumns} dataSource={memberList} loading={memberLoading} /> </div> ) : ( <div className='blank-busi-holder'> <p style={{ textAlign: 'left', fontWeight: 'bold' }}> <InfoCircleOutlined style={{ color: '#1473ff' }} /> {t('提示信息')} </p> <p> 没有与您相关的团队,请先 <a onClick={() => handleClick(ActionType.CreateTeam)}>创建团队</a> </p> </div> )} </div> <UserInfoModal visible={visible} action={action as ActionType} width={500} userType={activeKey} onClose={handleClose} onSearch={(val) => { setSearchValue(val); handleSearch('team', val); }} userId={userId} teamId={teamId} memberId={memberId} /> </div> </PageLayout> ); }
Example #29
Source File: Tabs.tsx From datart with Apache License 2.0 | 4 votes |
Tabs = memo(() => {
const [operatingView, setOperatingView] = useState<null | ViewViewModel>(
null,
);
const [confirmVisible, setConfirmVisible] = useState(false);
const dispatch = useDispatch();
const history = useHistory();
const { editorInstance } = useContext(EditorContext);
const orgId = useSelector(selectOrgId);
const editingViews = useSelector(selectEditingViews);
const id = useSelector(state =>
selectCurrentEditingViewAttr(state, { name: 'id' }),
) as string;
const t = useI18NPrefix('view.tabs');
const redirect = useCallback(
currentEditingViewKey => {
if (currentEditingViewKey) {
history.push(`/organizations/${orgId}/views/${currentEditingViewKey}`);
} else {
history.push(`/organizations/${orgId}/views`);
}
},
[history, orgId],
);
const tabChange = useCallback(
activeKey => {
if (id !== activeKey) {
history.push(`/organizations/${orgId}/views/${activeKey}`);
}
},
[history, id, orgId],
);
const tabEdit = useCallback(
(targetKey, action) => {
const view = editingViews.find(v => v.id === targetKey);
switch (action) {
case 'remove':
if (view!.touched === false) {
dispatch(removeEditingView({ id: targetKey, resolve: redirect }));
} else {
setOperatingView(view!);
setConfirmVisible(true);
}
break;
default:
break;
}
},
[dispatch, editingViews, redirect],
);
const hideConfirm = useCallback(() => {
setConfirmVisible(false);
}, []);
const removeTab = useCallback(() => {
dispatch(removeEditingView({ id: operatingView!.id, resolve: redirect }));
setConfirmVisible(false);
}, [dispatch, operatingView, redirect]);
const runTab = useCallback(() => {
const fragment = editorInstance
?.getModel()
?.getValueInRange(editorInstance.getSelection()!);
setConfirmVisible(false);
dispatch(runSql({ id, isFragment: !!fragment }));
}, [dispatch, id, editorInstance]);
return (
<Wrapper>
<TabsComponent
hideAdd
type="editable-card"
activeKey={id}
onChange={tabChange}
onEdit={tabEdit}
>
{editingViews.map(({ id, name, touched, stage, error }) => (
<TabPane
key={id}
tab={error ? <span css={errorColor}>{name}</span> : name}
closeIcon={
<CloseIcon touched={touched} stage={stage} error={!!error} />
}
/>
))}
</TabsComponent>
<Confirm
visible={confirmVisible}
title={t('warning')}
icon={<InfoCircleOutlined style={{ color: ORANGE }} />}
footer={
<Space>
<Button onClick={removeTab}>{t('discard')}</Button>
<Button onClick={hideConfirm}>{t('cancel')}</Button>
<Button onClick={runTab} type="primary">
{t('execute')}
</Button>
</Space>
}
/>
</Wrapper>
);
})