antd#Divider TypeScript Examples
The following examples show how to use
antd#Divider.
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: ExampleCustomScreen.tsx From jmix-frontend with Apache License 2.0 | 6 votes |
ExampleCustomScreen = () => {
const mainStore = useMainStore();
const [contentDisplayMode, setContentDisplayMode] = useState(mainStore.contentDisplayMode);
const handleContentDisplayModeChange = useCallback((e: RadioChangeEvent) => {
if (Object.values(ContentDisplayMode).includes(e.target.value)) {
mainStore.contentDisplayMode = e.target.value;
setContentDisplayMode(mainStore.contentDisplayMode);
}
}, [mainStore, setContentDisplayMode]);
return (
<>
<h2>
Example Custom Screen
</h2>
<Divider/>
<div>
<div><code>ContentDisplayMode:</code></div>
<Radio.Group onChange={handleContentDisplayModeChange} value={contentDisplayMode}>
<Space direction='vertical'>
<Radio value={ContentDisplayMode.ActivateExistingTab}>
<code>ContentDisplayMode.ActivateExistingTab</code>
</Radio>
<Radio value={ContentDisplayMode.AlwaysNewTab}>
<code>ContentDisplayMode.AlwaysNewTab</code>
</Radio>
<Radio value={ContentDisplayMode.NoTabs}>
<code>ContentDisplayMode.NoTabs</code>
</Radio>
</Space>
</Radio.Group>
</div>
</>
)
}
Example #2
Source File: PasswordReset.tsx From posthog-foss with MIT License | 6 votes |
function EmailUnavailable(): JSX.Element {
return (
<div>
<div>
Self-serve password reset is unavailable. Please <b>contact your instance administrator</b> to reset
your password.
</div>
<Divider />
<div className="mt">
If you're an administrator:
<ul>
<li>
Password reset is unavailable because email service is not configured.{' '}
<a href="https://posthog.com/docs/self-host/configure/email?utm_medium=in-product&utm_campaign=password-reset">
Read the docs
</a>{' '}
on how to set this up.
</li>
<li>To reset the password manually, run the following command in your instance.</li>
</ul>
<CodeSnippet language={Language.Bash} wrap>
{'python manage.py changepassword [account email]'}
</CodeSnippet>
</div>
</div>
)
}
Example #3
Source File: DatePresets.tsx From ant-extensions with MIT License | 6 votes |
DatePresets: React.FC<BaseProps> = React.memo((props) => {
return (
<div className="ant-ext-sd__quickForm">
<QuickSelect {...props} />
<Divider />
<QuickPresets {...props} />
</div>
);
})
Example #4
Source File: AdvanceSetting.tsx From next-basics with GNU General Public License v3.0 | 6 votes |
export function AdvanceSetting(props: AdvanceSettingProps): React.ReactElement {
const fold = (
<div style={props.foldStyle} id="foldBrickButton" className="foldContainer">
<span>{props.foldName}</span>
{props.showFoldIcon && (
<UpOutlined
rotate={props.show ? 0 : 180}
style={{ marginLeft: "15px", lineHeight: "0px" }}
/>
)}
</div>
);
return (
<div>
<FormItemWrapper {...props}>
{props.showDivider ? (
<Divider
dashed={props.dividerDashed}
orientation={props.dividerOrientation}
>
{fold}
</Divider>
) : (
fold
)}
</FormItemWrapper>
<div
className={classNames({
foldActive: props.show,
foldInactive: !props.show,
})}
>
<slot name="content"></slot>
</div>
</div>
);
}
Example #5
Source File: index.tsx From jetlinks-ui-antd with MIT License | 6 votes |
CheckDevice = (props: Props) => {
const [visible, setVisible] = useState<boolean>(false);
const [deviceId, setDeviceId] = useState<string[]>([]);
const productId = props.props['x-component-props']?.productId;
return (
<div style={{ width: '100%' }}>
<Input
value={deviceId}
placeholder="全部设备"
addonAfter={<>
<Icon type="close" onClick={() => {
setDeviceId([]);
props.mutators.change([])
}} />
<Divider type="vertical"/>
<Icon type="plus" onClick={() => setVisible(true)} /></>}
/>
{visible && (
<DeviceList
data={deviceId}
productId={productId}
close={() => setVisible(false)}
save={(data: string[]) => {
setVisible(false);
setDeviceId(data);
props.mutators.change(data);
}}
/>
)}
</div>
);
}
Example #6
Source File: listings-skeleton.tsx From tinyhouse with MIT License | 6 votes |
export function ListingsSkeleton({
title,
error = false,
}: ListingsSkeletonProp) {
const errorAlert = error ? (
<Alert
type="error"
message={
<>
Oh no! Something went wrong - please try again later
<span role="img" aria-label="Sad face emoji">
?
</span>
</>
}
className="listing-skeleton__alert"
/>
) : null;
return (
<div className="listings-skeleton">
{errorAlert}
<h2>
{title}
{[...Array(3)].map((_, index) => (
<div key={index}>
<Skeleton active paragraph={{ rows: 1 }} />
<Divider />
</div>
))}
</h2>
</div>
);
}
Example #7
Source File: LoginView.tsx From tailchat with GNU General Public License v3.0 | 6 votes |
OAuthLoginView: React.FC = React.memo(() => {
return (
<>
<Divider>{t('或')}</Divider>
<div className="bg-gray-400 w-1/3 px-4 py-1 text-3xl text-center rounded-md cursor-pointer shadow-md">
<Icon className="mx-auto" icon="mdi:github" />
</div>
</>
);
})
Example #8
Source File: index.tsx From Aragorn with MIT License | 6 votes |
About = () => {
function handleUpdate() {
ipcRenderer.send('check-update', true);
}
return (
<div className="info-wrapper">
<header>
<span>关于</span>
<Divider />
</header>
<main>
<h3>Aragorn</h3>
<a
style={{ margin: 10 }}
onClick={() => {
shell.openExternal(AppUrl);
}}
>
{AppUrl}
</a>
<p className="desc">v{remote.app.getVersion()}</p>
<Button type="primary" onClick={handleUpdate}>
检查更新
</Button>
</main>
</div>
);
}
Example #9
Source File: ResidentActions.tsx From condo with MIT License | 6 votes |
ResidentAppealDropdownOverlay = () => {
return (
<StyledMenu>
<MenuItem
menuItemWrapperProps={ResidentAppealDropDownMenuItemWrapperProps}
path={'/ticket/create'}
icon={AppealIcon}
label={'CreateAppeal'}
/>
<Divider style={{ margin: 0 }}/>
<MenuItem
menuItemWrapperProps={ResidentAppealDropDownMenuItemWrapperProps}
path={'/meter/create'}
icon={MeterIcon}
label={'CreateMeterReading'}
/>
</StyledMenu>
)
}
Example #10
Source File: DataTableCustomFilter.tsx From jmix-frontend with Apache License 2.0 | 5 votes |
render() {
return (
<Form layout='inline' onFinish={this.handleFinish} ref={this.setFormRef}>
<div className={styles.tableFilter}>
<div className={styles.settings}>
<div className={styles.controlsLayout}>
<Form.Item className={classNames(
styles.filterControl,
styles.propertyCaption)
}>
{this.propertyCaption}
</Form.Item>
<Form.Item className={styles.filterControl}
initialValue={this.getDefaultOperator()}
name={`${this.props.entityProperty}_operatorsDropdown`}
>
<Select
dropdownClassName={`cuba-operator-dropdown-${this.props.entityProperty}`}
dropdownMatchSelectWidth={false}
onChange={(operator: ComparisonType) => this.changeOperator(operator)}
>
{this.operatorTypeOptions}
</Select>
</Form.Item>
{this.simpleFilterEditor}
</div>
{this.complexFilterEditor}
</div>
<Divider className={styles.divider} />
<div className={styles.footer}>
<Button htmlType='submit'
type='link'>
<FormattedMessage id='jmix.dataTable.ok'/>
</Button>
<Button
htmlType='button'
type='link'
onClick={this.resetFilter}>
<FormattedMessage id='jmix.dataTable.reset'/>
</Button>
</div>
</div>
</Form>
);
}
Example #11
Source File: PathCleanFilter.tsx From posthog-foss with MIT License | 5 votes |
export function PathRegexPopup({ item, onComplete, onClose }: PathRegexPopupProps): JSX.Element {
const [alias, setAlias] = useState(item['alias'])
const [regex, setRegex] = useState(item['regex'])
return (
<div className="regex-popup">
<Col>
<b>New Wildcard</b>
<Divider style={{ marginTop: 10, marginBottom: 10 }} />
<span>Alias</span>
<Input
defaultValue={alias}
onChange={(e) => setAlias(e.target.value)}
onPressEnter={() => false}
style={{ marginTop: 8, marginBottom: 12 }}
/>
<span>Regex</span>
<Input
defaultValue={regex}
onChange={(e) => setRegex(e.target.value)}
onPressEnter={() => false}
style={{ marginTop: 8, marginBottom: 0, fontFamily: 'monospace' }}
/>
<div className="text-muted" style={{ marginBottom: 12 }}>
For example: <code>\/merchant\/\d+\/dashboard$</code>
</div>
<Row style={{ width: '100%', justifyContent: 'flex-end', marginTop: 12 }}>
<Button onClick={onClose} type="link">
{' '}
Cancel{' '}
</Button>
<Button onClick={() => onComplete({ alias, regex })} type="primary">
{' '}
Save{' '}
</Button>
</Row>
</Col>
</div>
)
}
Example #12
Source File: ToSketchLayout.tsx From html2sketch with MIT License | 5 votes |
ToSketchLayout: FC<FooterProps> = ({ elements, children, buttons }) => {
const { sketchJSON, generateGroup, generateSymbol } = useSketchJSON();
const [showJSON, setShowJSON] = useState(false);
return (
<div>
{children}
<Divider dashed />
<Row style={{ zIndex: 99999 }}>
<Col span={24}>
<Row justify="space-between">
<Col>
<Button
disabled={!sketchJSON}
onClick={() => {
setShowJSON(!showJSON);
}}
>
{showJSON ? '隐藏' : '显示'} JSON
</Button>
</Col>
<Col>
<Space>
{buttons?.map((button) => (
<Button key={button.name} onClick={button.onClick}>
{button.name}
</Button>
))}
<Button
onClick={() => {
generateGroup(elements);
}}
>
转换为 Group
</Button>
<Button
type="primary"
onClick={() => {
generateSymbol(elements);
}}
>
转换为 Symbol
</Button>
</Space>
</Col>
</Row>
</Col>
{showJSON ? (
<Col span={24}>
<Card>
<ReactJson name="Sketch JSON" src={sketchJSON || {}} />
</Card>
</Col>
) : null}
</Row>
</div>
);
}
Example #13
Source File: AppBar.tsx From next-basics with GNU General Public License v3.0 | 5 votes |
export function AppBar({
pageTitle,
breadcrumb,
documentId,
noCurrentApp,
}: AppBarProps): React.ReactElement {
const hideLaunchpadButton = React.useMemo(
() => getRuntime().getFeatureFlags()["hide-launchpad-button"],
[]
);
const licenseInfoEnabled = React.useMemo(
() => getRuntime().getFeatureFlags()["license-expires-detection"],
[]
);
React.useEffect(() => {
const baseTitle = getRuntime().getBrandSettings().base_title;
document.title = pageTitle ? `${pageTitle} - ${baseTitle}` : baseTitle;
}, [pageTitle]);
const username = getAuth().username;
React.useEffect(() => {
(async () => {
if (licenseInfoEnabled && username) {
try {
const { expires, updating } = await CustomerApi_getExpiration();
// org 为延期中的不提示
!updating && processLiscenseExpires(expires);
} catch (error) {
// eslint-disable-next-line no-empty
}
}
})();
}, [username]);
return (
<div className={styles.appBar} id="app-bar">
<div className={styles.titleContainer}>
{!hideLaunchpadButton && (
<>
<LaunchpadButton />
<Divider
type="vertical"
style={{ height: 24, margin: "0 16px", top: 0 }}
/>
</>
)}
<AppBarBreadcrumb breadcrumb={breadcrumb} noCurrentApp={noCurrentApp} />
</div>
<div className={styles.actionsContainer}>
<AppDocumentLink documentId={documentId} />
<AppSetting />
</div>
</div>
);
}
Example #14
Source File: index.tsx From erda-ui with GNU Affero General Public License v3.0 | 5 votes |
function renderActions<T extends object = any>(actions?: IActions<T>): Array<ColumnProps<T>> {
if (actions) {
const { width, render, limitNum } = actions;
return [
{
title: i18n.t('Operations'),
width,
dataIndex: 'operation',
ellipsis: true,
fixed: 'right',
render: (_: any, record: T) => {
const list = render(record);
const menu = (limitNum || limitNum === 0) && (
<Menu>
{list.slice(limitNum).map((item) => (
<Menu.Item key={item.title} onClick={item.onClick}>
<span className="fake-link mr-1">{item.title}</span>
</Menu.Item>
))}
</Menu>
);
return (
<span className="operate-list">
{list.slice(0, limitNum).map((item, index: number) => (
<>
{index !== 0 && <Divider type="vertical" />}
<span className="fake-link mr-1 align-middle" key={item.title} onClick={item.onClick}>
{item.title}
</span>
</>
))}
{menu && (
<Dropdown overlay={menu} align={{ offset: [0, 5] }}>
<Icon />
</Dropdown>
)}
</span>
);
},
},
];
} else {
return [];
}
}
Example #15
Source File: Button.tsx From slim with Apache License 2.0 | 5 votes |
render (): React.ReactNode {
const Icon = this.props.icon
if (Icon === undefined) {
return null
}
let text
if (this.props.label != null) {
text = (
<>
<Divider type='vertical' />
{this.props.label}
</>
)
}
let button
if (this.props.isSelected ?? false) {
button = (
<Btn
onClick={this.handleClick}
icon={<Icon />}
type='primary'
style={{ lineHeight: '1.0' }}
>
{text}
</Btn>
)
} else {
button = (
<Btn
onClick={this.handleClick}
icon={<Icon />}
type='default'
style={{ lineHeight: '1.0' }}
>
{text}
</Btn>
)
}
if (this.props.tooltip !== undefined) {
return (
<Tooltip title={this.props.tooltip}>
{button}
</Tooltip>
)
} else {
return button
}
}
Example #16
Source File: index.tsx From jetlinks-ui-antd with MIT License | 5 votes |
FunctionDebug: React.FC<Props> = props => {
const { item } = props;
const initState: State = {
debugData: "",
logs: "",
};
const [debugData, setDebugData] = useState(initState.debugData);
const [logs, setLogs] = useState(initState.logs);
const debugMqttClient = () => {
apis.deviceInstance
.invokedFunction(props.deviceId, props.type,JSON.parse(debugData))
.then(response => {
const tempResult = response?.result;
if (response.status === 200) {
setLogs(tempResult);
}else{
setLogs("调试错误");
}
}).catch(() => {
setLogs(`调试错误`);
});
};
return (
<Modal
visible
width={840}
title={item.name}
onCancel={() => props.close()}
footer={
<Fragment>
<Button
type="primary"
onClick={() => {
debugMqttClient();
}}
>
执行
</Button>
<Divider type="vertical" />
<Button type="ghost" onClick={() => setLogs('')}>
清空
</Button>
</Fragment>
}
>
<Form labelCol={{ span: 2 }} wrapperCol={{ span: 22 }}>
<Form.Item label="参数:">
<Input.TextArea
rows={4}
value={debugData}
onChange={e => {
setDebugData(e.target.value);
}}
placeholder="参数必须JSON格式"
/>
</Form.Item>
<Divider>调试日志</Divider>
<Input.TextArea rows={4} value={logs} />
</Form>
</Modal>
);
}
Example #17
Source File: index.tsx From tinyhouse with MIT License | 5 votes |
export function ListingBookings({
listingBookings,
bookingsPage,
limit,
setBookingsPage,
}: ListingBookingsProps) {
const total = listingBookings ? listingBookings.total : null;
const result = listingBookings ? listingBookings.result : null;
const listingBookingsList = listingBookings ? (
<List
grid={{
gutter: 8,
xs: 1,
sm: 2,
lg: 3,
}}
dataSource={result ? result : undefined}
locale={{ emptyText: "No bookings have been made yet!" }}
pagination={{
current: bookingsPage,
total: total ? total : undefined,
defaultPageSize: limit,
hideOnSinglePage: true,
showLessItems: true,
onChange: (page: number) => setBookingsPage(page),
}}
renderItem={(listingBooking) => {
const bookingHistory = (
<div className="listing-bookings__history">
<div>
Check in:{" "}
<Text strong>{listingBooking.checkIn}</Text>
</div>
<div>
Check out:{" "}
<Text strong>{listingBooking.checkOut}</Text>
</div>
</div>
);
return (
<List.Item className="listing-bookings__item">
{bookingHistory}
<Link to={`/user/${listingBooking.tenant.id}`}>
<Avatar
src={listingBooking.tenant.avatar}
size={64}
shape="square"
/>
</Link>
</List.Item>
);
}}
/>
) : null;
const listingBookingsElement = listingBookingsList ? (
<div className="listing-bookings">
<Divider />
<div className="listing-bookings__section">
<Title level={4}>Bookings</Title>
</div>
{listingBookingsList}
</div>
) : null;
return listingBookingsElement;
}
Example #18
Source File: index.tsx From metaplex with Apache License 2.0 | 5 votes |
AdminView = () => {
const { store, whitelistedCreatorsByCreator, isLoading } = useMeta();
const connection = useConnection();
const wallet = useWallet();
const { setVisible } = useWalletModal();
const connect = useCallback(
() => (wallet.wallet ? wallet.connect().catch() : setVisible(true)),
[wallet.wallet, wallet.connect, setVisible],
);
const { storeAddress, setStoreForOwner, isConfigured } = useStore();
useEffect(() => {
if (
!store &&
!storeAddress &&
wallet.publicKey &&
!process.env.NEXT_PUBLIC_STORE_OWNER_ADDRESS
) {
setStoreForOwner(wallet.publicKey.toBase58());
}
}, [store, storeAddress, wallet.publicKey]);
console.log('@admin', wallet.connected, storeAddress, isLoading, store);
return (
<>
{!wallet.connected ? (
<p>
<Button type="primary" className="app-btn" onClick={connect}>
Connect
</Button>{' '}
to admin store.
</p>
) : !storeAddress || isLoading ? (
<Spin />
) : store && wallet ? (
<>
<InnerAdminView
store={store}
whitelistedCreatorsByCreator={whitelistedCreatorsByCreator}
connection={connection}
wallet={wallet}
connected={wallet.connected}
/>
{!isConfigured && (
<>
<Divider />
<Divider />
<p>
To finish initialization please copy config below into{' '}
<b>packages/web/.env</b> and restart yarn or redeploy
</p>
<SetupVariables
storeAddress={storeAddress}
storeOwnerAddress={wallet.publicKey?.toBase58()}
/>
</>
)}
</>
) : (
<>
<p>Store is not initialized</p>
<Link to={`/`}>Go to initialize</Link>
</>
)}
</>
);
}
Example #19
Source File: Item.tsx From tailchat with GNU General Public License v3.0 | 5 votes |
/**
* 构造聊天项
*/
export function buildMessageItemRow(
messages: ChatMessage[],
messageId: string
) {
const index = findMessageIndexWithId(messages, messageId); // TODO: 这里是因为mattermost的动态列表传的id因此只能这边再用id找回,可以看看是否可以优化
if (index === -1) {
return <div />;
}
const message = messages[index];
let showDate = true;
let showAvatar = true;
const messageCreatedAt = new Date(message.createdAt ?? '');
if (index > 0) {
// 当不是第一条数据时
// 进行时间合并
const prevMessage = messages[index - 1];
if (
!shouldShowMessageTime(
new Date(prevMessage.createdAt ?? ''),
messageCreatedAt
)
) {
showDate = false;
}
// 进行头像合并(在同一时间块下 且发送者为同一人)
if (showDate === false) {
showAvatar =
prevMessage.author !== message.author || prevMessage.hasRecall === true;
}
}
return (
<div key={message._id}>
{showDate && (
<Divider className="text-sm opacity-40 px-6 font-normal select-text">
{getMessageTimeDiff(messageCreatedAt)}
</Divider>
)}
<ChatMessageItem showAvatar={showAvatar} payload={message} />
</div>
);
}
Example #20
Source File: index.tsx From fe-v5 with Apache License 2.0 | 5 votes |
index = (_props: any) => {
const history = useHistory();
const { t, i18n } = useTranslation();
const [query, setQuery] = useState('');
const [mine, setMine] = useState(true);
const [days, setDays] = useState(7);
const { curBusiItem } = useSelector<RootState, CommonStoreState>((state) => state.common);
const { tableProps } = useAntdTable((options) => getTableData(options, curBusiItem.id, query, mine, days), { refreshDeps: [curBusiItem.id, query, mine, days] });
const columns: ColumnProps<DataItem>[] = [
{
title: 'ID',
dataIndex: 'id',
width: 100,
},
{
title: t('task.title'),
dataIndex: 'title',
width: 200,
render: (text, record) => {
return <Link to={{ pathname: `/job-tasks/${record.id}/result` }}>{text}</Link>;
},
},
{
title: t('table.operations'),
width: 150,
render: (_text, record) => {
return (
<span>
<Link to={{ pathname: '/job-tasks/add', search: `task=${record.id}` }}>{t('task.clone')}</Link>
<Divider type='vertical' />
<Link to={{ pathname: `/job-tasks/${record.id}/detail` }}>{t('task.meta')}</Link>
</span>
);
},
},
{
title: t('task.creator'),
dataIndex: 'create_by',
width: 100,
},
{
title: t('task.created'),
dataIndex: 'create_at',
width: 160,
render: (text) => {
return moment.unix(text).format('YYYY-MM-DD HH:mm:ss');
},
},
];
return (
<PageLayout
hideCluster
title={
<>
<CodeOutlined />
{t('执行历史')}
</>
}
>
<div style={{ display: 'flex' }}>
<LeftTree></LeftTree>
{curBusiItem.id ? (
<div style={{ flex: 1, padding: 10 }}>
<Row>
<Col span={16} className='mb10'>
<Input
style={{ width: 200, marginRight: 10 }}
prefix={<SearchOutlined />}
defaultValue={query}
onPressEnter={(e) => {
setQuery(e.currentTarget.value);
}}
placeholder='搜索标题'
/>
<Select
style={{ marginRight: 10 }}
value={days}
onChange={(val: number) => {
setDays(val);
}}
>
<Select.Option value={7}>{t('last.7.days')}</Select.Option>
<Select.Option value={15}>{t('last.15.days')}</Select.Option>
<Select.Option value={30}>{t('last.30.days')}</Select.Option>
<Select.Option value={60}>{t('last.60.days')}</Select.Option>
<Select.Option value={90}>{t('last.90.days')}</Select.Option>
</Select>
<Checkbox
checked={mine}
onChange={(e) => {
setMine(e.target.checked);
}}
>
{t('task.only.mine')}
</Checkbox>
</Col>
<Col span={8} style={{ textAlign: 'right' }}>
<Button
type='primary'
ghost
onClick={() => {
history.push('/job-tasks/add');
}}
>
{t('task.temporary.create')}
</Button>
</Col>
</Row>
<Table
rowKey='id'
columns={columns as any}
{...(tableProps as any)}
pagination={
{
...tableProps.pagination,
showSizeChanger: true,
pageSizeOptions: ['10', '50', '100', '500', '1000'],
showTotal: (total) => {
return i18n.language == 'en' ? `Total ${total} items` : `共 ${total} 条`;
},
} as any
}
/>
</div>
) : (
<BlankBusinessPlaceholder text={t('执行历史')}></BlankBusinessPlaceholder>
)}
</div>
</PageLayout>
);
}
Example #21
Source File: index.tsx From Aragorn with MIT License | 5 votes |
Profile = () => {
const {
state: {
uploaderProfiles,
configuration: { defaultUploaderProfileId }
}
} = useAppContext();
const { id } = useParams<{ id: string }>();
const [curUploaderProfileId, setCurUploaderProfileId] = useState('');
const uploaderProfileFormRef = useRef({} as UploaderProfileFormHandle);
useEffect(() => {
const currentId = id || (defaultUploaderProfileId as string);
handleUploaderProfileChange(currentId);
}, []);
const handleUploaderProfileChange = (id: string) => {
setCurUploaderProfileId(id);
uploaderProfileFormRef.current.handleUploaderProfilesSelect(id);
};
const handleSubmit = () => {
uploaderProfileFormRef.current.handleSubmit();
};
const handleDelete = () => {
uploaderProfileFormRef.current.handleDelete();
};
const handleTest = () => {
uploaderProfileFormRef.current.handleTest();
};
return (
<div className="profile-page">
<header>
<span>上传器配置</span>
<Divider />
</header>
<div className="header-menu">
<Select
style={{ minWidth: 120 }}
value={curUploaderProfileId || '请选择'}
onChange={handleUploaderProfileChange}
>
{uploaderProfiles.map(item => (
<Select.Option key={item.name} value={item.id}>
{item.name}
</Select.Option>
))}
</Select>
</div>
<main>
<UploaderProfileForm ref={uploaderProfileFormRef} />
</main>
<footer>
<Divider />
<Space>
<Button type="primary" onClick={handleSubmit}>
更新配置
</Button>
<Button danger onClick={handleDelete}>
删除
</Button>
<Button onClick={handleTest}>测试</Button>
</Space>
</footer>
</div>
);
}
Example #22
Source File: palette.tsx From jmix-frontend with Apache License 2.0 | 4 votes |
palette = () => (
<Palette>
<Category name="Text">
<Component name="Formatted Message">
<Variant>
<FormattedMessage />
</Variant>
</Component>
<Component name="Heading">
<Variant name="h1">
<Typography.Title></Typography.Title>
</Variant>
<Variant name="h2">
<Typography.Title level={2}></Typography.Title>
</Variant>
<Variant name="h3">
<Typography.Title level={3}></Typography.Title>
</Variant>
<Variant name="h4">
<Typography.Title level={4}></Typography.Title>
</Variant>
<Variant name="h5">
<Typography.Title level={5}></Typography.Title>
</Variant>
</Component>
<Component name="Text">
<Variant>
<Typography.Text></Typography.Text>
</Variant>
<Variant name="Secondary">
<Typography.Text type="secondary"></Typography.Text>
</Variant>
<Variant name="Success">
<Typography.Text type="success"></Typography.Text>
</Variant>
<Variant name="Warning">
<Typography.Text type="warning"></Typography.Text>
</Variant>
<Variant name="Danger">
<Typography.Text type="danger"></Typography.Text>
</Variant>
<Variant name="Disabled">
<Typography.Text disabled></Typography.Text>
</Variant>
</Component>
</Category>
<Category name="Layout">
<Component name="Divider">
<Variant>
<Divider />
</Variant>
</Component>
<Component name="Grid">
<Variant name="Simple Row">
<Row></Row>
</Variant>
<Variant name="Two columns">
<Row>
<Col span={12}></Col>
<Col span={12}></Col>
</Row>
</Variant>
<Variant name="Three columns">
<Row>
<Col span={8}></Col>
<Col span={8}></Col>
<Col span={8}></Col>
</Row>
</Variant>
</Component>
<Component name="Space">
<Variant>
<Space />
</Variant>
<Variant name="Small">
<Space size={"small"} />
</Variant>
<Variant name="Large">
<Space size={"large"} />
</Variant>
</Component>
</Category>
<Category name="Controls">
<Component name="Autocomplete">
<Variant>
<AutoComplete placeholder="input here" />
</Variant>
</Component>
<Component name="Button">
<Variant>
<Button></Button>
</Variant>
<Variant name="Primary">
<Button type="primary"></Button>
</Variant>
<Variant name="Link">
<Button type="link"></Button>
</Variant>
<Variant name="Dropdown">
<Dropdown
trigger={["click"]}
overlay={
<Menu>
<Menu.Item></Menu.Item>
<Menu.Item></Menu.Item>
<Menu.Item></Menu.Item>
</Menu>
}
>
<Button></Button>
</Dropdown>
</Variant>
</Component>
<Component name="Checkbox">
<Variant>
<Checkbox />
</Variant>
</Component>
<Component name="Switch">
<Variant>
<Switch />
</Variant>
</Component>
<Component name="Radio Group">
<Variant>
<Radio.Group>
<Radio value={1}>A</Radio>
<Radio value={2}>B</Radio>
<Radio value={3}>C</Radio>
<Radio value={4}>D</Radio>
</Radio.Group>
</Variant>
<Variant name="Button">
<Radio.Group>
<Radio.Button value={1}>A</Radio.Button>
<Radio.Button value={2}>B</Radio.Button>
<Radio.Button value={3}>C</Radio.Button>
<Radio.Button value={4}>D</Radio.Button>
</Radio.Group>
</Variant>
</Component>
<Component name="DatePicker">
<Variant>
<DatePicker />
</Variant>
<Variant name="Range">
<DatePicker.RangePicker />
</Variant>
</Component>
<Component name="TimePicker">
<Variant>
<TimePicker />
</Variant>
<Variant name="Range">
<TimePicker.RangePicker />
</Variant>
</Component>
<Component name="Input">
<Variant>
<Input />
</Variant>
<Variant name="Number">
<InputNumber />
</Variant>
</Component>
<Component name="Select">
<Variant>
<Select defaultValue="1">
<Select.Option value="1">1</Select.Option>
<Select.Option value="2">2</Select.Option>
</Select>
</Variant>
<Variant name="Multiple">
<Select defaultValue={["1"]} mode="multiple" allowClear>
<Select.Option value="1">1</Select.Option>
<Select.Option value="2">2</Select.Option>
</Select>
</Variant>
</Component>
<Component name="Link">
<Variant>
<Typography.Link href="" target="_blank"></Typography.Link>
</Variant>
</Component>
<Component name="Slider">
<Variant>
<Slider defaultValue={30} />
</Variant>
<Variant name="Range">
<Slider range defaultValue={[20, 50]} />
</Variant>
</Component>
</Category>
<Category name="Data Display">
<Component name="Field">
<Variant>
<Field
entityName={ENTITY_NAME}
disabled={readOnlyMode}
propertyName=""
formItemProps={{
style: { marginBottom: "12px" }
}}
/>
</Variant>
</Component>
<Component name="Card">
<Variant>
<Card />
</Variant>
<Variant name="With Title">
<Card>
<Card title="Card title">
<p>Card content</p>
</Card>
</Card>
</Variant>
<Variant name="My custom card">
<Card>
<Card title="Card title">
<p>Card content</p>
<Avatar />
</Card>
</Card>
</Variant>
</Component>
<Component name="Tabs">
<Variant>
<Tabs defaultActiveKey="1">
<Tabs.TabPane tab="Tab 1" key="1">
Content of Tab Pane 1
</Tabs.TabPane>
<Tabs.TabPane tab="Tab 2" key="2">
Content of Tab Pane 2
</Tabs.TabPane>
<Tabs.TabPane tab="Tab 3" key="3">
Content of Tab Pane 3
</Tabs.TabPane>
</Tabs>
</Variant>
<Variant name="Tab Pane">
<Tabs.TabPane></Tabs.TabPane>
</Variant>
</Component>
<Component name="Collapse">
<Variant>
<Collapse defaultActiveKey="1">
<Collapse.Panel
header="This is panel header 1"
key="1"
></Collapse.Panel>
<Collapse.Panel
header="This is panel header 2"
key="2"
></Collapse.Panel>
<Collapse.Panel
header="This is panel header 3"
key="3"
></Collapse.Panel>
</Collapse>
</Variant>
</Component>
<Component name="Image">
<Variant>
<Image width={200} src="" />
</Variant>
</Component>
<Component name="Avatar">
<Variant>
<Avatar icon={<UserOutlined />} />
</Variant>
<Variant name="Image">
<Avatar src="https://joeschmoe.io/api/v1/random" />
</Variant>
</Component>
<Component name="Badge">
<Variant>
<Badge count={1}></Badge>
</Variant>
</Component>
<Component name="Statistic">
<Variant>
<Statistic title="Title" value={112893} />
</Variant>
</Component>
<Component name="Alert">
<Variant name="Success">
<Alert message="Text" type="success" />
</Variant>
<Variant name="Info">
<Alert message="Text" type="info" />
</Variant>
<Variant name="Warning">
<Alert message="Text" type="warning" />
</Variant>
<Variant name="Error">
<Alert message="Text" type="error" />
</Variant>
</Component>
<Component name="List">
<Variant>
<List
bordered
dataSource={[]}
renderItem={item => <List.Item></List.Item>}
/>
</Variant>
</Component>
</Category>
<Category name="Icons">
<Component name="Arrow">
<Variant name="Up">
<ArrowUpOutlined />
</Variant>
<Variant name="Down">
<ArrowDownOutlined />
</Variant>
<Variant name="Left">
<ArrowLeftOutlined />
</Variant>
<Variant name="Right">
<ArrowRightOutlined />
</Variant>
</Component>
<Component name="Question">
<Variant>
<QuestionOutlined />
</Variant>
<Variant name="Circle">
<QuestionCircleOutlined />
</Variant>
</Component>
<Component name="Plus">
<Variant>
<PlusOutlined />
</Variant>
<Variant name="Circle">
<PlusCircleOutlined />
</Variant>
</Component>
<Component name="Info">
<Variant>
<InfoOutlined />
</Variant>
<Variant name="Circle">
<InfoCircleOutlined />
</Variant>
</Component>
<Component name="Exclamation">
<Variant>
<ExclamationOutlined />
</Variant>
<Variant name="Circle">
<ExclamationCircleOutlined />
</Variant>
</Component>
<Component name="Close">
<Variant>
<CloseOutlined />
</Variant>
<Variant name="Circle">
<CloseCircleOutlined />
</Variant>
</Component>
<Component name="Check">
<Variant>
<CheckOutlined />
</Variant>
<Variant name="Circle">
<CheckCircleOutlined />
</Variant>
</Component>
<Component name="Edit">
<Variant>
<EditOutlined />
</Variant>
</Component>
<Component name="Copy">
<Variant>
<CopyOutlined />
</Variant>
</Component>
<Component name="Delete">
<Variant>
<DeleteOutlined />
</Variant>
</Component>
<Component name="Bars">
<Variant>
<BarsOutlined />
</Variant>
</Component>
<Component name="Bell">
<Variant>
<BellOutlined />
</Variant>
</Component>
<Component name="Clear">
<Variant>
<ClearOutlined />
</Variant>
</Component>
<Component name="Download">
<Variant>
<DownloadOutlined />
</Variant>
</Component>
<Component name="Upload">
<Variant>
<UploadOutlined />
</Variant>
</Component>
<Component name="Sync">
<Variant>
<SyncOutlined />
</Variant>
</Component>
<Component name="Save">
<Variant>
<SaveOutlined />
</Variant>
</Component>
<Component name="Search">
<Variant>
<SearchOutlined />
</Variant>
</Component>
<Component name="Settings">
<Variant>
<SettingOutlined />
</Variant>
</Component>
<Component name="Paperclip">
<Variant>
<PaperClipOutlined />
</Variant>
</Component>
<Component name="Phone">
<Variant>
<PhoneOutlined />
</Variant>
</Component>
<Component name="Mail">
<Variant>
<MailOutlined />
</Variant>
</Component>
<Component name="Home">
<Variant>
<HomeOutlined />
</Variant>
</Component>
<Component name="Contacts">
<Variant>
<ContactsOutlined />
</Variant>
</Component>
<Component name="User">
<Variant>
<UserOutlined />
</Variant>
<Variant name="Add">
<UserAddOutlined />
</Variant>
<Variant name="Remove">
<UserDeleteOutlined />
</Variant>
</Component>
<Component name="Team">
<Variant>
<TeamOutlined />
</Variant>
</Component>
</Category>
<Category name="Screens">
<Component name="ExampleCustomScreen">
<Variant>
<ExampleCustomScreen />
</Variant>
</Component>
<Component name="CustomEntityFilterTest">
<Variant>
<CustomEntityFilterTest />
</Variant>
</Component>
<Component name="CustomFormControls">
<Variant>
<CustomFormControls />
</Variant>
</Component>
<Component name="CustomDataDisplayComponents">
<Variant>
<CustomDataDisplayComponents />
</Variant>
</Component>
<Component name="CustomAppLayouts">
<Variant>
<CustomAppLayouts />
</Variant>
</Component>
<Component name="CustomControls">
<Variant>
<CustomControls />
</Variant>
</Component>
<Component name="ErrorBoundaryTests">
<Variant>
<ErrorBoundaryTests />
</Variant>
</Component>
<Component name="TestBlankScreen">
<Variant>
<TestBlankScreen />
</Variant>
</Component>
<Component name="CarEditor">
<Variant>
<CarEditor />
</Variant>
</Component>
<Component name="CarBrowserCards">
<Variant>
<CarBrowserCards />
</Variant>
</Component>
<Component name="CarBrowserList">
<Variant>
<CarBrowserList />
</Variant>
</Component>
<Component name="CarBrowserTable">
<Variant>
<CarBrowserTable />
</Variant>
</Component>
<Component name="CarCardsGrid">
<Variant>
<CarCardsGrid />
</Variant>
</Component>
<Component name="FavoriteCars">
<Variant>
<FavoriteCars />
</Variant>
</Component>
<Component name="CarCardsWithDetails">
<Variant>
<CarCardsWithDetails />
</Variant>
</Component>
<Component name="CarTableWithFilters">
<Variant>
<CarTableWithFilters />
</Variant>
</Component>
<Component name="CarMasterDetail">
<Variant>
<CarMasterDetail />
</Variant>
</Component>
<Component name="FormWizardCompositionO2O">
<Variant>
<FormWizardCompositionO2O />
</Variant>
</Component>
<Component name="FormWizardEditor">
<Variant>
<FormWizardEditor />
</Variant>
</Component>
<Component name="FormWizardBrowserTable">
<Variant>
<FormWizardBrowserTable />
</Variant>
</Component>
<Component name="CarMultiSelectionTable">
<Variant>
<CarMultiSelectionTable />
</Variant>
</Component>
<Component name="DatatypesTestEditor">
<Variant>
<DatatypesTestEditor />
</Variant>
</Component>
<Component name="DatatypesTestBrowserCards">
<Variant>
<DatatypesTestBrowserCards />
</Variant>
</Component>
<Component name="DatatypesTestBrowserList">
<Variant>
<DatatypesTestBrowserList />
</Variant>
</Component>
<Component name="DatatypesTestBrowserTable">
<Variant>
<DatatypesTestBrowserTable />
</Variant>
</Component>
<Component name="DatatypesTestCards">
<Variant>
<DatatypesTestCards />
</Variant>
</Component>
<Component name="AssociationO2OEditor">
<Variant>
<AssociationO2OEditor />
</Variant>
</Component>
<Component name="AssociationO2OBrowserTable">
<Variant>
<AssociationO2OBrowserTable />
</Variant>
</Component>
<Component name="AssociationO2MEditor">
<Variant>
<AssociationO2MEditor />
</Variant>
</Component>
<Component name="AssociationO2MBrowserTable">
<Variant>
<AssociationO2MBrowserTable />
</Variant>
</Component>
<Component name="AssociationM2OEditor">
<Variant>
<AssociationM2OEditor />
</Variant>
</Component>
<Component name="AssociationM2OBrowserTable">
<Variant>
<AssociationM2OBrowserTable />
</Variant>
</Component>
<Component name="AssociationM2MEditor">
<Variant>
<AssociationM2MEditor />
</Variant>
</Component>
<Component name="AssociationM2MBrowserTable">
<Variant>
<AssociationM2MBrowserTable />
</Variant>
</Component>
<Component name="CompositionO2OEditor">
<Variant>
<CompositionO2OEditor />
</Variant>
</Component>
<Component name="CompositionO2OBrowserTable">
<Variant>
<CompositionO2OBrowserTable />
</Variant>
</Component>
<Component name="CompositionO2MEditor">
<Variant>
<CompositionO2MEditor />
</Variant>
</Component>
<Component name="CompositionO2MBrowserTable">
<Variant>
<CompositionO2MBrowserTable />
</Variant>
</Component>
<Component name="DeeplyNestedTestEntityEditor">
<Variant>
<DeeplyNestedTestEntityEditor />
</Variant>
</Component>
<Component name="DeeplyNestedO2MTestEntityTable">
<Variant>
<DeeplyNestedO2MTestEntityTable />
</Variant>
</Component>
<Component name="DeeplyNestedO2MTestEntityEditor">
<Variant>
<DeeplyNestedO2MTestEntityEditor />
</Variant>
</Component>
<Component name="IntIdEditor">
<Variant>
<IntIdEditor />
</Variant>
</Component>
<Component name="IntIdBrowserTable">
<Variant>
<IntIdBrowserTable />
</Variant>
</Component>
<Component name="IntIdBrowserCards">
<Variant>
<IntIdBrowserCards />
</Variant>
</Component>
<Component name="IntIdBrowserList">
<Variant>
<IntIdBrowserList />
</Variant>
</Component>
<Component name="IntIdentityIdCards">
<Variant>
<IntIdentityIdCards />
</Variant>
</Component>
<Component name="IntIdentityIdEditor">
<Variant>
<IntIdentityIdEditor />
</Variant>
</Component>
<Component name="IntIdentityIdBrowserTable">
<Variant>
<IntIdentityIdBrowserTable />
</Variant>
</Component>
<Component name="IntIdentityIdBrowserCards">
<Variant>
<IntIdentityIdBrowserCards />
</Variant>
</Component>
<Component name="IntIdentityIdBrowserList">
<Variant>
<IntIdentityIdBrowserList />
</Variant>
</Component>
<Component name="StringIdCards">
<Variant>
<StringIdCards />
</Variant>
</Component>
<Component name="StringIdMgtCardsEdit">
<Variant>
<StringIdMgtCardsEdit />
</Variant>
</Component>
<Component name="StringIdBrowserCards">
<Variant>
<StringIdBrowserCards />
</Variant>
</Component>
<Component name="StringIdBrowserList">
<Variant>
<StringIdBrowserList />
</Variant>
</Component>
<Component name="StringIdBrowserTable">
<Variant>
<StringIdBrowserTable />
</Variant>
</Component>
<Component name="WeirdStringIdEditor">
<Variant>
<WeirdStringIdEditor />
</Variant>
</Component>
<Component name="WeirdStringIdBrowserCards">
<Variant>
<WeirdStringIdBrowserCards />
</Variant>
</Component>
<Component name="WeirdStringIdBrowserList">
<Variant>
<WeirdStringIdBrowserList />
</Variant>
</Component>
<Component name="WeirdStringIdBrowserTable">
<Variant>
<WeirdStringIdBrowserTable />
</Variant>
</Component>
<Component name="BoringStringIdEditor">
<Variant>
<BoringStringIdEditor />
</Variant>
</Component>
<Component name="BoringStringIdBrowserTable">
<Variant>
<BoringStringIdBrowserTable />
</Variant>
</Component>
<Component name="TrickyIdEditor">
<Variant>
<TrickyIdEditor />
</Variant>
</Component>
<Component name="TrickyIdBrowserTable">
<Variant>
<TrickyIdBrowserTable />
</Variant>
</Component>
</Category>
</Palette>
)
Example #23
Source File: Cart.tsx From Shopping-Cart with MIT License | 4 votes |
Cart = () => {
const dispatch = useDispatch();
const { isLoading, items } = useSelector(cartedProductSelector);
const { tableDataSource, recommend } = useSelector(
paymentCartedProductSelector,
);
useEffect(() => {
if (storageService.getItem('cart-class101')) {
dispatch(
fetchCartedProductListAsync.request({
productIdList: JSON.parse(
storageService.getItem('cart-class101') as string,
),
}),
);
dispatch(fetchPaymentCartedProductListAsync.request({ id: [] }));
}
}, [storageService.getItem]);
const handleCartTableClick = useCallback(() => {
storageService.removeItem('cart-class101');
dispatch(fetchCartedProductListAsync.request({}));
}, [storageService.removeItem]);
const handleCartTableChange = useCallback(
(id: ProductModel['id'], quantity: number) => {
dispatch(fetchCartedProductListEditAsync.request({ id, quantity }));
},
[dispatch],
);
const handleSelectChange = useCallback(
(selectedRowKeys: any, selectedRows: any) => {
// antd에서 타입을 any로 해놔서 일단, any로 받음. 나머지 로직에서 타입 체크를 차라리 제대로 하자.
dispatch(
fetchPaymentCartedProductListAsync.request({
id: selectedRowKeys as ProductModel['id'][], // 다른 곳에서라도 타입을 정확하게 판단하기 위해 강제 어썰션
ProductModelList: selectedRows as ProductModel[],
}),
);
},
[dispatch],
);
const handlePaymentClick = useCallback(() => {
InfoModal('error', '경고', '결제는 안되요~');
}, [InfoModal]);
if (isLoading && !items) {
return <LoadingSpin />;
}
return (
<>
<Row>
<Col span={24}>
<PageTitle title="장바구니" />
</Col>
</Row>
<Row style={{ marginBottom: 50 }}>
<CartTable
dataSource={items}
onClick={handleCartTableClick}
onChange={handleCartTableChange}
onSelectChange={handleSelectChange}
/>
</Row>
<Row>
<Divider orientation="left">최종 결제 금액</Divider>
<CartFinalPriceTable
dataSource={tableDataSource}
recommend={recommend}
/>
<Divider />
</Row>
<Row style={{ textAlign: 'right' }}>
<NavLink to={PRODUCTS_LIST_PATH}>
<Button size="large" style={{ marginRight: 8 }}>
뒤로 가기
</Button>
</NavLink>
<Button
type="danger"
size="large"
style={{ marginRight: 6 }}
disabled={!tableDataSource.totalPrice}
onClick={handlePaymentClick}
>
결제하기
</Button>
</Row>
</>
);
}
Example #24
Source File: Cohort.tsx From posthog-foss with MIT License | 4 votes |
export function Cohort(props: { cohort: CohortType }): JSX.Element {
const logic = cohortLogic(props)
const { setCohort } = useActions(logic)
const { cohort, submitted } = useValues(logic)
const { hasAvailableFeature } = useValues(userLogic)
const onDescriptionChange = (description: string): void => {
setCohort({
...cohort,
description,
})
}
const onTypeChange = (type: string): void => {
if (type === COHORT_STATIC) {
setCohort({
...cohort,
is_static: true,
})
} else if (type === COHORT_DYNAMIC) {
setCohort({
...cohort,
is_static: false,
})
}
}
const staticCSVDraggerProps = {
name: 'file',
multiple: false,
fileList: cohort.csv ? [cohort.csv] : [],
beforeUpload(file: UploadFile) {
setCohort({ ...cohort, csv: file })
return false
},
accept: '.csv',
}
const COHORT_TYPE_OPTIONS = [
{
key: COHORT_STATIC,
label: 'Static',
description: 'Upload a list of users. Updates manually',
icon: <OrderedListOutlined />,
},
{
key: COHORT_DYNAMIC,
label: 'Dynamic',
description: 'Cohort updates dynamically based on properties',
icon: <CalculatorOutlined />,
},
]
const cohortTypeDropdown = (): JSX.Element => (
<DropdownSelector
options={COHORT_TYPE_OPTIONS}
disabled={cohort.id !== 'new'}
value={cohort.is_static ? COHORT_STATIC : COHORT_DYNAMIC}
onValueChange={onTypeChange}
/>
)
return (
<div className="mb">
<Row gutter={16}>
<Col>
<h3 className="l3">General</h3>
</Col>
</Row>
<Row gutter={16}>
<Col md={14}>
<CohortNameInput input={cohort.name} onChange={(name: string) => setCohort({ ...cohort, name })} />
</Col>
<Col md={10}>
{cohort.id === 'new' ? (
cohortTypeDropdown()
) : (
<Tooltip title="Create a new cohort to use a different type of cohort.">
<div>{cohortTypeDropdown()}</div>
</Tooltip>
)}
</Col>
</Row>
{hasAvailableFeature(AvailableFeature.DASHBOARD_COLLABORATION) && (
<Row gutter={16} className="mt">
<Col span={24}>
<CohortDescriptionInput description={cohort.description} onChange={onDescriptionChange} />
</Col>
</Row>
)}
{cohort.id && cohort.id !== 'new' && <CohortDetailsRow cohort={cohort} />}
<Divider />
{cohort.is_static ? (
<div>
<h3 className="l3">Add Users</h3>
<span>
Drop a <pre style={{ display: 'inline' }}>.csv</pre> file here to add users to your cohort
</span>
<Dragger {...staticCSVDraggerProps} className="cohort-csv-dragger">
<p className="ant-upload-drag-icon">
<InboxOutlined />
</p>
<div>
<p className="ant-upload-text">Click or drag file to this area to upload</p>
<p className="ant-upload-hint">
The CSV file only requires a single column with the user’s distinct ID.
</p>
{submitted && !cohort.csv && (
<p style={{ color: 'var(--danger)', marginTop: 16 }}>You need to upload a CSV file.</p>
)}
</div>
</Dragger>
</div>
) : (
<CohortMatchingCriteriaSection logic={logic} />
)}
{cohort.id !== 'new' && (
<>
<Divider />
<div>
<h3 className="l3">Matched Users</h3>
<span>List of users that currently match the criteria defined</span>
{cohort.is_calculating ? (
<div className="cohort-recalculating flex-center">
<Spinner size="sm" style={{ marginRight: 4 }} />
We're recalculating who belongs to this cohort. This could take up to a couple of
minutes.
</div>
) : (
<div style={{ marginTop: 15 }}>
<Persons cohort={cohort} />
</div>
)}
</div>
</>
)}
</div>
)
}
Example #25
Source File: Button.tsx From html2sketch with MIT License | 4 votes |
ButtonSymbolDemo: FC = () => {
const [json, setJSON] = useState<object>();
const groupLayout = 'LEFT_TO_RIGHT';
const typeList = [
{ type: 'default' },
{ type: 'primary' },
{ type: 'disabled' },
{ type: 'dashed' },
{ type: 'ghost' },
{ type: 'default', icon: <StepForwardOutlined /> },
{ type: 'primary', icon: <UpCircleOutlined /> },
{ type: 'text' },
{ type: 'link' },
{ type: 'primary', danger: true },
{ type: 'default', danger: true },
{ type: 'dashed', danger: true },
{ type: 'text', danger: true },
];
const buttonList = [
typeList.map((i) => ({ ...i, size: 'default' })),
typeList.map((i) => ({ ...i, size: 'small' })),
typeList.map((i) => ({ ...i, size: 'large' })),
];
const transformFunc = async (
transferFn: (node: Element) => Promise<Object>,
) => {
try {
const els = document.getElementsByClassName('button');
const buttons: Object[] = [];
const list = Array.from(els);
for (let i = 0; i < list.length; i++) {
const sketchBtn = await transferFn(list[i]);
buttons.push(sketchBtn);
}
console.log('-------转换结束--------');
console.log(buttons);
copy(JSON.stringify(buttons));
message.success('转换成功?已复制到剪切板');
setJSON(buttons);
} catch (e) {
message.error('解析失败,配置项可能存在错误!');
console.error(e);
}
};
const actionList: ActionType[] = [
{
text: '转换为 Group',
type: 'default',
onClick: () => {
transformFunc(async (node) => {
return (await nodeToGroup(node)).toSketchJSON();
});
},
},
{
text: '转换为 Symbol',
type: 'primary',
onClick: () => {
transformFunc(async (node) => {
const symbolLayout = node.getAttribute('layout') as GroupLayoutType;
const symbol = await nodeToSketchSymbol(node, {
symbolLayout: symbolLayout || undefined,
handleSymbol: (symbol) => {
symbol.name = node.getAttribute('symbol-name') || 'symbol';
const renameBG = (layer: AnyLayer) => {
if (layer.layers) {
layer.layers.forEach(renameBG);
}
if (layer?.name?.includes('ant-btn')) {
layer.name = '背景';
}
};
symbol.layers.forEach(renameBG);
},
});
return symbol.toSketchJSON();
});
},
},
];
const group = ['默认', '小', '大'];
return (
<div>
<Row>
{buttonList.map((list, sizeIndex) => {
return (
<Fragment key={sizeIndex}>
<Col key={sizeIndex}>
<Space align="start">
<div style={{ width: 32 }}>{group[sizeIndex]}</div>
<Row gutter={[8, 12]}>
{list.map((button, index) => {
const { type, size, danger, icon } = button;
return (
<Col key={index}>
<Button
className="button"
icon={icon}
symbol-name={generateSymbolName({
type,
size,
typeIndex: index + 1,
sizeIndex: sizeIndex + 1,
component: 'button',
componentIndex: 1,
content: 'general',
contentIndex: 1,
suffix: danger ? '-Danger' : undefined,
})}
layout={groupLayout}
// @ts-ignore
type={type}
danger={danger}
disabled={type === 'disabled'}
// @ts-ignore
size={size}
>
文本
</Button>
</Col>
);
})}
</Row>
</Space>
</Col>
{sizeIndex === buttonList.length - 1 ? null : <Divider dashed />}
</Fragment>
);
})}
</Row>
<Footer json={json} actions={actionList} />
</div>
);
}
Example #26
Source File: index.tsx From antdp with MIT License | 4 votes |
QuickForm: QuickFormComponent = (props, ref) => {
const {
collapseAttributes,
panelAttributes,
visible = false,
type = 'cardform',
extra,
formDatas,
colspan = 3,
header,
defaultFormLayout = 'vertical',
defaultFormItemLayout = formDefaultFormItemLayout,
size = 'default',
formHide,
initialHide,
...otherProps
} = props;
const [hide] = useFormItemHide(formHide)
hide.setInitialValues(initialHide || {}, true)
const HideFormItemDoM = []; // 隐藏的表单
const FormItemDoM = [];
let rowcolspan: string | any; // col 里的布局
let formitemlayout: string | any; // formitem 的布局
for (var i = 0; i < formDatas.length; i++) {
if (formDatas[i].hideInForm) {
HideFormItemDoM.push(formDatas[i]);
} else {
FormItemDoM.push(formDatas[i]);
}
}
// 计算一个row里排几个表单;
const result = [];
for (let i = 0, j = FormItemDoM.length; i < j; i++) {
if (FormItemDoM[i].full) {
result.push(FormItemDoM.slice(i, i + 1));
} else {
if (FormItemDoM[i + 1] && FormItemDoM[i + 1].full) {
result.push(FormItemDoM.slice(i, i + 1));
} else if (FormItemDoM[i].defaultcolspan) {
result.push(FormItemDoM.slice(i, i + FormItemDoM[i].defaultcolspan));
i = i + FormItemDoM[i].defaultcolspan - 1;
} else {
result.push(FormItemDoM.slice(i, i + colspan));
i = i + colspan - 1;
}
}
}
// 渲染成表单;
const CollapseFormDoM = (item: any, idx: React.Key | null | undefined) => {
const {
label,
name,
attributes,
type,
options,
onlyimg,
defaultFormItemLayout,
full,
defaultRowColspan,
hideInForm,
descItem,
render,
// 用于判断是否需要进行隐藏显示 (在组件外层包裹一层组件用于控制item显示和隐藏)
isHide,
...otherts
} = item;
const dataList = options || [];
const optionDatas =
dataList &&
dataList.length > 0 &&
dataList.map(
(
{ value, label, ...others }: any,
_idx: React.Key | null | undefined,
) => {
if (type === 'select' || type === 'Select') {
return (
<Option value={value} key={_idx} {...others}>
{label}
</Option>
);
} else if (type === 'radio' || type === 'Radio') {
return (
<Radio.Button value={value} key={_idx} {...others}>
{label}
</Radio.Button>
);
}
},
);
const selectOption = optionDatas ? optionDatas : [];
const rowcolspan_num = [
colLayout_one,
colLayout_two,
colLayout_third,
colLayout_fourth,
];
const formitemlayout_num = [
fromItemLayout_conspan_one,
fromItemLayout_conspan_two,
fromItemLayout_conspan_third,
fromItemLayout_conspan_fourth,
];
if (colspan && full) {
rowcolspan = colLayout_one;
if (colspan === 3 || colspan === 4) {
if (props.defaultFormItemLayout) {
// 如果FormCollapse组件上带有defaulFormItemLayout参数
formitemlayout = props.defaultFormItemLayout;
// eslint-disable-next-line max-depth
if (item.defaultFormItemLayout || item.defaultRowColspan) {
// 如果FormCollapse组件内部的某个小组件带有defaulFormItemLayout参数
formitemlayout = item.defaultFormItemLayout;
rowcolspan = item.defaultRowColspan; // 单独的表单col 布局
}
} else if (item.defaultFormItemLayout || item.defaultRowColspan) {
//FormCollapse组件内部只有某个小组件带了defaulFormItemLayout参数
formitemlayout = item.defaultFormItemLayout;
rowcolspan = item.defaultRowColspan; // 单独的表单col 布局
} else {
formitemlayout = fromItemLayout_third_row;
}
} else {
formitemlayout = fromItemLayout_two_row;
}
} else {
rowcolspan = rowcolspan_num[colspan - 1];
if (props.defaultFormItemLayout) {
formitemlayout = props.defaultFormItemLayout;
if (item.defaultFormItemLayout || item.defaultRowColspan) {
// 如果FormCollapse组件内部的某个小组件带有defaultFormItemLayout参数
formitemlayout = item.defaultFormItemLayout;
rowcolspan = item.defaultRowColspan; // 单独的表单col 布局
}
} else if (item.defaultFormItemLayout || item.defaultRowColspan) {
formitemlayout =
item.defaultFormItemLayout || formitemlayout_num[colspan - 1];
rowcolspan = item.defaultRowColspan; // 单独的表单col 布局
} else {
formitemlayout = formitemlayout_num[colspan - 1];
}
}
// 上传图片的按钮展示
const uploadButtonDom = () => {
if (item.attributes.listType === 'picture-card') {
if (item.attributes.imageUrl && item.attributes.imageUrl !== '') {
return (
<img
src={item.attributes.imageUrl}
alt="avatar"
style={{ width: '100%' }}
/>
);
} else if (item.attributes.fileList) {
// 上传的图片大于或等于8张时 并且 没有onlyimg参数,显示icon上传按钮
if (item.attributes.fileList.length >= 8 && !onlyimg) {
return (
<div>
{item.attributes.loading === 'loading' ? (
<LoadingOutlined />
) : (
<PlusOutlined />
)}
<div className="ant-upload-text">上传</div>
</div>
);
// 上传的图片大于或等于maxCount张时 并且 有onlyimg参数,不显示上传按钮
} else if (item.attributes.maxCount && item.attributes.fileList.length >= item.attributes.maxCount && onlyimg) {
return null;
}
return (
<div>
{item.attributes.loading === 'loading' ? (
<LoadingOutlined />
) : (
<PlusOutlined />
)}
<div className="ant-upload-text">上传</div>
</div>
);
}
} else {
return (
<div>
<Button>
<UploadOutlined />
上传
</Button>
</div>
);
}
};
let renderItem = (
<Col
key={idx}
style={{
display: item.hideInForm ? 'none' : 'block',
padding:
defaultFormLayout && defaultFormLayout === 'vertical'
? '0px 12px 8px 12px'
: '0',
}}
className={
defaultFormLayout && defaultFormLayout === 'vertical'
? 'antdp-FormCol'
: ''
}
{...rowcolspan}
>
<FormItem
className="antdp-FormItem"
colon={false}
label={label}
name={name}
{...(defaultFormLayout && defaultFormLayout === 'vertical'
? null
: formitemlayout)}
{...otherts}
>
{name ? (
(() => {
// 组件基础参数
const componentprams = {
size: size ? size : 'small',
...attributes,
};
if (type === 'select' || type === 'Select') {
return (
<Select
dropdownMatchSelectWidth={false}
allowClear
placeholder={
attributes && attributes.disabled ? '' : `请选择${label} `
}
{...componentprams}
>
{selectOption}
</Select>
);
} else if (type === 'radio' || type === 'Radio') {
return (
<Radio.Group size={size ? size : 'small'} {...attributes}>
{selectOption}
</Radio.Group>
);
} else if (type === 'datePicker' || type === 'DatePicker') {
return (
<DatePicker
locale={locale}
style={{ width: '100%' }}
placeholder={
attributes && attributes.disabled ? '' : `请选择${label} `
}
{...componentprams}
/>
);
} else if (type === 'monthPicker' || type === 'MonthPicker') {
return (
<MonthPicker
locale={locale}
style={{ width: '100%' }}
placeholder={
attributes && attributes.disabled ? '' : `请选择${label} `
}
{...componentprams}
/>
);
} else if (type === 'rangePicker' || type === 'RangePicker') {
return (
<RangePicker
locale={locale}
style={{ width: '100%' }}
{...componentprams}
/>
);
} else if (
type === 'timepicker' ||
type === 'timePicker' ||
type === 'TimePicker'
) {
return (
<TimePicker
locale={locale}
style={{ width: '100%' }}
placeholder={
attributes && attributes.disabled ? '' : `请选择${label} `
}
{...componentprams}
/>
);
} else if (type === 'cascader' || type === 'Cascader') {
return (
<Cascader
placeholder={
attributes && attributes.disabled ? '' : `请选择${label} `
}
{...componentprams}
/>
);
} else if (type === 'textarea' || type === 'TextArea') {
return (
<Input.TextArea
placeholder={
attributes && attributes.disabled ? '' : `请输入${label} `
}
{...componentprams}
/>
);
} else if (type === 'inputNumber' || type === 'InputNumber') {
return (
<InputNumber
placeholder={
attributes && attributes.disabled ? '' : `请输入${label} `
}
style={{ width: '100%' }}
{...componentprams}
/>
);
} else if (type === 'treeSelect' || type === 'TreeSelect') {
return (
<TreeSelect
placeholder={
attributes && attributes.disabled ? '' : `请选择${label} `
}
{...componentprams}
/>
);
} else if (type === 'checkbox' || type === 'Checkbox') {
if (
(item.options && item.options.length > 0) ||
(item.option && item.option.length > 0)
) {
return (
<Checkbox.Group
options={item.options || item.option}
{...attributes}
/>
);
}
return (
<Checkbox {...attributes}>
{label || item.checkboxLable}
</Checkbox>
);
} else if (type === 'UploadGrid' || type === 'uploadGrid') {
return (
<UploadGrid {...attributes}>{uploadButtonDom()}</UploadGrid>
);
} else if (type === 'autoComplete' || type === 'AutoComplete') {
return (
<AutoComplete
placeholder={
attributes && attributes.disabled ? '' : `请输入${label} `
}
{...componentprams}
/>
);
} else if (type === 'Password') {
return (
<Input.Password
placeholder={
attributes && attributes.disabled ? '' : `请输入${label} `
}
{...componentprams}
/>
);
} else if (type === 'inputCount' || type === 'InputCount') {
return (
<InputCount
placeholder={
attributes && attributes.disabled ? '' : `请输入${label} `
}
{...attributes}
/>
);
} else if (type === 'render') {
return render && render
} else {
if (
(attributes && attributes.type === 'Search') ||
type === 'InputSearch'
) {
const suffix = (
<AudioOutlined
style={{
fontSize: 16,
color: '#fff',
}}
/>
);
return (
<Search
suffix={suffix}
placeholder={
attributes && attributes.disabled
? ''
: `请输入${label} `
}
{...componentprams}
/>
);
}
return (
<Input
placeholder={
attributes && attributes.disabled ? '' : `请输入${label} `
}
{...componentprams}
/>
);
}
})()
) : (
<Input
placeholder={
attributes && attributes.disabled ? '' : `请输入${label} `
}
size={size}
{...attributes}
/>
)}
</FormItem>
</Col>
)
if (isHide && name) {
return (
<Hide key={idx} name={name}>
{renderItem}
</Hide>
);
}
return renderItem;
};
// 隐藏的表单集合
const hideCollapseForm = HideFormItemDoM.map((item, idx) =>
CollapseFormDoM(item, idx),
);
// 表单集合
const CollapseForm = result.map((it, indix) => {
return (
<Row key={indix}>
{it.map((item, idx) => {
return CollapseFormDoM(item, idx);
})}
</Row>
);
});
// Form+表单集合
const FormDom = (
<HideContext.Provider value={hide} >
<ConfigProvider locale={zhCN}>
<Form
layout={defaultFormLayout ? defaultFormLayout : 'horizontal'}
ref={ref}
{...(defaultFormLayout && defaultFormLayout === 'vertical'
? null
: formitemlayout)}
{...otherProps}
>
<Row>{hideCollapseForm}</Row>
<div>{CollapseForm}</div>
</Form>
</ConfigProvider>
</HideContext.Provider>
);
// type 为 modal时没有折叠,没有标题,直接显示form表单内容
if (type === 'modal') {
return <div style={{ margin: -10 }}>{FormDom}</div>
}
// type 为CardPro 带标题
if (type === 'CardPro') {
return (
<CardPro title={header}>
<div className="antdp-FormBox">{FormDom}</div>
</CardPro>
);
}
// type 为cardform 时 显示表单,分割线 分离每个表单
if (type === 'cardform') {
return (
<div>
<h3 className="antdp-FormTitle">{header}</h3>
{FormDom}
<Divider type="horizontal" className="antdp-FormDivider" />
</div>
);
}
return (
<Collapse
defaultActiveKey={!visible ? ['1'] : ''}
{...collapseAttributes}
className="antdp-mb10"
>
<Panel header={header} key="1" {...panelAttributes} extra={extra}>
{FormDom}
</Panel>
</Collapse>
);
}
Example #27
Source File: index.tsx From S2 with MIT License | 4 votes |
App = ({ data }) => {
const onIconClick = ({ meta }) => {
setInteractedCol(meta.value);
setColModalVisible(!colModalVisible);
};
const s2Ref = useRef(null);
const [columns, setColumns] = React.useState(initColumns);
const [interactedCol, setInteractedCol] = useState('');
const modalCallbackRef = useRef((e) => {});
const [options, setOptions] = useState({
width: 600,
height: 400,
showSeriesNumber: true,
interaction: {
enableCopy: true,
autoResetSheetStyle: false,
hoverFocus: false,
},
colCell: (item, spreadsheet, headerConfig) => {
if (item.colIndex === 0) {
return new CustomCornerCell(item, spreadsheet, headerConfig);
}
return new CustomTableColCell(
item,
spreadsheet,
headerConfig,
onIconClick,
);
},
customSVGIcons: [
{
name: 'Filter',
svg: filterIcon,
},
{
name: 'SortUp',
svg: sortUp,
},
{
name: 'SortDown',
svg: sortDown,
},
],
tooltip: {
operation: {
hiddenColumns: true,
},
},
showDefaultHeaderActionIcon: false,
});
const [dataCfg, setDataCfg] = useState({
fields: {
columns,
},
data,
sortParams: [],
filterParams: [],
});
useEffect(() => {
setDataCfg((cfg) => ({
...cfg,
fields: { columns },
}));
s2Ref.current.render(true);
}, [columns.length]);
const [searchKey, setSearchKey] = useState('');
const [searchResult, setSearchResult] = useState([]);
const [colModalVisible, setColModalVisible] = useState(false);
const [searchResultActiveIndex, setSearchResultActiveIndex] = useState(-1);
const [form] = Form.useForm();
const allChecked = columns.length === initColumns.length;
const focusNext = (results, currentIndex) => {
const length = results.length;
let nextIndex = currentIndex + 1;
if (nextIndex >= length) {
nextIndex = 0;
}
setSearchResultActiveIndex(nextIndex);
const current = results[nextIndex];
scrollToCell(
current.row,
current.col,
s2Ref.current.options,
s2Ref.current.facet,
s2Ref.current.interaction,
);
};
const focusPrev = (results) => {
const length = results.length;
let nextIndex = searchResultActiveIndex - 1;
if (nextIndex < 0) {
nextIndex = length - 1;
}
setSearchResultActiveIndex(nextIndex);
const current = results[nextIndex];
scrollToCell(
current.row,
current.col,
s2Ref.current.options,
s2Ref.current.facet,
s2Ref.current.interaction,
);
};
const search = (key) => {
let searchData = [];
if (s2Ref.current) {
searchData = s2Ref.current.dataSet.getDisplayDataSet();
}
const results = getSearchResult(key, searchData, columns);
setSearchResult(results);
setSearchResultActiveIndex(-1);
if (results.length > 0) {
focusNext(results, -1);
}
};
return (
<div>
<Space>
<ShowList
columns={columns}
allChecked={allChecked}
setColumns={setColumns}
/>
<Search
placeholder="输入关键词搜索"
allowClear
enterButton="Search"
value={searchKey}
onChange={(e) => {
setSearchKey(e.target.value);
}}
onSearch={(key) => {
search(key);
}}
/>
{searchResult.length ? (
<>
<div>{`${searchResultActiveIndex + 1}/${
searchResult.length + 1
}`}</div>
<Button
shape="circle"
icon={<antdIcons.ArrowLeftOutlined />}
onClick={() => {
if (searchResult.length > 0) {
focusPrev(searchResult, searchResultActiveIndex);
}
}}
/>
<Button
shape="circle"
icon={<antdIcons.ArrowRightOutlined />}
onClick={() => {
if (searchResult.length > 0) {
focusNext(searchResult, searchResultActiveIndex);
}
}}
/>
</>
) : null}
</Space>
<Divider />
<SheetComponent
ref={s2Ref}
dataCfg={dataCfg}
options={options}
sheetType="table"
onColCellClick={(e) => {
// 最左侧列的格子点击后全选
if (e.viewMeta.colIndex === 0) {
s2Ref.current?.interaction.selectAll();
}
}}
onCopied={() => {
message.success('复制成功');
}}
/>
<Modal
title="列设置"
visible={colModalVisible}
className="antv-s2-data-preview-demo-modal"
onCancel={() => {
setColModalVisible(false);
form.resetFields();
}}
onOk={() => {
modalCallbackRef.current();
setColModalVisible(false);
}}
>
<SortPopover
spreadsheet={s2Ref.current}
fieldName={interactedCol}
modalCallbackRef={modalCallbackRef}
/>
</Modal>
</div>
);
}
Example #28
Source File: DashboardPage.tsx From iot-center-v2 with MIT License | 4 votes |
DashboardPage: FunctionComponent<
RouteComponentProps<PropsRoute> & Props
> = ({match, history, helpCollapsed}) => {
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 [devices, setDevices] = useState<DeviceInfo[] | undefined>(undefined)
const [timeStart, setTimeStart] = useState('-1d')
const [xDomain, setXDomain] = useState<number[] | undefined>(undefined)
const resetXDomain = () =>
setXDomain(getXDomainFromTable(deviceData?.measurementsTable))
const isVirtualDevice = deviceId === VIRTUAL_DEVICE
const measurementsTable = deviceData?.measurementsTable
// fetch device configuration and data
useEffect(() => {
const fetchDeviceLastValues = async (
config: DeviceConfig,
timeStart: string
) => {
return Promise.all(
measurementsDefinitions.map(async ({column}) => ({
column,
table: await fetchDeviceDataFieldLast(config, column, timeStart),
}))
)
}
const fetchData = async () => {
setLoading(true)
try {
const config = await fetchDeviceConfig(deviceId)
const deviceData: DeviceData = {config}
const [table, lastValues] = await Promise.all([
fetchDeviceMeasurements(config, timeStart),
fetchDeviceLastValues(config, timeStart),
])
deviceData.measurementsTable = table
deviceData.measurementsLastValues = lastValues
setDeviceData(deviceData)
} catch (e) {
console.error(e)
setMessage({
title: 'Cannot load device data',
description: String(e),
type: 'error',
})
}
setLoading(false)
}
fetchData()
}, [dataStamp, deviceId, timeStart])
useEffect(() => {
resetXDomain()
// eslint-disable-next-line
}, [deviceData])
useEffect(() => {
const fetchDevices = async () => {
try {
const response = await fetch('/api/devices')
if (response.status >= 300) {
const text = await response.text()
throw new Error(`${response.status} ${text}`)
}
const data = await response.json()
setDevices(data)
} catch (e) {
setMessage({
title: 'Cannot fetch data',
description: String(e),
type: 'error',
})
}
}
fetchDevices()
}, [])
const renderGauge = (
gaugeDefinition: Partial<GaugeLayerConfig>,
table: GiraffeTable
) => {
const gaugeDefaults: GaugeLayerConfig = {
type: 'gauge',
gaugeColors: [],
gaugeSize: 4,
gaugeTheme: {
...GAUGE_THEME_LIGHT,
valuePositionYOffset: 1,
},
}
return (
<div style={{width: '100%', height: 150}}>
<Plot
config={{
showAxes: false,
layers: [{...gaugeDefaults, ...gaugeDefinition}],
table,
}}
/>
</div>
)
}
const gaugeLastTimeMessage = (time: number) => {
const now = Date.now()
const diff = now - time
if (diff < 60_000) return 'just now'
if (diff < 300_000) return 'less than 5 min ago'
if (diff < 900_000) return 'more than 5 min ago'
return 'long time ago'
}
const gaugeMissingValues: string[] = []
const gauges = deviceData?.measurementsLastValues?.length ? (
<>
<Row gutter={[22, 22]}>
{measurementsDefinitions.map(({gauge, title, column}) => {
const lastValueTable = deviceData?.measurementsLastValues?.find(
(x) => x.column === column
)?.table
if (!lastValueTable?.length) {
gaugeMissingValues.push(title)
return undefined
}
const [time] = lastValueTable.getColumn('_time') as number[]
return (
<Col
sm={helpCollapsed ? 24 : 24}
md={helpCollapsed ? 12 : 24}
xl={helpCollapsed ? 6 : 12}
>
<Card
title={title}
extra={
<Tooltip title={new Date(time).toISOString()}>
<div style={{color: COLOR_TEXT}}>
{gaugeLastTimeMessage(time)}
</div>
</Tooltip>
}
>
{renderGauge(gauge, lastValueTable)}
</Card>
</Col>
)
})}
</Row>
<Divider style={{color: 'rgba(0, 0, 0, .2)'}} orientation="right">
{gaugeMissingValues.length
? `Gauge missing values: ${gaugeMissingValues.join(', ')}`
: undefined}
</Divider>
</>
) : undefined
const renderPlot = (
lineDefinition: Partial<LineLayerConfig> | undefined,
table: GiraffeTable,
column: string
) => {
const lineDefaults: LineLayerConfig = {
type: 'line',
x: '_time',
y: column,
interpolation: 'linear',
colors: [COLOR_PRIMARY],
}
return (
<div style={{width: '100%', height: 200}}>
<Plot
config={{
xDomain: xDomain,
onSetXDomain: setXDomain,
onResetXDomain: resetXDomain,
layers: [{...lineDefaults, ...lineDefinition}],
table,
valueFormatters: {
_time: timeFormatter({
timeZone: 'UTC',
format: 'YYYY-MM-DD HH:mm:ss ZZ',
}),
},
}}
/>
</div>
)
}
const plots =
measurementsTable && measurementsTable?.length
? (() => {
const measurementsWithValues = measurementsDefinitions.filter(
({column}) => measurementsTable.getColumn(column)
)
const measurementsNoValues = measurementsDefinitions.filter(
({column}) => !measurementsTable.getColumn(column)
)
return (
<>
<Row gutter={[0, 24]}>
{measurementsWithValues.map(({line, title, column}, i) => (
<Col xs={24}>
<Collapse
defaultActiveKey={measurementsWithValues.map((_, i) => i)}
>
<CollapsePanel key={i} header={title}>
{renderPlot(line, measurementsTable, column)}
</CollapsePanel>
</Collapse>
</Col>
))}
</Row>
{measurementsNoValues.length ? (
<Collapse>
{measurementsNoValues.map(({title}, i) => (
<CollapsePanel
key={i}
disabled={true}
header={`${title} - No data`}
/>
))}
</Collapse>
) : undefined}
</>
)
})()
: undefined
const timeOptions: {label: string; value: string}[] = [
{label: 'Past 5m', value: '-5m'},
{label: 'Past 15m', value: '-15m'},
{label: 'Past 1h', value: '-1h'},
{label: 'Past 6h', value: '-6h'},
{label: 'Past 1d', value: '-1d'},
{label: 'Past 3d', value: '-3d'},
{label: 'Past 7d', value: '-7d'},
{label: 'Past 30d', value: '-30d'},
]
const pageControls = (
<>
<Tooltip title="Choose device" placement="left">
<Select
showSearch
value={deviceId}
placeholder={'select device to show'}
showArrow={true}
filterOption={true}
onChange={(key) => history.push(`/dashboard/${key}`)}
style={{minWidth: 200, width: 350, marginRight: 10}}
loading={!devices}
disabled={!devices}
>
{devices &&
devices.map(({deviceId}) => (
<Select.Option key={deviceId} value={deviceId}>
{deviceId}
</Select.Option>
))}
</Select>
</Tooltip>
<Tooltip title="Choose time" placement="left">
<Select
value={timeStart}
onChange={setTimeStart}
style={{minWidth: 100}}
loading={loading}
disabled={loading}
>
{timeOptions.map(({label, value}) => (
<Select.Option key={value} value={value}>
{label}
</Select.Option>
))}
</Select>
</Tooltip>
<Tooltip title="Reload Device Data">
<Button
disabled={loading}
loading={loading}
onClick={() => setDataStamp(dataStamp + 1)}
style={{marginLeft: 10}}
icon={<IconRefresh />}
/>
</Tooltip>
<Tooltip title="Go to device settings" placement="topRight">
<Button
type="primary"
icon={<IconSettings />}
style={{marginLeft: 10}}
href={`/devices/${deviceId}`}
></Button>
</Tooltip>
</>
)
return (
<PageContent
title={
<>
Dashboard
{isVirtualDevice ? (
<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>
) : undefined}
</>
}
titleExtra={pageControls}
message={message}
spin={loading}
forceShowScroll={true}
>
{deviceData?.measurementsTable?.length ? (
<>
{gauges}
{plots}
</>
) : (
<Card>
<Empty />
</Card>
)}
</PageContent>
)
}
Example #29
Source File: DendronCalendarPanel.tsx From dendron with GNU Affero General Public License v3.0 | 4 votes |
export default function DendronCalendarPanel({ ide, engine }: DendronProps) {
// --- init
const ctx = "CalendarView";
const logger = createLogger("calendarView");
logger.info({
ctx,
state: "enter",
});
const { getPrefixCls } = React.useContext(ConfigProvider.ConfigContext);
const [activeMode, setActiveMode] = useState<CalendarProps["mode"]>("month");
const { notes, config } = engine;
const { noteActive } = ide;
const currentVault = noteActive?.vault;
logger.info({
activeNoteFname: noteActive ? noteActive.fname : "no active note found",
});
const maxDots: number = 5;
const wordsPerDot: number = 250;
const defaultConfig = ConfigUtils.genDefaultConfig();
const journalConfig = ConfigUtils.getJournal(config || defaultConfig);
const journalDailyDomain = journalConfig.dailyDomain;
const journalName = journalConfig.name;
// Load up the full engine state as all notes are needed for the Tree View
const [workspace] = useWorkspaceProps();
useEngine({ engineState: engine, opts: workspace });
// luxon token format lookup https://github.com/moment/luxon/blob/master/docs/formatting.md#table-of-tokens
let journalDateFormat = journalConfig.dateFormat;
const journalMonthDateFormat = "y.MM"; // TODO compute format for currentMode="year" from config
// Currently luxon does not support setting first day of the week (https://github.com/moment/luxon/issues/373)
// const dayOfWeek = config?.journal.firstDayOfWeek;
// const locale = "en-us";
if (journalDateFormat) {
// correct possible user mistake that very likely is meant to be day of the month, padded to 2 (dd) and not localized date with abbreviated month (DD)
journalDateFormat = journalDateFormat.replace(/DD/, "dd");
}
const groupedDailyNotes = useMemo(() => {
const vaultNotes = _.values(notes).filter((notes) => {
if (currentVault) {
return VaultUtils.isEqualV2(notes.vault, currentVault);
}
return true;
});
const dailyNotes = vaultNotes.filter((note) =>
note.fname.startsWith(`${journalDailyDomain}.${journalName}`)
);
const result = _.groupBy(dailyNotes, (note) => {
return journalName ? getMaybeDatePortion(note, journalName) : undefined;
});
return result;
}, [notes, journalName, journalDailyDomain, currentVault?.fsPath]);
const activeDate = useMemo(() => {
if (noteActive && journalName && journalDateFormat) {
const maybeDatePortion = getMaybeDatePortion(noteActive, journalName);
if (maybeDatePortion && _.first(groupedDailyNotes[maybeDatePortion])) {
const dailyDate = Time.DateTime.fromFormat(
maybeDatePortion,
journalDateFormat
);
const monthlyDate = Time.DateTime.fromFormat(
maybeDatePortion,
journalMonthDateFormat
);
return dailyDate.isValid
? dailyDate
: monthlyDate.isValid
? monthlyDate
: undefined;
}
return undefined;
}
}, [noteActive, groupedDailyNotes, journalName, journalDateFormat]);
const getDateKey = useCallback<
(date: DateTime, mode?: CalendarProps["mode"]) => string | undefined
>(
(date, mode) => {
const format =
(mode || activeMode) === "month"
? journalDateFormat
: journalMonthDateFormat;
return format ? date.toFormat(format) : undefined;
},
[activeMode, journalDateFormat]
);
const onSelect = useCallback<
(date: DateTime, mode?: CalendarProps["mode"]) => void
>(
(date, mode) => {
logger.info({ ctx: "onSelect", date });
const dateKey = getDateKey(date, mode);
const selectedNote = dateKey
? _.first(groupedDailyNotes[dateKey])
: undefined;
postVSCodeMessage({
type: CalendarViewMessageType.onSelect,
data: {
id: selectedNote?.id,
fname: `${journalDailyDomain}.${journalName}.${dateKey}`,
},
source: DMessageSource.webClient,
});
},
[groupedDailyNotes, getDateKey, journalDailyDomain, journalName]
);
const onPanelChange = useCallback<
Exclude<CalendarProps["onPanelChange"], undefined>
>((date, mode) => {
logger.info({ ctx: "onPanelChange", date, mode });
setActiveMode(mode);
}, []);
const onClickToday = useCallback(() => {
const mode = "month";
setActiveMode(mode);
onSelect(Time.now(), mode);
}, [onSelect]);
const dateFullCellRender = useCallback<
Exclude<CalendarProps["dateFullCellRender"], undefined>
>(
(date) => {
const dateKey = getDateKey(date);
const dailyNote = dateKey
? _.first(groupedDailyNotes[dateKey])
: undefined;
const dailyNotes = dailyNote ? [dailyNote] : []; // keeping for case of showing all dailyNotes of day in multi-vault
const dateCell =
// multiple daily notes can exist for that day in a mulit-vault setup
// will only show up when `noteActive` is `undefined`. this happens when opening vscode with no document open
dailyNotes.map((note, index) => {
const amount = _.clamp(
wordsPerDot
? Math.floor(note.body.split(/\n| /).length / wordsPerDot) // TODO create test
: 0,
0,
maxDots
);
return (
<div
key={note.id}
style={{
position: "relative",
top: index * 2 - 6, // space between the day and dots boxes
// left: index * 1,
}}
>
{_.times(amount, (index) => (
<div
key={index}
style={{
position: "absolute",
left: index * 7, // 7 resutls in a nice visible space between the dots
}}
>
<Badge
className={`${note.fname}`}
dot
color={
"#00adb5" /* color copied from packages/dendron-next-server/assets/themes/dark-theme.less TODO make dependent on active theme */
}
/>
</div>
))}
</div>
);
});
const prefixCls = getPrefixCls("picker");
const calendarPrefixCls = `${prefixCls}-calendar`;
return (
<div
className={classNames(
`${prefixCls}-cell-inner`,
`${calendarPrefixCls}-date`,
{
[`${calendarPrefixCls}-date-today`]: isSameDate(today, date),
}
)}
>
<div
className={`${calendarPrefixCls}-date-value`}
style={{ color: !dailyNote ? "gray" : undefined }}
>
{_.padStart(String(luxonGenerateConfig.getDate(date)), 2, "0")}
</div>
<div className={`${calendarPrefixCls}-date-content`}>{dateCell}</div>
</div>
);
},
[getDateKey, groupedDailyNotes]
);
return (
<>
<div className="calendar">
<Calendar
mode={activeMode}
onSelect={onSelect}
onPanelChange={onPanelChange}
/*
// @ts-ignore -- `null` initializes ant Calendar into a controlled component whereby it does not render an selected/visible date (today) when `activeDate` is `undefined`*/
value={activeDate || null}
dateFullCellRender={dateFullCellRender}
fullscreen={false}
/>
</div>
<Divider plain style={{ marginTop: 0 }}>
<Button type="primary" onClick={onClickToday}>
Today
</Button>
</Divider>
</>
);
}