import React, { useState, useEffect } from "react"; import { Card, Button, FormBuilder, Loader } from "../../components/"; import { settings_get, settings_put, createFormBackend, FormObjToJSON, nop, } from "../../helpers/"; import { Backend } from "../../model/"; import { t } from "../../locales/"; import "./form.scss"; /* * This is the automatic form generation that we uses in: * login page, admin console, form filetype (eg: mysql & ldap plugin) * * FAQ: * Why reinvent the wheel? no existing library were fitting all the use cases so we made our own * How does that work? * 1. window.CONFIG["connection"] contains all the valid connections one can make with all sort of prefilled data * 2. Backend.all gives the specs of the login form as generated by the relevant backend plugin * 3. The FormBuilder component generates the form from the specs generated by createFormBackend */ export function Form({ onLoadingChange = nop, onError = nop, onSubmit = nop, }) { const [enabledBackends, setEnabledBackends] = useState([]); const [selectedTab, setSelectedTab] = useState(null); const [hasUserInteracted, setHasUserInteracted] = useState(false); useEffect(() => { Backend.all().then((backend) => { onLoadingChange(false); const backends = window.CONFIG["connections"].reduce((acc, conn) => { const f = createFormBackend(backend, conn); if (Object.keys(f).length > 0) { acc.push(f); } return acc; }, []); setEnabledBackends(backends); setSelectedTab((function() { const select = settings_get("login_tab"); if (select !== null && select < backends.length) { setSelectedTab(select); } if (backends.length === 0) return null; else if (backends.length < 4) return 0; else if (backends.length < 5) return 1; return 2; }())); }).catch((err) => onError(err)); return () => { settings_put("login_tab", selectedTab); }; }, []); const onFormChange = (p) => { setEnabledBackends(enabledBackends.map((backend) => (backend))); }; const onSubmitForm = (e) => { e.preventDefault(); const formData = FormObjToJSON((() => { const tmp = enabledBackends[selectedTab]; return tmp[Object.keys(tmp)[0]]; })()); delete formData["image"]; delete formData["label"]; delete formData["advanced"]; onSubmit(formData); }; const onTypeChange = (tabn) => { setHasUserInteracted(true); setSelectedTab(tabn); }; const renderForm = ($input, props, struct, onChange) => { if (struct.type === "image") { return (
{ $input }
); } else if (struct.enabled === true) { return null; } else if (struct.label === "advanced") { return ( ); } return ( ); }; return (
{ enabledBackends.length > 1 && ( { enabledBackends.map((backend, i) => { const key = Object.keys(backend)[0]; if (!backend[key]) return null; return ( ); }) } ) } { enabledBackends.map((form, i) => { const key = Object.keys(form)[0]; if (selectedTab !== i) return null; const auth = window.CONFIG["auth"]; if (auth.indexOf(key) !== -1 || auth.indexOf(form[key].label.value) !== -1) { return hasUserInteracted === false && enabledBackends.length > 1 ? ( ) : ( onSubmit({ middleware: true, label: form[key].label.value, })} /> ); } return (
onSubmitForm(e)}>
); }) }
); } function LoaderWithTimeout({ callback = nop, timeout = 0 }) { useEffect(() => { const t = setTimeout(() => callback(), timeout); return () => { clearTimeout(t); }; }); return ( ); }