@ant-design/icons#LockOutlined TypeScript Examples
The following examples show how to use
@ant-design/icons#LockOutlined.
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: StatusIcon.tsx From datart with Apache License 2.0 | 6 votes |
LockIcon: React.FC<{
title: React.ReactNode;
onClick?: React.MouseEventHandler<HTMLElement> | undefined;
}> = ({ title, onClick }) => {
return (
<Tooltip title={title}>
<Button
icon={<LockOutlined style={{ color: PRIMARY, opacity: 0.5 }} />}
type="link"
onClick={onClick}
/>
</Tooltip>
);
}
Example #2
Source File: Login.tsx From vite-react-ts with MIT License | 6 votes |
Login: React.FC = () => {
const { login, loading } = useStore((state) => ({ ...state }));
return (
<div className={cls.loginBox}>
<Card className="_bg" bordered={false}>
<Form
onFinish={({ username, password }) => {
if (username === 'admin' && password === '123456') {
return login({ username, password });
}
message.error('账号或密码错误,请重试!');
}}>
<Form.Item
name="username"
rules={[{ required: true, message: '请输入用户名' }]}>
<Input prefix={<UserOutlined />} placeholder="请输入用户名:admin" />
</Form.Item>
<Form.Item name="password" rules={[{ required: true, message: '请输入密码' }]}>
<Input prefix={<LockOutlined />} placeholder="请输入密码:123456" />
</Form.Item>
<Form.Item>
<Button
loading={loading}
type="primary"
htmlType="submit"
className={cls.button}>
登陆
</Button>
</Form.Item>
</Form>
</Card>
</div>
);
}
Example #3
Source File: GroupsIntroductionOption.tsx From posthog-foss with MIT License | 6 votes |
export function GroupsIntroductionOption({ value }: { value: any }): JSX.Element | null {
const { groupsAccessStatus } = useValues(groupsAccessLogic)
if (
![GroupsAccessStatus.HasAccess, GroupsAccessStatus.HasGroupTypes, GroupsAccessStatus.NoAccess].includes(
groupsAccessStatus
)
) {
return null
}
return (
<Select.Option
key="groups"
value={value}
disabled
style={{
height: '100%',
width: '100%',
overflow: 'hidden',
textOverflow: 'ellipsis',
backgroundColor: 'var(--bg-side)',
color: 'var(--text-muted)',
}}
>
<LockOutlined style={{ marginRight: 6, color: 'var(--warning)' }} />
Unique groups –{' '}
<Link
to="https://posthog.com/docs/user-guides/group-analytics?utm_medium=in-product&utm_campaign=group-analytics-learn-more"
target="_blank"
data-attr="group-analytics-learn-more"
style={{ fontWeight: 600 }}
>
Learn more
</Link>
</Select.Option>
)
}
Example #4
Source File: Login.tsx From jmix-frontend with Apache License 2.0 | 5 votes |
Login = observer(() => {
const intl = useIntl();
const mainStore = useMainStore();
const [login, setLogin] = useState("");
const [password, setPassword] = useState("");
const [performingLoginRequest, setPerformingLoginRequest] = useState(false);
const changeLogin = useCallback((e: ChangeEvent<HTMLInputElement>) => setLogin(e.target.value), [setLogin]);
const changePassword = useCallback((e: ChangeEvent<HTMLInputElement>) => setPassword(e.target.value), [setPassword]);
const doLogin = useCallback(() => {
setPerformingLoginRequest(true);
mainStore
.login(login, password)
.then(action(() => {
setPerformingLoginRequest(false);
}))
.catch(action((error: JmixServerError) => {
setPerformingLoginRequest(false);
const loginMessageErrorIntlId = loginMapJmixRestErrorToIntlId(error);
message.error(intl.formatMessage({id: loginMessageErrorIntlId}));
}));
}, [setPerformingLoginRequest, mainStore, intl, login, password]);
return (
<Card className={styles.loginForm}>
<JmixDarkIcon className={styles.logo} />
<div className={styles.title}>
<%= title %>
</div>
<Form layout='vertical' onFinish={doLogin}>
<Form.Item>
<Input id='input_login'
placeholder={intl.formatMessage({id: 'login.placeholder.login'})}
onChange={changeLogin}
value={login}
prefix={<UserOutlined style={{ margin: "0 11px 0 0" }}/>}
size='large'/>
</Form.Item>
<Form.Item>
<Input id='input_password'
placeholder={intl.formatMessage({id: 'login.placeholder.password'})}
onChange={changePassword}
value={password}
type='password'
prefix={<LockOutlined style={{ margin: "0 11px 0 0" }}/>}
size='large'/>
</Form.Item>
<Form.Item>
<div className={styles.languageSwitcherContainer}>
<LanguageSwitcher />
</div>
</Form.Item>
<Form.Item>
<Button type='primary'
htmlType='submit'
size='large'
block={true}
loading={performingLoginRequest}>
<FormattedMessage id='login.loginBtn'/>
</Button>
</Form.Item>
</Form>
</Card>
);
})
Example #5
Source File: ChangePasswordOnResetForm.tsx From jitsu with MIT License | 5 votes |
ChangePasswordOnResetForm = () => {
const services = useServices()
const { resetId } = useParams<{ resetId?: string }>()
const [isLoading, setIsLoading] = useState<boolean>(false)
const handleChangePassword = async values => {
setIsLoading(true)
try {
await services.userService.changePassword(values["password"], resetId)
message.success("Password has been changed!")
await sleep(800)
window.location.href = getBaseUIPath() ?? "/"
} catch (error) {
handleError(error)
} finally {
setIsLoading(false)
}
}
return (
<Card
title={
<div className="flex flex-col items-center justify-start">
<img src={logo} alt="[logo]" className="h-16" />
<h3 className="pt-6">Set your new password</h3>
</div>
}
style={{ margin: "auto", marginTop: "100px", maxWidth: "500px" }}
bordered={false}
className="password-form-card"
>
<Form
name="password-form"
className="password-form"
initialValues={{
remember: false,
}}
requiredMark={false}
layout="vertical"
onFinish={handleChangePassword}
>
<Form.Item
name="password"
rules={[
{
required: true,
message: "Please input new Password!",
},
]}
label={<b>New Password</b>}
>
<Input prefix={<LockOutlined />} type="password" placeholder="Password" />
</Form.Item>
<div className="password-action-buttons">
<div>
<Button type="primary" htmlType="submit" className="login-form-button" loading={isLoading}>
Save
</Button>
</div>
</div>
</Form>
</Card>
)
}
Example #6
Source File: AccessControl.tsx From posthog-foss with MIT License | 5 votes |
export function AccessControl({ isRestricted }: RestrictedComponentProps): JSX.Element {
const { currentOrganization, currentOrganizationLoading } = useValues(organizationLogic)
const { currentTeam, currentTeamLoading } = useValues(teamLogic)
const { updateCurrentTeam } = useActions(teamLogic)
const { guardAvailableFeature } = useActions(sceneLogic)
const { hasAvailableFeature } = useValues(userLogic)
const projectPermissioningEnabled =
hasAvailableFeature(AvailableFeature.PROJECT_BASED_PERMISSIONING) && currentTeam?.access_control
return (
<div>
<h2 className="subtitle" id="access-control">
Access Control
</h2>
<p>
{projectPermissioningEnabled ? (
<>
This project is{' '}
<b>
<LockOutlined style={{ color: 'var(--warning)', marginRight: 5 }} />
private
</b>
. Only members listed below are allowed to access it.
</>
) : (
<>
This project is{' '}
<b>
<UnlockOutlined style={{ marginRight: 5 }} />
open
</b>
. Any member of the organization can access it. To enable granular access control, make it
private.
</>
)}
</p>
<Switch
id="access-control-switch"
onChange={(checked) => {
guardAvailableFeature(
AvailableFeature.PROJECT_BASED_PERMISSIONING,
'project-based permissioning',
'Set permissions granularly for each project. Make sure only the right people have access to protected data.',
() => updateCurrentTeam({ access_control: checked })
)
}}
checked={projectPermissioningEnabled}
loading={currentOrganizationLoading || currentTeamLoading}
disabled={isRestricted || !currentOrganization || !currentTeam}
/>
<label
style={{
marginLeft: '10px',
}}
htmlFor="access-control-switch"
>
Make project private
</label>
</div>
)
}
Example #7
Source File: Login.tsx From nodestatus with MIT License | 5 votes |
Login: FC = () => {
const navigate = useNavigate();
const { mutate } = useSWRConfig();
const onFinish = useCallback(async (values: { username: string, password: string }) => {
const { username, password } = values;
const res = await axios.post<IResp<string>>('/api/session', { username, password });
const { data } = res;
if (!data.code) {
notify('Success', undefined, 'success');
localStorage.setItem('token', data.data);
mutate('/api/session', { code: 0, msg: 'OK', data: null }, false).then(() => navigate('/dashboard'));
}
}, [navigate, mutate]);
return (
<div
className="flex items-center min-h-screen p-6 bg-violet-50"
style={{ backgroundImage: `url(${loginBackground})` }}
>
<div className="flex-1 h-full max-w-xl md:max-w-4xl mx-auto overflow-hidden bg-white rounded-lg shadow-xl">
<div className="flex flex-col md:flex-row">
<div className="h-60 md:h-auto md:w-1/2">
<img
aria-hidden="true"
className="object-cover w-full h-full"
src={cherry}
alt="Office"
/>
</div>
<div className="flex flex-col items-center justify-center p-6 sm:p-16 md:w-1/2">
<h1 className="text-2xl font-semibold text-gray-700 mb-6">NodeStatus</h1>
<Form
className="w-full"
initialValues={{ remember: true }}
onFinish={onFinish}
>
<Form.Item
name="username"
rules={[{ required: true, message: 'Please input your Username!' }]}
>
<Input size="large" prefix={<UserOutlined />} placeholder="Username" />
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: 'Please input your Password!' }]}
>
<Input
size="large"
prefix={<LockOutlined />}
type="password"
placeholder="Password"
/>
</Form.Item>
<Form.Item>
<Button type="primary" size="large" htmlType="submit" block>
Log in
</Button>
</Form.Item>
</Form>
</div>
</div>
</div>
</div>
);
}
Example #8
Source File: Icon.tsx From html2sketch with MIT License | 4 votes |
IconSymbol: FC = () => {
return (
<Row>
{/*<CaretUpOutlined*/}
{/* className="icon"*/}
{/* symbolName={'1.General/2.Icons/1.CaretUpOutlined'}*/}
{/*/>*/}
{/* className="icon"*/}
{/* symbolName={'1.General/2.Icons/2.MailOutlined'}*/}
{/*/>*/}
{/*<StepBackwardOutlined*/}
{/* className="icon"*/}
{/* symbolName={'1.General/2.Icons/2.StepBackwardOutlined'}*/}
{/*/>*/}
{/*<StepForwardOutlined*/}
{/* className="icon"*/}
{/* symbolName={'1.General/2.Icons/2.StepBackwardOutlined'}*/}
{/*/>*/}
<StepForwardOutlined />
<ShrinkOutlined />
<ArrowsAltOutlined />
<DownOutlined />
<UpOutlined />
<LeftOutlined />
<RightOutlined />
<CaretUpOutlined />
<CaretDownOutlined />
<CaretLeftOutlined />
<CaretRightOutlined />
<VerticalAlignTopOutlined />
<RollbackOutlined />
<FastBackwardOutlined />
<FastForwardOutlined />
<DoubleRightOutlined />
<DoubleLeftOutlined />
<VerticalLeftOutlined />
<VerticalRightOutlined />
<VerticalAlignMiddleOutlined />
<VerticalAlignBottomOutlined />
<ForwardOutlined />
<BackwardOutlined />
<EnterOutlined />
<RetweetOutlined />
<SwapOutlined />
<SwapLeftOutlined />
<SwapRightOutlined />
<ArrowUpOutlined />
<ArrowDownOutlined />
<ArrowLeftOutlined />
<ArrowRightOutlined />
<LoginOutlined />
<LogoutOutlined />
<MenuFoldOutlined />
<MenuUnfoldOutlined />
<BorderBottomOutlined />
<BorderHorizontalOutlined />
<BorderInnerOutlined />
<BorderOuterOutlined />
<BorderLeftOutlined />
<BorderRightOutlined />
<BorderTopOutlined />
<BorderVerticleOutlined />
<PicCenterOutlined />
<PicLeftOutlined />
<PicRightOutlined />
<RadiusBottomleftOutlined />
<RadiusBottomrightOutlined />
<RadiusUpleftOutlined />
<RadiusUprightOutlined />
<FullscreenOutlined />
<FullscreenExitOutlined />
<QuestionOutlined />
<PauseOutlined />
<MinusOutlined />
<PauseCircleOutlined />
<InfoOutlined />
<CloseOutlined />
<ExclamationOutlined />
<CheckOutlined />
<WarningOutlined />
<IssuesCloseOutlined />
<StopOutlined />
<EditOutlined />
<CopyOutlined />
<ScissorOutlined />
<DeleteOutlined />
<SnippetsOutlined />
<DiffOutlined />
<HighlightOutlined />
<AlignCenterOutlined />
<AlignLeftOutlined />
<AlignRightOutlined />
<BgColorsOutlined />
<BoldOutlined />
<ItalicOutlined />
<UnderlineOutlined />
<StrikethroughOutlined />
<RedoOutlined />
<UndoOutlined />
<ZoomInOutlined />
<ZoomOutOutlined />
<FontColorsOutlined />
<FontSizeOutlined />
<LineHeightOutlined />
<SortAscendingOutlined />
<SortDescendingOutlined />
<DragOutlined />
<OrderedListOutlined />
<UnorderedListOutlined />
<RadiusSettingOutlined />
<ColumnWidthOutlined />
<ColumnHeightOutlined />
<AreaChartOutlined />
<PieChartOutlined />
<BarChartOutlined />
<DotChartOutlined />
<LineChartOutlined />
<RadarChartOutlined />
<HeatMapOutlined />
<FallOutlined />
<RiseOutlined />
<StockOutlined />
<BoxPlotOutlined />
<FundOutlined />
<SlidersOutlined />
<AndroidOutlined />
<AppleOutlined />
<WindowsOutlined />
<IeOutlined />
<ChromeOutlined />
<GithubOutlined />
<AliwangwangOutlined />
<DingdingOutlined />
<WeiboSquareOutlined />
<WeiboCircleOutlined />
<TaobaoCircleOutlined />
<Html5Outlined />
<WeiboOutlined />
<TwitterOutlined />
<WechatOutlined />
<AlipayCircleOutlined />
<TaobaoOutlined />
<SkypeOutlined />
<FacebookOutlined />
<CodepenOutlined />
<CodeSandboxOutlined />
<AmazonOutlined />
<GoogleOutlined />
<AlipayOutlined />
<AntDesignOutlined />
<AntCloudOutlined />
<ZhihuOutlined />
<SlackOutlined />
<SlackSquareOutlined />
<BehanceSquareOutlined />
<DribbbleOutlined />
<DribbbleSquareOutlined />
<InstagramOutlined />
<YuqueOutlined />
<AlibabaOutlined />
<YahooOutlined />
<RedditOutlined />
<SketchOutlined />
<AccountBookOutlined />
<AlertOutlined />
<ApartmentOutlined />
<ApiOutlined />
<QqOutlined />
<MediumWorkmarkOutlined />
<GitlabOutlined />
<MediumOutlined />
<GooglePlusOutlined />
<AppstoreAddOutlined />
<AppstoreOutlined />
<AudioOutlined />
<AudioMutedOutlined />
<AuditOutlined />
<BankOutlined />
<BarcodeOutlined />
<BarsOutlined />
<BellOutlined />
<BlockOutlined />
<BookOutlined />
<BorderOutlined />
<BranchesOutlined />
<BuildOutlined />
<BulbOutlined />
<CalculatorOutlined />
<CalendarOutlined />
<CameraOutlined />
<CarOutlined />
<CarryOutOutlined />
<CiCircleOutlined />
<CiOutlined />
<CloudOutlined />
<ClearOutlined />
<ClusterOutlined />
<CodeOutlined />
<CoffeeOutlined />
<CompassOutlined />
<CompressOutlined />
<ContactsOutlined />
<ContainerOutlined />
<ControlOutlined />
<CopyrightCircleOutlined />
<CopyrightOutlined />
<CreditCardOutlined />
<CrownOutlined />
<CustomerServiceOutlined />
<DashboardOutlined />
<DatabaseOutlined />
<DeleteColumnOutlined />
<DeleteRowOutlined />
<DisconnectOutlined />
<DislikeOutlined />
<DollarCircleOutlined />
<DollarOutlined />
<DownloadOutlined />
<EllipsisOutlined />
<EnvironmentOutlined />
<EuroCircleOutlined />
<EuroOutlined />
<ExceptionOutlined />
<ExpandAltOutlined />
<ExpandOutlined />
<ExperimentOutlined />
<ExportOutlined />
<EyeOutlined />
<FieldBinaryOutlined />
<FieldNumberOutlined />
<FieldStringOutlined />
<DesktopOutlined />
<DingtalkOutlined />
<FileAddOutlined />
<FileDoneOutlined />
<FileExcelOutlined />
<FileExclamationOutlined />
<FileOutlined />
<FileImageOutlined />
<FileJpgOutlined />
<FileMarkdownOutlined />
<FilePdfOutlined />
<FilePptOutlined />
<FileProtectOutlined />
<FileSearchOutlined />
<FileSyncOutlined />
<FileTextOutlined />
<FileUnknownOutlined />
<FileWordOutlined />
<FilterOutlined />
<FireOutlined />
<FlagOutlined />
<FolderAddOutlined />
<FolderOutlined />
<FolderOpenOutlined />
<ForkOutlined />
<FormatPainterOutlined />
<FrownOutlined />
<FunctionOutlined />
<FunnelPlotOutlined />
<GatewayOutlined />
<GifOutlined />
<GiftOutlined />
<GlobalOutlined />
<GoldOutlined />
<GroupOutlined />
<HddOutlined />
<HeartOutlined />
<HistoryOutlined />
<HomeOutlined />
<HourglassOutlined />
<IdcardOutlined />
<ImportOutlined />
<InboxOutlined />
<InsertRowAboveOutlined />
<InsertRowBelowOutlined />
<InsertRowLeftOutlined />
<InsertRowRightOutlined />
<InsuranceOutlined />
<InteractionOutlined />
<KeyOutlined />
<LaptopOutlined />
<LayoutOutlined />
<LikeOutlined />
<LineOutlined />
<LinkOutlined />
<Loading3QuartersOutlined />
<LoadingOutlined />
<LockOutlined />
<MailOutlined />
<ManOutlined />
<MedicineBoxOutlined />
<MehOutlined />
<MenuOutlined />
<MergeCellsOutlined />
<MessageOutlined />
<MobileOutlined />
<MoneyCollectOutlined />
<MonitorOutlined />
<MoreOutlined />
<NodeCollapseOutlined />
<NodeExpandOutlined />
<NodeIndexOutlined />
<NotificationOutlined />
<NumberOutlined />
<PaperClipOutlined />
<PartitionOutlined />
<PayCircleOutlined />
<PercentageOutlined />
<PhoneOutlined />
<PictureOutlined />
<PoundCircleOutlined />
<PoundOutlined />
<PoweroffOutlined />
<PrinterOutlined />
<ProfileOutlined />
<ProjectOutlined />
<PropertySafetyOutlined />
<PullRequestOutlined />
<PushpinOutlined />
<QrcodeOutlined />
<ReadOutlined />
<ReconciliationOutlined />
<RedEnvelopeOutlined />
<ReloadOutlined />
<RestOutlined />
<RobotOutlined />
<RocketOutlined />
<SafetyCertificateOutlined />
<SafetyOutlined />
<ScanOutlined />
<ScheduleOutlined />
<SearchOutlined />
<SecurityScanOutlined />
<SelectOutlined />
<SendOutlined />
<SettingOutlined />
<ShakeOutlined />
<ShareAltOutlined />
<ShopOutlined />
<ShoppingCartOutlined />
<ShoppingOutlined />
<SisternodeOutlined />
<SkinOutlined />
<SmileOutlined />
<SolutionOutlined />
<SoundOutlined />
<SplitCellsOutlined />
<StarOutlined />
<SubnodeOutlined />
<SyncOutlined />
<TableOutlined />
<TabletOutlined />
<TagOutlined />
<TagsOutlined />
<TeamOutlined />
<ThunderboltOutlined />
<ToTopOutlined />
<ToolOutlined />
<TrademarkCircleOutlined />
<TrademarkOutlined />
<TransactionOutlined />
<TrophyOutlined />
<UngroupOutlined />
<UnlockOutlined />
<UploadOutlined />
<UsbOutlined />
<UserAddOutlined />
<UserDeleteOutlined />
<UserOutlined />
<UserSwitchOutlined />
<UsergroupAddOutlined />
<UsergroupDeleteOutlined />
<VideoCameraOutlined />
<WalletOutlined />
<WifiOutlined />
<BorderlessTableOutlined />
<WomanOutlined />
<BehanceOutlined />
<DropboxOutlined />
<DeploymentUnitOutlined />
<UpCircleOutlined />
<DownCircleOutlined />
<LeftCircleOutlined />
<RightCircleOutlined />
<UpSquareOutlined />
<DownSquareOutlined />
<LeftSquareOutlined />
<RightSquareOutlined />
<PlayCircleOutlined />
<QuestionCircleOutlined />
<PlusCircleOutlined />
<PlusSquareOutlined />
<MinusSquareOutlined />
<MinusCircleOutlined />
<InfoCircleOutlined />
<ExclamationCircleOutlined />
<CloseCircleOutlined />
<CloseSquareOutlined />
<CheckCircleOutlined />
<CheckSquareOutlined />
<ClockCircleOutlined />
<FormOutlined />
<DashOutlined />
<SmallDashOutlined />
<YoutubeOutlined />
<CodepenCircleOutlined />
<AliyunOutlined />
<PlusOutlined />
<LinkedinOutlined />
<AimOutlined />
<BugOutlined />
<CloudDownloadOutlined />
<CloudServerOutlined />
<CloudSyncOutlined />
<CloudUploadOutlined />
<CommentOutlined />
<ConsoleSqlOutlined />
<EyeInvisibleOutlined />
<FileGifOutlined />
<DeliveredProcedureOutlined />
<FieldTimeOutlined />
<FileZipOutlined />
<FolderViewOutlined />
<FundProjectionScreenOutlined />
<FundViewOutlined />
<MacCommandOutlined />
<PlaySquareOutlined />
<OneToOneOutlined />
<RotateLeftOutlined />
<RotateRightOutlined />
<SaveOutlined />
<SwitcherOutlined />
<TranslationOutlined />
<VerifiedOutlined />
<VideoCameraAddOutlined />
<WhatsAppOutlined />
{/*</Col>*/}
</Row>
);
}
Example #9
Source File: index.tsx From anew-server with MIT License | 4 votes |
Login: React.FC = () => {
const [submitting, setSubmitting] = useState(false);
const { initialState, setInitialState } = useModel('@@initialState');
const fetchUserInfo = async () => {
const userInfo = await initialState?.fetchUserInfo?.();
if (userInfo) {
setInitialState({ ...initialState, currentUser: userInfo });
}
};
const handleSubmit = async (values: API.LoginParams) => {
setSubmitting(true);
try {
// 登录
const login = await AuthLogin(values);
if (login.status) {
const defaultloginSuccessMessage = '登录成功';
message.success(defaultloginSuccessMessage);
localStorage.setItem('token', login.data.token);
localStorage.setItem('expires', login.data.expires);
await fetchUserInfo();
goto();
return;
} // 如果失败去设置用户错误信息
} catch (error) {
// 全局状态已处理,这里返回
return
}
setSubmitting(false);
};
return (
<div className={styles.container}>
<div className={styles.content}>
<div className={styles.top}>
<div className={styles.header}>
<Link to="/">
<img alt="logo" className={styles.logo} src="/logo.svg" />
<span className={styles.title}>Anew-Server</span>
</Link>
</div>
<div className={styles.desc}>{'运维平台'}</div>
</div>
<div className={styles.main}>
<ProForm
initialValues={{
autoLogin: true,
}}
submitter={{
searchConfig: {
submitText: '登录',
},
render: (_, dom) => dom.pop(),
submitButtonProps: {
loading: submitting,
size: 'large',
style: {
width: '100%',
},
},
}}
onFinish={async (values) => {
handleSubmit(values as API.LoginParams);
}}
>
<>
<ProFormText
name="username"
fieldProps={{
size: 'large',
prefix: <UserOutlined className={styles.prefixIcon} />,
}}
placeholder={'用户名: admin or user'}
rules={[
{
required: true,
message: '用户名是必填项!',
},
]}
/>
<ProFormText.Password
name="password"
fieldProps={{
size: 'large',
prefix: <LockOutlined className={styles.prefixIcon} />,
}}
placeholder={'密码: ant.design'}
rules={[
{
required: true,
message: '密码是必填项!',
},
]}
/>
</>
</ProForm>
</div>
</div>
<Footer />
</div>
);
}
Example #10
Source File: WidgetActionDropdown.tsx From datart with Apache License 2.0 | 4 votes |
WidgetActionDropdown: React.FC<WidgetActionDropdownProps> = memo(
({ widget }) => {
const { editing: boardEditing } = useContext(BoardContext);
const widgetAction = useWidgetAction();
const dataChart = useContext(WidgetChartContext)!;
const t = useI18NPrefix(`viz.widget.action`);
const menuClick = useCallback(
({ key }) => {
widgetAction(key, widget);
},
[widgetAction, widget],
);
const getAllList = useCallback(() => {
const allWidgetActionList: WidgetActionListItem<widgetActionType>[] = [
{
key: 'refresh',
label: t('refresh'),
icon: <SyncOutlined />,
},
{
key: 'fullScreen',
label: t('fullScreen'),
icon: <FullscreenOutlined />,
},
{
key: 'edit',
label: t('edit'),
icon: <EditOutlined />,
},
{
key: 'delete',
label: t('delete'),
icon: <DeleteOutlined />,
danger: true,
},
{
key: 'info',
label: t('info'),
icon: <InfoOutlined />,
},
{
key: 'lock',
label: t('lock'),
icon: <LockOutlined />,
},
{
key: 'makeLinkage',
label: t('makeLinkage'),
icon: <LinkOutlined />,
divider: true,
},
{
key: 'closeLinkage',
label: t('closeLinkage'),
icon: <CloseCircleOutlined />,
danger: true,
},
{
key: 'makeJump',
label: t('makeJump'),
icon: <BranchesOutlined />,
divider: true,
},
{
key: 'closeJump',
label: t('closeJump'),
icon: <CloseCircleOutlined />,
danger: true,
},
];
return allWidgetActionList;
}, [t]);
const actionList = useMemo(() => {
return (
getWidgetActionList({
allList: getAllList(),
widget,
boardEditing,
chartGraphId: dataChart?.config?.chartGraphId,
}) || []
);
}, [boardEditing, dataChart?.config?.chartGraphId, getAllList, widget]);
const dropdownList = useMemo(() => {
const menuItems = actionList.map(item => {
return (
<React.Fragment key={item.key}>
{item.divider && <Menu.Divider />}
<Menu.Item
danger={item.danger}
icon={item.icon}
disabled={item.disabled}
key={item.key}
>
{item.label}
</Menu.Item>
</React.Fragment>
);
});
return <Menu onClick={menuClick}>{menuItems}</Menu>;
}, [actionList, menuClick]);
if (actionList.length === 0) {
return null;
}
return (
<Dropdown
className="widget-tool-dropdown"
overlay={dropdownList}
placement="bottomCenter"
trigger={['click']}
arrow
>
<Button icon={<EllipsisOutlined />} type="link" />
</Dropdown>
);
},
)
Example #11
Source File: index.tsx From fe-v5 with Apache License 2.0 | 4 votes |
export default function Login() {
const { t } = useTranslation();
const [form] = Form.useForm();
const history = useHistory();
const location = useLocation();
const redirect = location.search && new URLSearchParams(location.search).get('redirect');
const dispatch = useDispatch();
const handleSubmit = async () => {
try {
await form.validateFields();
login();
} catch {
console.log(t('输入有误'));
}
};
const login = async () => {
let { username, password } = form.getFieldsValue();
const err = await dispatch({
type: 'account/login',
username,
password,
});
if (!err) {
history.push(redirect || '/metric/explorer');
}
};
return (
<div className='login-warp'>
<div className='banner'>
<div className='banner-bg'>
<img src={'/image/logo-l.svg'} className='logo' width='132'></img>
</div>
</div>
<div className='login-panel'>
<div className='login-main'>
<div className='login-title'>Nightingale</div>
<Form form={form} layout='vertical' requiredMark={true}>
<Form.Item
required
name='username'
rules={[
{
required: true,
message: t('请输入用户名'),
},
]}
>
<Input placeholder={t('请输入用户名')} prefix={<UserOutlined className='site-form-item-icon' />} />
</Form.Item>
<Form.Item
required
name='password'
rules={[
{
required: true,
message: t('请输入密码'),
},
]}
>
<Input type='password' placeholder={t('请输入密码')} onPressEnter={handleSubmit} prefix={<LockOutlined className='site-form-item-icon' />} />
</Form.Item>
<Form.Item>
<Button type='primary' onClick={handleSubmit}>
{t('登录')}
</Button>
</Form.Item>
<div className='login-other'>
<strong>其他登录方式:</strong>
<a
onClick={() => {
getRedirectURL().then((res) => {
if (res.dat) {
window.location.href = res.dat;
} else {
message.warning('没有配置 OIDC 登录地址!');
}
});
}}
>
OIDC
</a>
</div>
</Form>
</div>
</div>
</div>
);
}
Example #12
Source File: index.tsx From foodie with MIT License | 4 votes |
PostItem: React.FC<IProps> = (props) => {
const { post, likeCallback, isAuth } = props;
const [isCommentVisible, setCommentVisible] = useState(false);
const deleteModal = useModal();
const updateModal = useModal();
const commentInputRef = useRef<HTMLInputElement | null>(null);
const dispatch = useDispatch();
const handleToggleComment = () => {
if (!isAuth) return;
if (!isCommentVisible) setCommentVisible(true);
if (commentInputRef.current) commentInputRef.current.focus();
}
const displayLikeMetric = (likesCount: number, isLiked: boolean) => {
const like = likesCount > 1 ? 'like' : 'likes';
const likeMinusSelf = (likesCount - 1) > 1 ? 'like' : 'likes';
const people = likesCount > 1 ? 'people' : 'person';
const peopleMinusSelf = (likesCount - 1) > 1 ? 'people' : 'person';
if (isLiked && likesCount <= 1) {
return 'You like this.'
} else if (isLiked && likesCount > 1) {
return `You and ${likesCount - 1} other ${peopleMinusSelf} ${likeMinusSelf} this.`;
} else {
return `${likesCount} ${people} ${like} this.`;
}
}
const handleClickLikes = () => {
if (isAuth) {
dispatch(showModal(EModalType.POST_LIKES));
dispatch(setTargetPost(props.post));
}
}
const handleClickPrivacyChange = () => {
if (post.isOwnPost) {
dispatch(setTargetPost(post));
dispatch(showModal(EModalType.EDIT_POST));
}
}
return (
<div className="flex flex-col bg-white rounded-lg my-4 p-4 first:mt-0 shadow-lg dark:bg-indigo-1000">
{/* --- AVATAR AND OPTIONS */}
<div className="flex justify-between items-center w-full">
<div className="flex">
<Avatar
url={post.author.profilePicture?.url}
className="mr-3"
/>
<div className="flex flex-col">
<Link className="dark:text-indigo-400" to={`/user/${post.author.username}`}>
<h5 className="font-bold">{post.author.username}</h5>
</Link>
<div className="flex items-center space-x-1">
<span className="text-sm text-gray-500">{dayjs(post.createdAt).fromNow()}</span>
<div
className={`w-4 h-4 rounded-full flex items-center justify-center ${post.isOwnPost && 'cursor-pointer hover:bg-gray-100 dark:hover:bg-indigo-900'}`}
onClick={handleClickPrivacyChange}
title={post.isOwnPost ? 'Change Privacy' : ''}
>
{post.privacy === 'private'
? <LockOutlined className="text-xs text-gray-500 dark:text-white" />
: post.privacy === 'follower'
? <UserOutlined className="text-xs text-gray-500 dark:text-white" />
: <GlobalOutlined className="text-xs text-gray-500 dark:text-white" />
}
</div>
</div>
</div>
</div>
{isAuth && (
<PostOptions
openDeleteModal={deleteModal.openModal}
openUpdateModal={updateModal.openModal}
post={post}
/>
)}
</div>
{/* --- DESCRIPTION */}
<div className="mb-3 mt-2">
<p className="text-gray-700 dark:text-gray-300 break-words">{post.description}</p>
</div>
{/* --- IMAGE GRID ----- */}
{post.photos.length !== 0 && <ImageGrid images={post.photos.map(img => img.url)} />}
{/* ---- LIKES/COMMENTS DETAILS ---- */}
<div className="flex justify-between px-2 my-2">
<div onClick={handleClickLikes}>
{post.likesCount > 0 && (
<span className="text-gray-500 text-sm cursor-pointer hover:underline hover:text-gray-800 dark:hover:text-white">
{displayLikeMetric(post.likesCount, post.isLiked)}
</span>
)}
</div>
{/* --- COMMENTS COUNT ----- */}
<div>
{post.commentsCount > 0 && (
<span
className="text-gray-500 hover:text-gray-800 cursor-pointer text-sm hover:underline dark:text-gray-500 dark:hover:text-white"
onClick={handleToggleComment}
>
{post.commentsCount} {post.commentsCount === 1 ? 'comment' : 'comments'}
</span>
)}
</div>
</div>
{/* --- LIKE/COMMENT BUTTON */}
{isAuth ? (
<div className="flex items-center justify-around py-2 border-t border-gray-200 dark:border-gray-800">
<LikeButton postID={post.id} isLiked={post.isLiked} likeCallback={likeCallback} />
<span
className="py-2 rounded-md flex items-center justify-center text-gray-700 hover:text-gray-800 700 dark:text-gray-400 dark:hover:text-white dark:hover:bg-indigo-1100 cursor-pointer hover:bg-gray-100 text-l w-2/4"
onClick={handleToggleComment}
>
<CommentOutlined /> Comment
</span>
</div>
) : (
<div className="text-center py-2">
<span className="text-gray-400 text-sm">
<Link className="font-medium underline dark:text-indigo-400" to={LOGIN}>Login</Link> to like or comment on post.
</span>
</div>
)}
{isAuth && (
<Suspense fallback={<LoadingOutlined className="text-gray-800 dark:text-white" />}>
<Comments
postID={post.id}
authorID={post.author.id}
isCommentVisible={isCommentVisible}
commentInputRef={commentInputRef}
setInputCommentVisible={setCommentVisible}
/>
</Suspense>
)}
</div>
);
}
Example #13
Source File: index.tsx From ant-design-pro-V4 with MIT License | 4 votes |
Login: React.FC<LoginProps> = (props) => {
const { userLogin = {}, submitting } = props;
const { status, type: loginType } = userLogin;
const [type, setType] = useState<string>('account');
const intl = useIntl();
const handleSubmit = (values: LoginParamsType) => {
const { dispatch } = props;
dispatch({
type: 'login/login',
payload: { ...values, type },
});
};
return (
<div className={styles.main}>
<ProForm
initialValues={{
autoLogin: true,
}}
submitter={{
render: (_, dom) => dom.pop(),
submitButtonProps: {
loading: submitting,
size: 'large',
style: {
width: '100%',
},
},
}}
onFinish={(values) => {
handleSubmit(values as LoginParamsType);
return Promise.resolve();
}}
>
<Tabs activeKey={type} onChange={setType}>
<Tabs.TabPane
key="account"
tab={intl.formatMessage({
id: 'pages.login.accountLogin.tab',
defaultMessage: 'Account password login',
})}
/>
<Tabs.TabPane
key="mobile"
tab={intl.formatMessage({
id: 'pages.login.phoneLogin.tab',
defaultMessage: 'Mobile phone number login',
})}
/>
</Tabs>
{status === 'error' && loginType === 'account' && !submitting && (
<LoginMessage
content={intl.formatMessage({
id: 'pages.login.accountLogin.errorMessage',
defaultMessage: 'Incorrect account or password(admin/ant.design)',
})}
/>
)}
{type === 'account' && (
<>
<ProFormText
name="userName"
fieldProps={{
size: 'large',
prefix: <UserOutlined className={styles.prefixIcon} />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.username.placeholder',
defaultMessage: 'Username: admin or user',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.username.required"
defaultMessage="Please enter user name!"
/>
),
},
]}
/>
<ProFormText.Password
name="password"
fieldProps={{
size: 'large',
prefix: <LockOutlined className={styles.prefixIcon} />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.password.placeholder',
defaultMessage: 'Password: ant.design',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.password.required"
defaultMessage="Please enter password!"
/>
),
},
]}
/>
</>
)}
{status === 'error' && loginType === 'mobile' && !submitting && (
<LoginMessage content="Verification code error" />
)}
{type === 'mobile' && (
<>
<ProFormText
fieldProps={{
size: 'large',
prefix: <MobileOutlined className={styles.prefixIcon} />,
}}
name="mobile"
placeholder={intl.formatMessage({
id: 'pages.login.phoneNumber.placeholder',
defaultMessage: 'Phone number',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.phoneNumber.required"
defaultMessage="Please enter phone number!"
/>
),
},
{
pattern: /^1\d{10}$/,
message: (
<FormattedMessage
id="pages.login.phoneNumber.invalid"
defaultMessage="Malformed phone number!"
/>
),
},
]}
/>
<ProFormCaptcha
fieldProps={{
size: 'large',
prefix: <MailOutlined className={styles.prefixIcon} />,
}}
captchaProps={{
size: 'large',
}}
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: 'Please enter verification code',
})}
captchaTextRender={(timing, count) => {
if (timing) {
return `${count} ${intl.formatMessage({
id: 'pages.getCaptchaSecondText',
defaultMessage: 'Get verification code',
})}`;
}
return intl.formatMessage({
id: 'pages.login.phoneLogin.getVerificationCode',
defaultMessage: 'Get verification code',
});
}}
name="captcha"
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.captcha.required"
defaultMessage="Please enter verification code!"
/>
),
},
]}
onGetCaptcha={async (mobile) => {
const result = await getFakeCaptcha(mobile);
if (result === false) {
return;
}
message.success(
'Get the verification code successfully! The verification code is: 1234',
);
}}
/>
</>
)}
<div
style={{
marginBottom: 24,
}}
>
<ProFormCheckbox noStyle name="autoLogin">
<FormattedMessage id="pages.login.rememberMe" defaultMessage="Auto login" />
</ProFormCheckbox>
<a
style={{
float: 'right',
}}
>
<FormattedMessage id="pages.login.forgotPassword" defaultMessage="Forget password" />
</a>
</div>
</ProForm>
<Space className={styles.other}>
<FormattedMessage id="pages.login.loginWith" defaultMessage="Other login methods" />
<AlipayCircleOutlined className={styles.icon} />
<TaobaoCircleOutlined className={styles.icon} />
<WeiboCircleOutlined className={styles.icon} />
</Space>
</div>
);
}
Example #14
Source File: GeneralSignup.tsx From next-basics with GNU General Public License v3.0 | 4 votes |
export function GeneralSignup(props: GeneralSignupProps): React.ReactElement {
const [form] = Form.useForm();
const runtime = getRuntime();
const brand = runtime.getBrandSettings();
const enabledFeatures = runtime.getFeatureFlags();
const { t } = useTranslation(NS_GENERAL_AUTH);
const [, setForceUpdate] = useState<any>();
const passwordConfigMap = {
default: {
regex: /^.{6,20}$/,
description: "请输入6至20位密码",
},
strong: {
regex: /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^a-zA-Z0-9]).{8,20}$/,
description: "请输入8至20位密码,且同时包含大小写字母、数字、特殊字符",
},
backend: {},
};
let passwordLevel: keyof typeof passwordConfigMap = "default"; //特性开关
useEffect(() => {
if (enabledFeatures["enable-backend-password-config"]) {
(async () => {
passwordLevel = "backend";
passwordConfigMap[passwordLevel] =
await UserAdminApi_getPasswordConfig();
})();
}
}, []);
const MIN_USERNAME_LENGTH = 3; //特性开关
const MAX_USERNAME_LENGTH = 32; //特性开关
const usernamePattern = new RegExp(
`^[A-Za-z0-9][A-Za-z0-9|_\\-\\.]{${MIN_USERNAME_LENGTH - 1},${
MAX_USERNAME_LENGTH - 1
}}$`
);
const iniviteCodePattern = /^[0-9a-zA-Z]{9}$/;
const hideInvite = iniviteCodePattern.test(getInviteCode());
const [isCommonSignup, setIsCommonSignup] = useState(true);
const [isTermsVisible, setIsTermsVisible] = useState(false);
function showTerms(): void {
setIsTermsVisible(true);
}
function hideTerms(): void {
setIsTermsVisible(false);
}
function agreeTerms(): void {
form.setFieldsValue({
terms: true,
});
hideTerms();
}
function disagreeTerms(): void {
form.setFieldsValue({
terms: false,
});
hideTerms();
}
const [imageHeight, setImageHeight] = useState(window.innerHeight);
const onWindowResized = () => {
if (imageHeight < window.innerHeight) {
setImageHeight(window.innerHeight);
}
};
useEffect(() => {
const handleWindowResized = debounce(onWindowResized, 500, {
leading: false,
});
window.addEventListener("resize", handleWindowResized);
return () => {
window.removeEventListener("resize", handleWindowResized);
};
}, []);
const timer = useRef<any>();
const count = useRef<number>(duration);
const [verifyBtnDisabled, setVerifyBtnDisabled] = useState(true);
const [content, setContent] = useState(t(K.GET_VERIFY_CODE));
const [messageId, setMessageId] = useState("");
const handleVerifyBtnClick = async (
e: React.MouseEvent<HTMLElement, MouseEvent>
) => {
if (timer.current) return;
count.current -= 1;
setContent(t(K.GET_VERIFY_CODE_TIPS, { count: count.current }));
setVerifyBtnDisabled(true);
timer.current = setInterval(() => {
count.current -= 1;
setContent(t(K.GET_VERIFY_CODE_TIPS, { count: count.current }));
if (count.current === 0) {
clearInterval(timer.current);
timer.current = null;
count.current = duration;
setVerifyBtnDisabled(false);
setContent(t(K.GET_VERIFY_CODE));
}
}, 1000);
const result = await CustomerApi_sendApplicationVerificationCode({
phone_number: form.getFieldValue("phone"),
});
result.message_id && setMessageId(result.message_id);
};
const redirect = async (result: Record<string, any>): Promise<void> => {
runtime.reloadSharedData();
await runtime.reloadMicroApps();
resetLegacyIframe();
authenticate({
org: result.org,
username: result.username,
userInstanceId: result.userInstanceId,
accessRule: result.accessRule,
});
const { state } = getHistory().location;
const from =
state && state.from
? state.from
: {
pathname: "/",
};
const redirect = createLocation(from);
getHistory().push(redirect);
};
const onFinish = async (values: Record<string, any>): Promise<void> => {
values.password = encryptValue(values.password);
try {
let result: Record<string, any>;
if (isCommonSignup && !hideInvite) {
result = await OrgApi_saaSOrgRegister(
assign(omit(values, ["terms", "password2"]), {
message_id: messageId,
}) as OrgApi_SaaSOrgRegisterRequestBody
);
} else {
result = await AuthApi_register(
assign(
omit(values, ["terms", "password2", "username"]),
hideInvite
? { invite: getInviteCode(), name: values["username"] }
: { name: values["username"] }
) as AuthApi_RegisterRequestBody
);
}
if (result.loggedIn) {
redirect(result);
}
message.success(t(K.REGISTER_SUCCESS));
} catch (error) {
Modal.error({
title: t(K.REGISTER_FAILED),
content:
isCommonSignup && !hideInvite
? t(K.WRONG_VERIFICATION_CODE)
: t(K.WRONG_INVITE_CODE),
});
}
};
return (
<>
<div className={styles.signupWrapper}>
<div className={styles.signupHeader}>
<div className={styles.logoBar}>
<Link to="/">
{brand.auth_logo_url ? (
<img
src={brand.auth_logo_url}
style={{ height: 32, verticalAlign: "middle" }}
/>
) : (
<Logo height={32} style={{ verticalAlign: "middle" }} />
)}
</Link>
</div>
</div>
<div className={styles.signupImg}>
<img src={loginPng} style={{ height: imageHeight }} />
</div>
<div className={styles.signupForm}>
<Card bordered={false}>
{!hideInvite &&
(isCommonSignup ? (
<a
onClick={() => {
setIsCommonSignup(false);
}}
style={{ alignSelf: "flex-end" }}
id="JumpToJoinFormLink"
>
{t(K.JOIN_THE_ORGANIZATION)} <RightOutlined />
</a>
) : (
<a
onClick={() => {
setIsCommonSignup(true);
}}
id="JumpToCommonFormLink"
>
<LeftOutlined /> {t(K.REGISTER_COMMONLY)}
</a>
))}
{!hideInvite && isCommonSignup ? (
<div className={styles.title}>{t(K.REGISTER_ACCOUNT)}</div>
) : (
<div className={styles.title}>{t(K.REGISTER_AND_JOIN)}</div>
)}
<Form name="signupForm" form={form} onFinish={onFinish}>
<Form.Item
validateFirst={true}
name="username"
rules={[
{
required: true,
message: t(K.USERNAME_TIPS, {
minLength: 3,
maxLength: 32,
}),
},
{
pattern: usernamePattern,
message: t(K.USERNAME_TIPS, {
minLength: 3,
maxLength: 32,
}),
},
{
validator: (
_: any,
value: any,
callback: (value?: string) => void
) =>
validateMap["airNameValidator"](
value,
callback,
setForceUpdate
),
},
]}
>
<Input
prefix={<UserOutlined className={styles.inputPrefixIcon} />}
placeholder={t(K.USERNAME)}
/>
</Form.Item>
{enabledFeatures["enable-nickname-config"] && hideInvite && (
<Form.Item validateFirst={false} name="nickname">
<Input
prefix={
<SolutionOutlined className={styles.inputPrefixIcon} />
}
placeholder={t(K.NICKNAME)}
/>
</Form.Item>
)}
<Form.Item
name="email"
validateFirst={true}
rules={[
{ required: true, message: t(K.PLEASE_ENTER_VALID_EMAIL) },
{ type: "email", message: t(K.PLEASE_ENTER_VALID_EMAIL) },
{
validator: (
_: any,
value: any,
callback: (value?: string) => void
) =>
validateMap["airEmailValidator"](
value,
callback,
setForceUpdate
),
},
]}
>
<Input
prefix={<MailOutlined className={styles.inputPrefixIcon} />}
type="email"
placeholder={t(K.EMAIL)}
/>
</Form.Item>
<Form.Item
validateFirst={true}
name="password"
rules={[
{ required: true, message: t(K.PLEASE_INPUT_PASSWORD) },
{
pattern: passwordConfigMap[passwordLevel].regex,
message: passwordConfigMap[passwordLevel].description,
},
]}
>
<Input
prefix={<LockOutlined className={styles.inputPrefixIcon} />}
type="password"
placeholder={t(K.PASSWORD)}
/>
</Form.Item>
<Form.Item
dependencies={["password"]}
name="password2"
rules={[
{ required: true, message: t(K.PLEASE_INPUT_PASSWORD) },
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue("password") === value) {
return Promise.resolve();
}
return Promise.reject(
new Error(t(K.TWO_PASSWORDS_ARE_INCONSISTENT))
);
},
}),
]}
>
<Input
prefix={<LockOutlined className={styles.inputPrefixIcon} />}
type="password"
placeholder={t(K.PASSWORD_CONFIRM)}
/>
</Form.Item>
{!hideInvite &&
(isCommonSignup ? (
<>
<Form.Item
validateFirst={true}
rules={[
{
required: true,
message: t(K.PLEASE_FILL_IN_VALID_PHONE_NUMBER),
},
{
validator: (_, value) => {
if (
/^(?=\d{11}$)^1(?:3\d|4[57]|5[^4\D]|7[^249\D]|8\d)\d{8}$/.test(
value
)
) {
setVerifyBtnDisabled(false);
return Promise.resolve();
}
setVerifyBtnDisabled(true);
return Promise.reject(
new Error(t(K.PLEASE_FILL_IN_VALID_PHONE_NUMBER))
);
},
},
]}
name="phone"
>
<Input
prefix={
<PhoneOutlined
className={styles.inputPrefixIcon}
rotate={90}
/>
}
suffix={
<Button
disabled={verifyBtnDisabled}
type="text"
onClick={handleVerifyBtnClick}
id="verifyBtn"
>
{content}
</Button>
}
placeholder={t(K.PHONE)}
/>
</Form.Item>
<Form.Item
rules={[
{
required: true,
message: t(K.PLEASE_INPUT_PHRASE),
},
{
pattern: /^\d{6}$/,
message: t(K.PLEASE_INPUT_VALID_PHRASE),
},
]}
name="verification_code"
>
<Input
prefix={
<SafetyOutlined className={styles.inputPrefixIcon} />
}
placeholder={t(K.VERIFY_CODE)}
></Input>
</Form.Item>
</>
) : (
<Form.Item
validateFirst={true}
name="invite"
rules={[
{
required: true,
message: t([K.PLEASE_FILL_IN_INVITE_CODE]),
},
{
pattern: iniviteCodePattern,
message: t([K.PLEASE_FILL_IN_INVITE_CODE]),
},
]}
>
<Input
prefix={
<GeneralIcon
icon={{
lib: "easyops",
icon: "release-management",
category: "menu",
color: "rgba(0,0,0,.25)",
}}
/>
}
type="text"
placeholder={t(K.INVITE_CODE)}
/>
</Form.Item>
))}
<Form.Item
name="terms"
valuePropName="checked"
rules={[
{
validator: (_, value) =>
value
? Promise.resolve()
: Promise.reject(new Error(t(K.AGREE_TERMS_TIPS))),
},
]}
>
<Checkbox>
{t(K.AGREE_TERMS)}
<a
onClick={() => {
showTerms();
}}
id="TermsLink"
>
{t(K.UWINTECH_TERMS)}
</a>
</Checkbox>
</Form.Item>
<Form.Item>
<Button
type="primary"
htmlType="submit"
style={{
width: "100%",
height: 34,
}}
id="submitBtn"
>
{t(K.REGISTER)}
</Button>
</Form.Item>
<Form.Item>
<div style={{ textAlign: "center" }}>
{t(K.ALREADY_HAVE_AN_ACCOUNT)}
<a
id="LogInLink"
onClick={() => {
getHistory().push(
createLocation({
pathname: props.loginUrl ?? "/auth/login",
})
);
}}
>
{t(K.LOGIN_IMMEDIATELY)}
</a>
</div>
</Form.Item>
</Form>
</Card>
<Modal
visible={isTermsVisible}
title={t(K.UWINTECH_TERMS)}
width={598}
okType="default"
cancelText={t(K.DISAGREE)}
okText={t(K.AGREE)}
closable={false}
onCancel={() => {
disagreeTerms();
}}
onOk={() => {
agreeTerms();
}}
>
<Terms />
</Modal>
</div>
</div>
</>
);
}
Example #15
Source File: GeneralLogin.tsx From next-basics with GNU General Public License v3.0 | 4 votes |
render(): React.ReactNode {
const { t, form } = this.props;
const {
getFieldDecorator,
getFieldsValue,
isFieldTouched,
setFieldsValue,
} = form;
const runtime = getRuntime();
const enabledFeatures = runtime.getFeatureFlags();
const brand = runtime.getBrandSettings();
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
const notSetField = (fieldValue: string, fieldName: string): boolean => {
if (fieldValue !== undefined) {
return !fieldValue.length && isFieldTouched(fieldName);
} else {
return false;
}
};
const renderLoginForm = () => {
return (
<Form onSubmit={this.handleSubmit}>
<Tooltip title={this.state.loginErrorMsg}>
<div className={styles.loginFormError}>
{this.state.loginErrorMsg}
</div>
</Tooltip>
<Form.Item>
{getFieldDecorator("username", {
rules: [
{
validator(rule, value) {
const { username, password, phrase } = getFieldsValue();
if (!username.length) {
if (
notSetField(password, "password") &&
notSetField(phrase, "phrase")
) {
self.setState({
loginErrorMsg: t(
K.PLEASE_INPUT_USERNAME_PASSWORD_PHRASE
),
});
} else if (
notSetField(password, "password") &&
!notSetField(phrase, "phrase")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_USERNAME_PASSWORD),
});
} else if (
!notSetField(password, "password") &&
notSetField(phrase, "phrase")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_USERNAME_PHRASE),
});
} else {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_USERNAME),
});
}
return Promise.reject("");
} else {
if (
notSetField(password, "password") &&
notSetField(phrase, "phrase")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_PASSWORD_PHRASE),
});
} else if (
notSetField(password, "password") &&
!notSetField(phrase, "phrase")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_PASSWORD),
});
} else if (
!notSetField(password, "password") &&
notSetField(phrase, "phrase")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_PHRASE),
});
} else {
self.setState({
loginErrorMsg: "",
});
}
}
return Promise.resolve();
},
},
],
})(
<Input
prefix={<UserOutlined style={{ color: "rgba(0,0,0,.25)" }} />}
placeholder={
this.state.currentLoginMethod === "ldap"
? t(K.LDAP_ACCOUNT)
: t(K.USERNAME)
}
/>
)}
</Form.Item>
<Form.Item>
{getFieldDecorator("password", {
rules: [
{
validator(rule, value) {
const { username, password, phrase } = getFieldsValue();
if (!password.length) {
if (
notSetField(username, "username") &&
notSetField(phrase, "phrase")
) {
self.setState({
loginErrorMsg: t(
K.PLEASE_INPUT_USERNAME_PASSWORD_PHRASE
),
});
} else if (
notSetField(username, "username") &&
!notSetField(phrase, "phrase")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_USERNAME_PASSWORD),
});
} else if (
!notSetField(username, "username") &&
notSetField(phrase, "phrase")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_PASSWORD_PHRASE),
});
} else {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_PASSWORD),
});
}
return Promise.reject("");
} else {
if (
notSetField(username, "username") &&
notSetField(phrase, "phrase")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_USERNAME_PHRASE),
});
} else if (
notSetField(username, "username") &&
!notSetField(phrase, "phrase")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_USERNAME),
});
} else if (
!notSetField(username, "username") &&
notSetField(phrase, "phrase")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_PHRASE),
});
} else {
self.setState({
loginErrorMsg: "",
});
}
}
return Promise.resolve();
},
},
],
})(
<Input
prefix={<LockOutlined style={{ color: "rgba(0,0,0,.25)" }} />}
type="password"
placeholder={t(K.PASSWORD)}
/>
)}
</Form.Item>
{this.state.security_codeEnabled && (
<Form.Item style={{ bottom: "61px", marginBottom: "24px" }}>
{getFieldDecorator("phrase", {
rules: [
{
validator(rule, value) {
const { username, password, phrase } = getFieldsValue();
if (!phrase.length) {
if (
notSetField(username, "username") &&
notSetField(password, "password")
) {
self.setState({
loginErrorMsg: t(
K.PLEASE_INPUT_USERNAME_PASSWORD_PHRASE
),
});
} else if (
notSetField(username, "username") &&
!notSetField(password, "password")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_USERNAME_PHRASE),
});
} else if (
!notSetField(username, "username") &&
notSetField(password, "password")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_PASSWORD_PHRASE),
});
} else {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_PHRASE),
});
}
return Promise.reject("");
} else {
if (
notSetField(username, "username") &&
notSetField(password, "password")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_USERNAME_PASSWORD),
});
} else if (
!notSetField(username, "username") &&
notSetField(password, "password")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_PASSWORD),
});
} else if (
notSetField(username, "username") &&
!notSetField(password, "password")
) {
self.setState({
loginErrorMsg: t(K.PLEASE_INPUT_USERNAME),
});
} else {
self.setState({
loginErrorMsg: "",
});
}
}
return Promise.resolve();
},
},
],
})(
<Row>
<Input
//prefix={<LockOutlined style={{ color: "rgba(0,0,0,.25)" }} />}
prefix={
<FontAwesomeIcon
icon="shield-alt"
style={{ color: "rgba(0,0,0,.25)" }}
/>
}
style={{
width: "50%",
height: "42px",
verticalAlign: "middle",
}}
placeholder={t(K.SECURITY_CODE)}
/>
<img
src={this.state.yzm}
style={{
width: "50%",
height: "42px",
verticalAlign: "middle",
}}
alt=""
onClick={this.handleGetSecurityCodeAgain}
/>
</Row>
)}
</Form.Item>
)}
<Form.Item>
<Spin spinning={this.state.loggingIn}>
<Button
type="primary"
htmlType="submit"
style={{
width: "100%",
height: 34,
bottom: this.state.security_codeEnabled ? "-45px" : "0",
}}
>
{t(K.LOGIN)}
</Button>
</Spin>
<div className={styles.loginAppendix}>
{enabledFeatures["sign-up-for-free-enabled"] && (
<a
href={getRuntime().getBasePath() + "auth/signup"}
style={{ display: "block" }}
>
{t(K.REGISTER_ACCOUNT)}
</a>
)}
{enabledFeatures["forgot-password-enabled"] && (
<a
href="/login/forgot-password"
style={{ display: "block", flexGrow: 1, textAlign: "end" }}
>
{t(K.FORGET_PASSWORD)}
</a>
)}
</div>
</Form.Item>
</Form>
);
};
const changeLoginMethod = (event: string) => {
this.setState({ currentLoginMethod: event });
};
return (
<>
<div className={styles.loginWrapper}>
<div className={styles.loginHeader}>
<div className={styles.logoBar}>
<Link to="/">
{brand.auth_logo_url ? (
<img
src={brand.auth_logo_url}
style={{ height: 32, verticalAlign: "middle" }}
/>
) : (
<Logo height={32} style={{ verticalAlign: "middle" }} />
)}
</Link>
</div>
</div>
<div className={styles.loginImg}>
<img src={loginPng} style={{ height: this.state.imageHeight }} />
</div>
<div className={styles.loginForm}>
{this.state.wxQRCodeLogin ? (
<Tabs defaultActiveKey="code">
<Tabs.TabPane
tab={t(K.WX_LOGIN_TITLE)}
key="code"
className={styles.wxQRCodeLoginTab}
>
<Card bordered={false} className={styles.wxQRCodeLoginCard}>
<div id="wxQRCode"></div>
</Card>
</Tabs.TabPane>
<Tabs.TabPane tab={t(K.LOGIN_TITLE)} key="normal">
<Card title={t(K.LOGIN_TITLE)} bordered={false}>
{renderLoginForm()}
</Card>
</Tabs.TabPane>
</Tabs>
) : this.loginMethods.length === 1 ? (
<Card
title={
(this.loginMethodsMap as any)[this.state.currentLoginMethod]
}
bordered={false}
>
{renderLoginForm()}
</Card>
) : (
<Card>
<Tabs
onChange={changeLoginMethod}
activeKey={this.state.currentLoginMethod}
>
{this.loginMethods.map((item: string) => {
return (
<Tabs.TabPane
tab={(this.loginMethodsMap as any)[item]}
key={item}
>
{renderLoginForm()}
</Tabs.TabPane>
);
})}
</Tabs>
</Card>
)}
{this.state.MFALogin && (
<MFALogin
onCancel={this.handleCancel}
dataSource={this.state.mfaInfo}
redirect={this.redirect}
/>
)}
</div>
</div>
</>
);
}
Example #16
Source File: index.tsx From react_admin with MIT License | 4 votes |
Login: React.FC<Iprops> = (props) => {
const username = useInput("");
const password = useInput("");
const code = useInput("");
const inputRef = useRef<any>(null);
const [loading, setLoading] = useState(false);
/**
* 判断是否登录过 && 获取焦点
*/
useEffect(() => {
const userinfo = localStorage.getItem("userinfo")
? JSON.parse(localStorage.getItem("userinfo") as string)
: null;
if (userinfo) {
props.history.replace("/home");
} else {
inputRef.current.focus();
}
}, []);
/**
* @function
* 登录校验 发出请求
*/
const handleSubmit = async () => {
const _loginName = username.val.trim();
const _password = password.val.trim();
const _code = code.val.trim();
try {
if (!_loginName) throw new Error("用户名不能为空");
if (!_password) throw new Error("密码不能为空");
if (!_code) throw new Error("验证码不能为空");
if (_code !== captcha) throw new Error("验证码错误");
setLoading(true);
const data = (await getUserLoginData({
data: { _loginName, _password },
url: API.getLogin,
})) as Ilogin;
setLoading(false);
// 登录成功
if (_loginName === data.username && _password === data.password) {
localStorage.setItem(
"userinfo",
JSON.stringify({ _loginName, _password })
);
await props.setUserInfoMy({ _loginName, _password });
props.history.replace("/home");
} else {
throw new Error("用户名密码错误");
}
} catch (err) {
message.error(err.message);
return;
}
};
const reloadCaptcha = useCallback((e) => {
captcha = getRandom();
let url = API.getCaptcha + captcha;
e.target.src = url;
}, []);
return (
<section className="login-page">
<a
rel="noopener noreferrer"
className="login-right"
href="https://github.com/2662419405"
target="_blank"
>
<img
src="https://github.blog/wp-content/uploads/2008/12/forkme_right_darkblue_121621.png?resize=149%2C149"
alt="github"
/>
</a>
<div className="wrap">
<div>
<div className="logo-wrap">
<img
alt="logo"
className="logo"
src={require("../../assets/img/sh.png")}
/>
<em>TS + Hooks</em>
</div>
<Input.Group>
<Input
ref={inputRef}
{...username}
onPressEnter={handleSubmit}
prefix={<UserOutlined />}
maxLength={32}
autoComplete="off"
placeholder="username/admin"
/>
<Input
{...password}
prefix={<LockOutlined />}
onPressEnter={handleSubmit}
type="password"
maxLength={32}
autoComplete="off"
placeholder="password/123456"
/>
<Input
{...code}
onKeyDown={(e) => {
if (e.keyCode === 13) handleSubmit();
}}
prefix={<PictureOutlined />}
onPressEnter={handleSubmit}
maxLength={4}
autoComplete="off"
placeholder="请输入验证码"
suffix={
<img
className="captcha"
src={API.getCaptcha + captcha}
onClick={reloadCaptcha}
alt="code"
/>
}
/>
</Input.Group>
<Button
size="large"
className="weitiao-btn"
block={true}
type="primary"
onClick={handleSubmit}
loading={loading}
>
{loading ? "正在登录" : "登录"}
</Button>
<div className="other-login">
<span className="txt">其他登录方式</span>
<GithubOutlined className="github-icon" />
<div className="href-right">
<Tooltip
placement="bottom"
title="账号为admin,密码为123456,推荐使用第三方github进行登录"
>
<span className="text-right">注册账号</span>
</Tooltip>
</div>
</div>
</div>
</div>
<Footer />
</section>
);
}
Example #17
Source File: FeatureFlag.tsx From posthog-foss with MIT License | 4 votes |
export function FeatureFlag(): JSX.Element {
const [form] = Form.useForm()
const {
featureFlag,
featureFlagId,
multivariateEnabled,
variants,
nonEmptyVariants,
areVariantRolloutsValid,
variantRolloutSum,
groupTypes,
aggregationTargetName,
taxonomicGroupTypes,
} = useValues(featureFlagLogic)
const {
addConditionSet,
updateConditionSet,
removeConditionSet,
duplicateConditionSet,
saveFeatureFlag,
deleteFeatureFlag,
setMultivariateEnabled,
addVariant,
updateVariant,
removeVariant,
distributeVariantsEqually,
setFeatureFlag,
setAggregationGroupTypeIndex,
} = useActions(featureFlagLogic)
const { showGroupsOptions, aggregationLabel } = useValues(groupsModel)
const { hasAvailableFeature, upgradeLink } = useValues(userLogic)
// whether the key for an existing flag is being changed
const [hasKeyChanged, setHasKeyChanged] = useState(false)
// whether to warn the user that their variants will be lost
const [showVariantDiscardWarning, setShowVariantDiscardWarning] = useState(false)
useEffect(() => {
form.setFieldsValue({ ...featureFlag })
}, [featureFlag])
// :KLUDGE: Match by select only allows Select.Option as children, so render groups option directly rather than as a child
const matchByGroupsIntroductionOption = GroupsIntroductionOption({ value: -2 })
return (
<div className="feature-flag">
{featureFlag ? (
<Form
layout="vertical"
form={form}
initialValues={{ name: featureFlag.name, key: featureFlag.key, active: featureFlag.active }}
onValuesChange={(newValues) => {
if (featureFlagId !== 'new' && newValues.key) {
setHasKeyChanged(newValues.key !== featureFlag.key)
}
setFeatureFlag({ ...featureFlag, ...newValues })
}}
onFinish={(values) =>
saveFeatureFlag({
...featureFlag,
...values,
filters: featureFlag.filters,
})
}
requiredMark={false}
scrollToFirstError
>
<PageHeader
title="Feature Flag"
buttons={
<div style={{ display: 'flex' }}>
<Form.Item className="enabled-switch">
<Form.Item
shouldUpdate={(prevValues, currentValues) =>
prevValues.active !== currentValues.active
}
style={{ marginBottom: 0, marginRight: 6 }}
>
{({ getFieldValue }) => {
return (
<span className="ant-form-item-label" style={{ lineHeight: '1.5rem' }}>
{getFieldValue('active') ? (
<span className="text-success">Enabled</span>
) : (
<span className="text-danger">Disabled</span>
)}
</span>
)
}}
</Form.Item>
<Form.Item name="active" noStyle valuePropName="checked">
<Switch />
</Form.Item>
</Form.Item>
{featureFlagId !== 'new' && (
<Button
data-attr="delete-flag"
danger
icon={<DeleteOutlined />}
onClick={() => {
deleteFeatureFlag(featureFlag)
}}
style={{ marginRight: 16 }}
>
Delete
</Button>
)}
<Button
icon={<SaveOutlined />}
type="primary"
data-attr="feature-flag-submit"
htmlType="submit"
>
Save changes
</Button>
</div>
}
/>
<h3 className="l3">General configuration</h3>
<div className="text-muted mb">
General settings for your feature flag and integration instructions.
</div>
<Row gutter={16} style={{ marginBottom: 32 }}>
<Col span={12}>
<Form.Item
name="key"
label="Key (must be unique)"
rules={[
{ required: true, message: 'You need to set a key.' },
{
pattern: /^([A-z]|[a-z]|[0-9]|-|_)+$/,
message: 'Only letters, numbers, hyphens (-) & underscores (_) are allowed.',
},
]}
validateStatus={hasKeyChanged ? 'warning' : undefined}
help={
hasKeyChanged ? (
<small>
<b>Warning! </b>Changing this key will
<a
href={`https://posthog.com/docs/features/feature-flags${UTM_TAGS}#feature-flag-persistence`}
target="_blank"
rel="noopener"
>
{' '}
affect the persistence of your flag <IconOpenInNew />
</a>
</small>
) : undefined
}
>
<Input
data-attr="feature-flag-key"
className="ph-ignore-input"
autoFocus
placeholder="examples: new-landing-page, betaFeature, ab_test_1"
autoComplete="off"
autoCapitalize="off"
autoCorrect="off"
spellCheck={false}
/>
</Form.Item>
<Form.Item name="name" label="Description">
<Input.TextArea
className="ph-ignore-input"
data-attr="feature-flag-description"
placeholder="Adding a helpful description can ensure others know what this feature is for."
/>
</Form.Item>
</Col>
<Col span={12} style={{ paddingTop: 31 }}>
<Collapse>
<Collapse.Panel
header={
<div style={{ display: 'flex', fontWeight: 'bold', alignItems: 'center' }}>
<IconJavascript style={{ marginRight: 6 }} /> Javascript integration
instructions
</div>
}
key="js"
>
<Form.Item
shouldUpdate={(prevValues, currentValues) =>
prevValues.key !== currentValues.key
}
>
{({ getFieldValue }) => <JSSnippet flagKey={getFieldValue('key')} />}
</Form.Item>
</Collapse.Panel>
<Collapse.Panel
header={
<div style={{ display: 'flex', fontWeight: 'bold', alignItems: 'center' }}>
<IconPython style={{ marginRight: 6 }} /> Python integration instructions
</div>
}
key="python"
>
<Form.Item
shouldUpdate={(prevValues, currentValues) =>
prevValues.key !== currentValues.key
}
>
{({ getFieldValue }) => <PythonSnippet flagKey={getFieldValue('key')} />}
</Form.Item>
</Collapse.Panel>
<Collapse.Panel
header={
<div style={{ display: 'flex', fontWeight: 'bold', alignItems: 'center' }}>
<ApiFilled style={{ marginRight: 6 }} /> API integration instructions
</div>
}
key="api"
>
<Form.Item
shouldUpdate={(prevValues, currentValues) =>
prevValues.key !== currentValues.key
}
>
<APISnippet />
</Form.Item>
</Collapse.Panel>
</Collapse>
</Col>
</Row>
<div className="mb-2">
<h3 className="l3">Served value</h3>
<div className="mb-05">
<Popconfirm
placement="top"
title="Change value type? The variants below will be lost."
visible={showVariantDiscardWarning}
onConfirm={() => {
setMultivariateEnabled(false)
setShowVariantDiscardWarning(false)
}}
onCancel={() => setShowVariantDiscardWarning(false)}
okText="OK"
cancelText="Cancel"
>
<Radio.Group
options={[
{
label: 'Boolean value (A/B test)',
value: false,
},
{
label: (
<Tooltip
title={
hasAvailableFeature(AvailableFeature.MULTIVARIATE_FLAGS)
? ''
: 'This feature is not available on your current plan.'
}
>
<div>
{!hasAvailableFeature(AvailableFeature.MULTIVARIATE_FLAGS) && (
<Link to={upgradeLink} target="_blank">
<LockOutlined
style={{ marginRight: 4, color: 'var(--warning)' }}
/>
</Link>
)}
String value (Multivariate test){' '}
<LemonTag type="warning">Beta</LemonTag>
</div>
</Tooltip>
),
value: true,
disabled: !hasAvailableFeature(AvailableFeature.MULTIVARIATE_FLAGS),
},
]}
onChange={(e) => {
const { value } = e.target
if (value === false && nonEmptyVariants.length) {
setShowVariantDiscardWarning(true)
} else {
setMultivariateEnabled(value)
focusVariantKeyField(0)
}
}}
value={multivariateEnabled}
optionType="button"
/>
</Popconfirm>
</div>
<div className="text-muted mb">
{capitalizeFirstLetter(aggregationTargetName)} will be served{' '}
{multivariateEnabled ? (
<>
<strong>a variant key</strong> according to the below distribution
</>
) : (
<strong>
<code>true</code>
</strong>
)}{' '}
if they match one or more release condition groups.
</div>
{multivariateEnabled && (
<div className="variant-form-list">
<Row gutter={8} className="label-row">
<Col span={7}>Variant key</Col>
<Col span={7}>Description</Col>
<Col span={9}>
<span>Rollout percentage</span>
<Button
type="link"
onClick={distributeVariantsEqually}
icon={<MergeCellsOutlined />}
style={{ padding: '0 0 0 0.5em' }}
title="Distribute variants equally"
>
Distribute
</Button>
</Col>
</Row>
{variants.map(({ rollout_percentage }, index) => (
<Form
key={index}
onValuesChange={(changedValues) => updateVariant(index, changedValues)}
initialValues={variants[index]}
validateTrigger={['onChange', 'onBlur']}
>
<Row gutter={8}>
<Col span={7}>
<Form.Item
name="key"
rules={[
{ required: true, message: 'Key should not be empty.' },
{
pattern: /^([A-z]|[a-z]|[0-9]|-|_)+$/,
message:
'Only letters, numbers, hyphens (-) & underscores (_) are allowed.',
},
]}
>
<Input
data-attr="feature-flag-variant-key"
data-key-index={index.toString()}
className="ph-ignore-input"
placeholder={`example-variant-${index + 1}`}
autoComplete="off"
autoCapitalize="off"
autoCorrect="off"
spellCheck={false}
/>
</Form.Item>
</Col>
<Col span={7}>
<Form.Item name="name">
<Input
data-attr="feature-flag-variant-name"
className="ph-ignore-input"
placeholder="Description"
/>
</Form.Item>
</Col>
<Col span={7}>
<Slider
tooltipPlacement="top"
value={rollout_percentage}
onChange={(value: number) =>
updateVariant(index, { rollout_percentage: value })
}
/>
</Col>
<Col span={2}>
<InputNumber
min={0}
max={100}
value={rollout_percentage}
onChange={(value) => {
if (value !== null && value !== undefined) {
const valueInt = parseInt(value.toString())
if (!isNaN(valueInt)) {
updateVariant(index, {
rollout_percentage: valueInt,
})
}
}
}}
style={{
width: '100%',
borderColor: areVariantRolloutsValid
? undefined
: 'var(--danger)',
}}
/>
</Col>
{variants.length > 1 && (
<Col span={1}>
<Tooltip title="Delete this variant" placement="bottomLeft">
<Button
type="link"
icon={<DeleteOutlined />}
onClick={() => removeVariant(index)}
style={{ color: 'var(--danger)' }}
/>
</Tooltip>
</Col>
)}
</Row>
</Form>
))}
{variants.length > 0 && !areVariantRolloutsValid && (
<p className="text-danger">
Percentage rollouts for variants must sum to 100 (currently {variantRolloutSum}
).
</p>
)}
<Button
type="dashed"
block
icon={<PlusOutlined />}
onClick={() => {
const newIndex = variants.length
addVariant()
focusVariantKeyField(newIndex)
}}
style={{ marginBottom: 16 }}
>
Add Variant
</Button>
</div>
)}
</div>
<div className="feature-flag-form-row">
<div>
<h3 className="l3">Release conditions</h3>
<div className="text-muted mb">
Specify the {aggregationTargetName} to which you want to release this flag. Note that
condition sets are rolled out independently of each other.
</div>
</div>
{showGroupsOptions && (
<div className="centered">
Match by
<Select
value={
featureFlag.filters.aggregation_group_type_index != null
? featureFlag.filters.aggregation_group_type_index
: -1
}
onChange={(value) => {
const groupTypeIndex = value !== -1 ? value : null
setAggregationGroupTypeIndex(groupTypeIndex)
}}
style={{ marginLeft: 8 }}
data-attr="feature-flag-aggregation-filter"
dropdownMatchSelectWidth={false}
dropdownAlign={{
// Align this dropdown by the right-hand-side of button
points: ['tr', 'br'],
}}
>
<Select.Option key={-1} value={-1}>
Users
</Select.Option>
{groupTypes.map((groupType) => (
<Select.Option
key={groupType.group_type_index}
value={groupType.group_type_index}
>
{capitalizeFirstLetter(aggregationLabel(groupType.group_type_index).plural)}
</Select.Option>
))}
{matchByGroupsIntroductionOption}
</Select>
</div>
)}
</div>
<Row gutter={16}>
{featureFlag.filters.groups.map((group, index) => (
<Col span={24} md={24} key={`${index}-${featureFlag.filters.groups.length}`}>
{index > 0 && (
<div style={{ display: 'flex', marginLeft: 16 }}>
<div className="stateful-badge or-light-grey mb">OR</div>
</div>
)}
<Card style={{ marginBottom: 16 }}>
<div className="feature-flag-form-row" style={{ height: 24 }}>
<div>
<span className="simple-tag tag-light-blue" style={{ marginRight: 8 }}>
Set {index + 1}
</span>
{group.properties?.length ? (
<>
Matching <b>{aggregationTargetName}</b> with filters
</>
) : (
<>
Condition set will match <b>all {aggregationTargetName}</b>
</>
)}
</div>
<div>
<Tooltip title="Duplicate this condition set" placement="bottomLeft">
<Button
type="link"
icon={<CopyOutlined />}
style={{ width: 24, height: 24 }}
onClick={() => duplicateConditionSet(index)}
/>
</Tooltip>
{featureFlag.filters.groups.length > 1 && (
<Tooltip title="Delete this condition set" placement="bottomLeft">
<Button
type="link"
icon={<DeleteOutlined />}
style={{ width: 24, height: 24 }}
onClick={() => removeConditionSet(index)}
/>
</Tooltip>
)}
</div>
</div>
<LemonSpacer large />
<PropertyFilters
style={{ marginLeft: 15 }}
pageKey={`feature-flag-${featureFlag.id}-${index}-${
featureFlag.filters.groups.length
}-${featureFlag.filters.aggregation_group_type_index ?? ''}`}
propertyFilters={group?.properties}
onChange={(properties) => updateConditionSet(index, undefined, properties)}
taxonomicGroupTypes={taxonomicGroupTypes}
showConditionBadge
greyBadges
/>
<LemonSpacer large />
<div className="feature-flag-form-row">
<div className="centered">
Roll out to{' '}
<InputNumber
style={{ width: 100, marginLeft: 8, marginRight: 8 }}
onChange={(value): void => {
updateConditionSet(index, value as number)
}}
value={
group.rollout_percentage != null ? group.rollout_percentage : 100
}
min={0}
max={100}
addonAfter="%"
/>{' '}
of <b>{aggregationTargetName}</b> in this set
</div>
</div>
</Card>
</Col>
))}
</Row>
<Card size="small" style={{ marginBottom: 16 }}>
<Button type="link" onClick={addConditionSet} style={{ marginLeft: 5 }}>
<PlusOutlined style={{ marginRight: 15 }} /> Add condition set
</Button>
</Card>
<Form.Item className="text-right">
<Button
icon={<SaveOutlined />}
htmlType="submit"
type="primary"
data-attr="feature-flag-submit-bottom"
>
Save changes
</Button>
</Form.Item>
</Form>
) : (
// TODO: This should be skeleton loaders
<SceneLoading />
)}
</div>
)
}
Example #18
Source File: TableConfig.tsx From posthog-foss with MIT License | 4 votes |
function ColumnConfigurator({ immutableColumns, defaultColumns, availableColumns }: TableConfigProps): JSX.Element {
// the virtualised list doesn't support gaps between items in the list
// setting the container to be larger than we need
// and adding a container with a smaller height to each row item
// allows the new row item to set a margin around itself
const rowContainerHeight = 36
const rowItemHeight = 32
const { selectedColumns, modalVisible } = useValues(tableConfigLogic)
const { hideModal } = useActions(tableConfigLogic)
const logic = columnConfiguratorLogic({
availableColumns,
selectedColumns: selectedColumns === 'DEFAULT' ? defaultColumns : selectedColumns,
})
const { selectColumn, unselectColumn, resetColumns, save, setColumnFilter } = useActions(logic)
const { visibleColumns, hiddenColumns, scrollIndex, columnFilter, filteredVisibleColumns, filteredHiddenColumns } =
useValues(logic)
function AvailableColumn({ index, style, key }: ListRowProps): JSX.Element {
return (
<div style={style} key={key} onClick={() => selectColumn(filteredHiddenColumns[index])}>
<div className="column-display-item" style={{ height: `${rowItemHeight}px` }}>
<PropertyKeyInfo value={filteredHiddenColumns[index]} />
<div className="text-right" style={{ flex: 1 }}>
<Tooltip title="Add">
<PlusOutlined style={{ color: 'var(--success)' }} />
</Tooltip>
</div>
</div>
</div>
)
}
function SelectedColumn({ index, style, key }: ListRowProps): JSX.Element {
const disabled = immutableColumns?.includes(filteredVisibleColumns[index])
return (
<div style={style} key={key} onClick={() => !disabled && unselectColumn(filteredVisibleColumns[index])}>
<div
className={clsx(['column-display-item', { selected: !disabled, disabled: disabled }])}
style={{ height: `${rowItemHeight}px` }}
>
<PropertyKeyInfo value={filteredVisibleColumns[index]} />
<div className="text-right" style={{ flex: 1 }}>
<Tooltip title={disabled ? 'Reserved' : 'Remove'}>
{disabled ? <LockOutlined /> : <CloseOutlined style={{ color: 'var(--danger)' }} />}
</Tooltip>
</div>
</div>
</div>
)
}
return (
<Modal
centered
visible={modalVisible}
title="Customize columns"
onOk={save}
width={700}
bodyStyle={{ padding: '16px 16px 0 16px' }}
className="column-configurator-modal"
okButtonProps={{
// @ts-ignore
'data-attr': 'items-selector-confirm',
}}
okText="Save"
onCancel={hideModal}
footer={
<Row>
<Space style={{ flexGrow: 1 }} align="start">
<Button className="text-blue" onClick={() => resetColumns(defaultColumns)}>
Reset to default
</Button>
</Space>
<Space>
<Button className="text-blue" type="text" onClick={hideModal}>
Cancel
</Button>
<Button type="primary" onClick={save}>
Save
</Button>
</Space>
</Row>
}
>
<Search
allowClear
autoFocus
placeholder="Search"
type="search"
value={columnFilter}
onChange={(e) => setColumnFilter(e.target.value)}
/>
<Row gutter={16} className="mt">
<Col xs={24} sm={12}>
<h3 className="l3">Hidden columns ({hiddenColumns.length})</h3>
<div style={{ height: 320 }}>
<AutoSizer>
{({ height, width }: { height: number; width: number }) => {
return (
<VirtualizedList
height={height}
rowCount={filteredHiddenColumns.length}
rowRenderer={AvailableColumn}
rowHeight={rowContainerHeight}
width={width}
/>
)
}}
</AutoSizer>
</div>
</Col>
<Col xs={24} sm={12}>
<h3 className="l3">Visible columns ({visibleColumns.length})</h3>
<div style={{ height: 320 }}>
<AutoSizer>
{({ height, width }: { height: number; width: number }) => {
return (
<VirtualizedList
height={height}
rowCount={filteredVisibleColumns.length}
rowRenderer={SelectedColumn}
rowHeight={rowContainerHeight}
width={width}
scrollToIndex={scrollIndex}
/>
)
}}
</AutoSizer>
</div>
</Col>
</Row>
</Modal>
)
}
Example #19
Source File: EditableField.tsx From posthog-foss with MIT License | 4 votes |
export function EditableField({
name,
value,
onChange,
className,
dataAttr,
placeholder,
locked,
multiline,
}: EditableFieldProps): JSX.Element {
const [isEditing, setIsEditing] = useState(false)
const [editedValue, setEditedValue] = useState(value)
useEffect(() => {
setEditedValue(value)
}, [value])
return (
<div
className={`editable-field${className ? ` ${className}` : ''} ${isEditing ? 'edit-mode' : 'view-mode'}`}
data-attr={dataAttr}
>
{isEditing ? (
<div className="edit-container ant-input-affix-wrapper ant-input-affix-wrapper-lg editable-textarea-wrapper">
<Input.TextArea
autoFocus
placeholder={placeholder}
value={multiline ? editedValue : editedValue.split('\n').join('')}
onChange={(e) => setEditedValue(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
onChange(editedValue)
setIsEditing(false)
}
}}
autoSize={{ minRows: 1, maxRows: 5 }}
/>
<Button className="btn-cancel" size="small" onClick={() => setIsEditing(false)}>
Cancel
</Button>
<Button
className="ml-025"
type="primary"
size="small"
onClick={() => {
onChange(editedValue)
setIsEditing(false)
}}
>
Done
</Button>
</div>
) : (
<div className="view-container">
<span className="field">{value || <i>{placeholder}</i>}</span>
{!locked ? (
<Button
type="link"
onClick={() => {
setEditedValue(value)
setIsEditing(true)
}}
className="btn-edit"
data-attr={`edit-prop-${name}`}
title={`Edit ${name}`}
>
<EditOutlined />
</Button>
) : (
<Tooltip
title="This field is part of PostHog's team-oriented feature set and requires a premium plan. Check PostHog pricing."
isDefaultTooltip
>
<LockOutlined style={{ marginLeft: 6, color: 'var(--text-muted)' }} />
</Tooltip>
)}
</div>
)}
</div>
)
}
Example #20
Source File: Login.tsx From jmix-frontend with Apache License 2.0 | 4 votes |
Login = observer(() => {
const intl = useIntl();
const mainStore = useMainStore();
const [login, setLogin] = useState("");
const [password, setPassword] = useState("");
const [performingLoginRequest, setPerformingLoginRequest] = useState(false);
const changeLogin = useCallback(
(e: ChangeEvent<HTMLInputElement>) => setLogin(e.target.value),
[setLogin]
);
const changePassword = useCallback(
(e: ChangeEvent<HTMLInputElement>) => setPassword(e.target.value),
[setPassword]
);
const doLogin = useCallback(() => {
setPerformingLoginRequest(true);
mainStore
.login(login, password)
.then(
action(() => {
setPerformingLoginRequest(false);
})
)
.catch(
action((error: JmixServerError) => {
setPerformingLoginRequest(false);
const loginMessageErrorIntlId = loginMapJmixRestErrorToIntlId(error);
message.error(intl.formatMessage({ id: loginMessageErrorIntlId }));
})
);
}, [setPerformingLoginRequest, mainStore, intl, login, password]);
return (
<Card className={styles.loginForm}>
<JmixDarkIcon className={styles.logo} />
<div className={styles.title}>scr-jmix</div>
<Form layout="vertical" onFinish={doLogin}>
<Form.Item>
<Input
id="input_login"
placeholder={intl.formatMessage({ id: "login.placeholder.login" })}
onChange={changeLogin}
value={login}
prefix={<UserOutlined style={{ margin: "0 11px 0 0" }} />}
size="large"
/>
</Form.Item>
<Form.Item>
<Input
id="input_password"
placeholder={intl.formatMessage({
id: "login.placeholder.password"
})}
onChange={changePassword}
value={password}
type="password"
prefix={<LockOutlined style={{ margin: "0 11px 0 0" }} />}
size="large"
/>
</Form.Item>
<Form.Item>
<div className={styles.languageSwitcherContainer}>
<LanguageSwitcher />
</div>
</Form.Item>
<Form.Item>
<Button
type="primary"
htmlType="submit"
size="large"
block={true}
loading={performingLoginRequest}
>
<FormattedMessage id="login.loginBtn" />
</Button>
</Form.Item>
</Form>
</Card>
);
})
Example #21
Source File: index.tsx From shippo with MIT License | 4 votes |
Page_passport = () => {
const history = useNavigate()
const handleSmsSend = (phone: string) => {
console.log('handleSmsSend', { phone })
if (!checkPhone(phone)) {
return message.info('手机号格式错误')
}
services.captcha.send({ phone })
message.success('验证码已经发送')
}
const [form] = Form.useForm<{ phone: string; captcha: string }>()
const onFinish = async (values: { phone: string; captcha: string }) => {
console.log('Received values of form: ', values)
const { phone, captcha: code } = values
if (!checkPhone(phone)) {
return message.info('手机号格式错误')
}
if (!checkSmsCode(code)) {
return message.info('短信验证码格式错误')
}
const { data } = await services.user.login({
phone,
code,
})
window.localStorage.setItem('__PASSPORT', data.resource.passport)
history('/')
}
return (
<Layout>
<Header
style={{
background: 'transparent',
textAlign: 'center',
height: '200px',
lineHeight: '200px',
}}
>
<span
style={{
color: 'rgba(0,0,0,.85)',
fontWeight: 600,
fontSize: '33px',
}}
>
Shippo
</span>
</Header>
<Content>
<div style={{ width: '328px', margin: '0 auto' }}>
<Form form={form} name="register" onFinish={onFinish} scrollToFirstError>
<Form.Item name="phone" rules={[{ required: true, message: '请输入你的手机号!' }]}>
<Input
prefix={<LockOutlined className="site-form-item-icon" />}
placeholder="请输入你的手机号!"
style={{ width: '100%' }}
allowClear
size="large"
/>
</Form.Item>
<Form.Item>
<div
style={{
display: 'flex',
alignItems: 'center',
}}
>
<Form.Item
name="captcha"
noStyle
rules={[{ required: true, message: '请输入验证码!' }]}
>
<Input
prefix={<UserOutlined className="site-form-item-icon" />}
placeholder="请输入验证码!"
style={{
flex: 1,
marginRight: 8,
}}
size="large"
/>
</Form.Item>
<Button
style={{
display: 'block',
}}
onClick={() => handleSmsSend(form.getFieldValue('phone'))}
size="large"
>
获取验证码
</Button>
</div>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" style={{ width: '100%' }} size="large">
登录
</Button>
</Form.Item>
</Form>
</div>
</Content>
<Footer
style={{
textAlign: 'center',
marginBottom: '25px',
color: 'rgba(0,0,0,.45)',
fontSize: '14px',
}}
>
<CopyrightOutlined /> 2021 Shippo
</Footer>
</Layout>
)
}
Example #22
Source File: index.tsx From shippo with MIT License | 4 votes |
Page_passport = () => {
const history = useNavigate()
const handleSmsSend = (phone: string) => {
console.log('handleSmsSend', { phone })
if (!checkPhone(phone)) {
return message.info('手机号格式错误')
}
services.captcha.send({ phone })
message.success('验证码已经发送')
}
const [form] = Form.useForm<{ phone: string; captcha: string }>()
const onFinish = async (values: { phone: string; captcha: string }) => {
console.log('Received values of form: ', values)
const { phone, captcha: code } = values
if (!checkPhone(phone)) {
return message.info('手机号格式错误')
}
if (!checkSmsCode(code)) {
return message.info('短信验证码格式错误')
}
const { data } = await services.user.login({
phone,
code,
})
window.localStorage.setItem('__PASSPORT', data.resource.passport)
history('/')
}
return (
<Layout>
<Header
style={{
background: 'transparent',
textAlign: 'center',
height: '200px',
lineHeight: '200px',
}}
>
<span
style={{
color: 'rgba(0,0,0,.85)',
fontWeight: 600,
fontSize: '33px',
}}
>
Shippo Admin
</span>
</Header>
<Content>
<div style={{ width: '328px', margin: '0 auto' }}>
<Form form={form} name="register" onFinish={onFinish} scrollToFirstError>
<Form.Item name="phone" rules={[{ required: true, message: '请输入你的手机号!' }]}>
<Input
prefix={<LockOutlined className="site-form-item-icon" />}
placeholder="请输入你的手机号!"
style={{ width: '100%' }}
allowClear
size="large"
/>
</Form.Item>
<Form.Item>
<div
style={{
display: 'flex',
alignItems: 'center',
}}
>
<Form.Item
name="captcha"
noStyle
rules={[{ required: true, message: '请输入验证码!' }]}
>
<Input
prefix={<UserOutlined className="site-form-item-icon" />}
placeholder="请输入验证码!"
style={{
flex: 1,
marginRight: 8,
}}
size="large"
/>
</Form.Item>
<Button
style={{
display: 'block',
}}
onClick={() => handleSmsSend(form.getFieldValue('phone'))}
size="large"
>
获取验证码
</Button>
</div>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" style={{ width: '100%' }} size="large">
登录
</Button>
</Form.Item>
</Form>
</div>
</Content>
<Footer
style={{
textAlign: 'center',
marginBottom: '25px',
color: 'rgba(0,0,0,.45)',
fontSize: '14px',
}}
>
<CopyrightOutlined /> 2021 Shippo
</Footer>
</Layout>
)
}