mirror of
https://github.com/wassname/talk.git
synced 2026-09-11 12:51:33 +08:00
[CORL-423] Rearrange client files and folder (#2352)
* chore: reorganize account * chore: reorganize install * chore: reorganize auth files * chore: reorganize admin files * fix: graphql naming * chore: adapt account routing
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { Component } from "react";
|
||||
|
||||
import WizardContainer from "../containers/WizardContainer";
|
||||
import InstallWizard from "./InstallWizard";
|
||||
import MainBar from "./MainBar";
|
||||
|
||||
import styles from "./App.css";
|
||||
@@ -11,7 +11,7 @@ class App extends Component {
|
||||
<div className={styles.root}>
|
||||
<MainBar />
|
||||
<div className={styles.container}>
|
||||
<WizardContainer />
|
||||
<InstallWizard />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
+14
-14
@@ -1,15 +1,15 @@
|
||||
import React, { Component } from "react";
|
||||
|
||||
import Wizard from "../components/Wizard";
|
||||
import { InstallMutation, withInstallMutation } from "../mutations";
|
||||
import FinalStep from "../steps/components/FinalStep";
|
||||
import InitialStep from "../steps/components/InitialStep";
|
||||
import AddOrganizationContainer from "../steps/containers/AddOrganizationContainer";
|
||||
import CreateYourAccountContainer from "../steps/containers/CreateYourAccountContainer";
|
||||
import PermittedDomainsContainer from "../steps/containers/PermittedDomainsContainer";
|
||||
|
||||
import { InstallInput } from "coral-framework/rest";
|
||||
|
||||
import { InstallMutation, withInstallMutation } from "./InstallMutation";
|
||||
import AddOrganizationStep from "./steps/AddOrganizationStep";
|
||||
import CreateYourAccountStep from "./steps/CreateYourAccountStep";
|
||||
import FinalStep from "./steps/FinalStep";
|
||||
import InitialStep from "./steps/InitialStep";
|
||||
import PermittedDomainsStep from "./steps/PermittedDomainsStep";
|
||||
import Wizard from "./Wizard";
|
||||
|
||||
interface FormData {
|
||||
organizationName: string;
|
||||
organizationContactEmail: string;
|
||||
@@ -21,7 +21,7 @@ interface FormData {
|
||||
allowedDomains: string[];
|
||||
}
|
||||
|
||||
interface WizardContainerState {
|
||||
interface InstallWizardState {
|
||||
step: number;
|
||||
data: FormData;
|
||||
}
|
||||
@@ -58,7 +58,7 @@ interface Props {
|
||||
install: InstallMutation;
|
||||
}
|
||||
|
||||
class WizardContainer extends Component<Props, WizardContainerState> {
|
||||
class InstallWizard extends Component<Props, InstallWizardState> {
|
||||
public state = {
|
||||
step: 0,
|
||||
data: {
|
||||
@@ -99,19 +99,19 @@ class WizardContainer extends Component<Props, WizardContainerState> {
|
||||
return (
|
||||
<Wizard currentStep={this.state.step}>
|
||||
<InitialStep onGoToNextStep={this.handleGoToNextStep} />
|
||||
<CreateYourAccountContainer
|
||||
<CreateYourAccountStep
|
||||
data={this.state.data}
|
||||
onSaveData={this.handleSaveData}
|
||||
onGoToNextStep={this.handleGoToNextStep}
|
||||
onGoToPreviousStep={this.handleGoToPreviousStep}
|
||||
/>
|
||||
<AddOrganizationContainer
|
||||
<AddOrganizationStep
|
||||
data={this.state.data}
|
||||
onSaveData={this.handleSaveData}
|
||||
onGoToNextStep={this.handleGoToNextStep}
|
||||
onGoToPreviousStep={this.handleGoToPreviousStep}
|
||||
/>
|
||||
<PermittedDomainsContainer
|
||||
<PermittedDomainsStep
|
||||
data={this.state.data}
|
||||
onGoToNextStep={this.handleGoToNextStep}
|
||||
onGoToPreviousStep={this.handleGoToPreviousStep}
|
||||
@@ -123,4 +123,4 @@ class WizardContainer extends Component<Props, WizardContainerState> {
|
||||
}
|
||||
}
|
||||
|
||||
export default withInstallMutation(WizardContainer);
|
||||
export default withInstallMutation(InstallWizard);
|
||||
+1
-1
@@ -4,8 +4,8 @@ import React, { Component, ReactNode } from "react";
|
||||
|
||||
import { Step, StepBar } from "coral-ui/components";
|
||||
|
||||
import { WizardProps } from "../components/Wizard";
|
||||
import Header from "./Header";
|
||||
import { WizardProps } from "./Wizard";
|
||||
|
||||
import styles from "./Wizard.css";
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ exports[`renders correctly 1`] = `
|
||||
<div
|
||||
className="App-container"
|
||||
>
|
||||
<withContext(createMutationContainer(WizardContainer)) />
|
||||
<withContext(createMutationContainer(InstallWizard)) />
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1 @@
|
||||
export { default, default as App } from "./App";
|
||||
@@ -0,0 +1,208 @@
|
||||
import { Localized } from "fluent-react/compat";
|
||||
import React from "react";
|
||||
import { Field, Form } from "react-final-form";
|
||||
|
||||
import { OnSubmit } from "coral-framework/lib/form";
|
||||
import {
|
||||
composeValidators,
|
||||
required,
|
||||
validateEmail,
|
||||
validateURL,
|
||||
} from "coral-framework/lib/validation";
|
||||
import {
|
||||
CallOut,
|
||||
Flex,
|
||||
FormField,
|
||||
HorizontalGutter,
|
||||
InputDescription,
|
||||
InputLabel,
|
||||
TextField,
|
||||
Typography,
|
||||
ValidationMessage,
|
||||
} from "coral-ui/components";
|
||||
|
||||
import BackButton from "./BackButton";
|
||||
import NextButton from "./NextButton";
|
||||
|
||||
interface Props {
|
||||
onGoToNextStep: () => void;
|
||||
onGoToPreviousStep: () => void;
|
||||
data: FormProps;
|
||||
onSaveData: (newData: FormProps) => void;
|
||||
}
|
||||
|
||||
interface FormProps {
|
||||
organizationName: string;
|
||||
organizationContactEmail: string;
|
||||
organizationURL: string;
|
||||
}
|
||||
|
||||
class AddOrganizationStep extends React.Component<Props> {
|
||||
private onSubmit: OnSubmit<FormProps> = async (input, form) => {
|
||||
this.props.onSaveData(input);
|
||||
return this.props.onGoToNextStep();
|
||||
};
|
||||
public render() {
|
||||
return (
|
||||
<Form
|
||||
onSubmit={this.onSubmit}
|
||||
initialValues={{
|
||||
organizationName: this.props.data.organizationName,
|
||||
organizationContactEmail: this.props.data.organizationContactEmail,
|
||||
organizationURL: this.props.data.organizationURL,
|
||||
}}
|
||||
>
|
||||
{({ handleSubmit, submitting, submitError }) => (
|
||||
<form autoComplete="off" onSubmit={handleSubmit}>
|
||||
<HorizontalGutter size="double">
|
||||
<Localized id="install-addOrganization-title">
|
||||
<Typography variant="heading1" align="center">
|
||||
Add Organization
|
||||
</Typography>
|
||||
</Localized>
|
||||
<Localized id="install-addOrganization-description">
|
||||
<Typography variant="bodyCopy" align="center">
|
||||
Please tell us the name of your organization. This will appear
|
||||
in emails when inviting new team members.
|
||||
</Typography>
|
||||
</Localized>
|
||||
|
||||
{submitError && (
|
||||
<CallOut color="error" fullWidth>
|
||||
{submitError}
|
||||
</CallOut>
|
||||
)}
|
||||
|
||||
<Field
|
||||
name="organizationName"
|
||||
validate={composeValidators(required)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-addOrganization-orgName">
|
||||
<InputLabel>Organization Name</InputLabel>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-addOrganization-orgNameTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Organization Name"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
name="organizationContactEmail"
|
||||
validate={composeValidators(required, validateEmail)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-addOrganization-orgEmail">
|
||||
<InputLabel>Organization Contact Email</InputLabel>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-addOrganization-orgEmailTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Organization Contact Email"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
name="organizationURL"
|
||||
validate={composeValidators(required, validateURL)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-addOrganization-orgURL">
|
||||
<InputLabel>Organization URL</InputLabel>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-addOrganization-orgURLDescription"
|
||||
strong={<strong />}
|
||||
>
|
||||
<InputDescription>
|
||||
{/* Related: https://github.com/prettier/prettier/issues/2347 */}
|
||||
Be sure to include <strong>{"http://"}</strong> or{" "}
|
||||
<strong>{"https://"}</strong> in your URL
|
||||
</InputDescription>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-addOrganization-orgURLTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Organization URL"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
<Flex direction="row-reverse" itemGutter>
|
||||
<NextButton submitting={submitting} />
|
||||
<BackButton
|
||||
submitting={submitting}
|
||||
onGoToPreviousStep={this.props.onGoToPreviousStep}
|
||||
/>
|
||||
</Flex>
|
||||
</HorizontalGutter>
|
||||
</form>
|
||||
)}
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default AddOrganizationStep;
|
||||
@@ -0,0 +1,238 @@
|
||||
import { Localized } from "fluent-react/compat";
|
||||
import React, { Component } from "react";
|
||||
import { Field, Form } from "react-final-form";
|
||||
|
||||
import { OnSubmit } from "coral-framework/lib/form";
|
||||
import {
|
||||
composeValidators,
|
||||
required,
|
||||
validateEmail,
|
||||
validateEqualPasswords,
|
||||
validatePassword,
|
||||
validateUsername,
|
||||
} from "coral-framework/lib/validation";
|
||||
import {
|
||||
CallOut,
|
||||
Flex,
|
||||
FormField,
|
||||
HorizontalGutter,
|
||||
InputDescription,
|
||||
InputLabel,
|
||||
TextField,
|
||||
Typography,
|
||||
ValidationMessage,
|
||||
} from "coral-ui/components";
|
||||
|
||||
import NextButton from "./NextButton";
|
||||
|
||||
interface FormProps {
|
||||
email: string;
|
||||
username: string;
|
||||
password: string;
|
||||
confirmPassword: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
onGoToNextStep: () => void;
|
||||
onGoToPreviousStep: () => void;
|
||||
data: FormProps;
|
||||
onSaveData: (newData: FormProps) => void;
|
||||
}
|
||||
|
||||
class CreateYourAccountStep extends Component<Props> {
|
||||
private onSubmit: OnSubmit<FormProps> = async (input, form) => {
|
||||
this.props.onSaveData(input);
|
||||
return this.props.onGoToNextStep();
|
||||
};
|
||||
public render() {
|
||||
return (
|
||||
<Form
|
||||
onSubmit={this.onSubmit}
|
||||
initialValues={{
|
||||
email: this.props.data.email,
|
||||
username: this.props.data.username,
|
||||
}}
|
||||
>
|
||||
{({ handleSubmit, submitting, submitError }) => (
|
||||
<form autoComplete="off" onSubmit={handleSubmit}>
|
||||
<HorizontalGutter size="double">
|
||||
<Localized id="install-createYourAccount-title">
|
||||
<Typography variant="heading1" align="center">
|
||||
Create an Administrator Account
|
||||
</Typography>
|
||||
</Localized>
|
||||
|
||||
{submitError && (
|
||||
<CallOut color="error" fullWidth>
|
||||
{submitError}
|
||||
</CallOut>
|
||||
)}
|
||||
|
||||
<Field
|
||||
name="email"
|
||||
validate={composeValidators(required, validateEmail)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-createYourAccount-email">
|
||||
<InputLabel>Email</InputLabel>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-createYourAccount-emailTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Email"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
name="username"
|
||||
validate={composeValidators(required, validateUsername)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-createYourAccount-username">
|
||||
<InputLabel>Username</InputLabel>
|
||||
</Localized>
|
||||
<Localized id="install-createYourAccount-usernameDescription">
|
||||
<InputDescription>
|
||||
An identifier displayed on your comments. You may use
|
||||
“_” and “.”
|
||||
</InputDescription>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-createYourAccount-usernameTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Username"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
name="password"
|
||||
validate={composeValidators(required, validatePassword)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-createYourAccount-password">
|
||||
<InputLabel>Password</InputLabel>
|
||||
</Localized>
|
||||
<Localized id="install-createYourAccount-passwordDescription">
|
||||
<InputDescription>
|
||||
Must be at least 8 characters
|
||||
</InputDescription>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-createYourAccount-passwordTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Password"
|
||||
type="password"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
<Field
|
||||
name="confirmPassword"
|
||||
validate={composeValidators(required, validateEqualPasswords)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-createYourAccount-confirmPassword">
|
||||
<InputLabel>Confirm Password</InputLabel>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-createYourAccount-confirmPasswordTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Confirm Password"
|
||||
type="password"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Flex direction="row-reverse">
|
||||
<NextButton submitting={submitting} />
|
||||
</Flex>
|
||||
</HorizontalGutter>
|
||||
</form>
|
||||
)}
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CreateYourAccountStep;
|
||||
@@ -0,0 +1,136 @@
|
||||
import { OnSubmit } from "coral-framework/lib/form";
|
||||
import { FORM_ERROR } from "final-form";
|
||||
import { Localized } from "fluent-react/compat";
|
||||
import React, { Component } from "react";
|
||||
import { Field, Form } from "react-final-form";
|
||||
|
||||
import {
|
||||
Button,
|
||||
CallOut,
|
||||
Flex,
|
||||
FormField,
|
||||
HorizontalGutter,
|
||||
InputDescription,
|
||||
InputLabel,
|
||||
TextField,
|
||||
Typography,
|
||||
ValidationMessage,
|
||||
} from "coral-ui/components";
|
||||
|
||||
import BackButton from "./BackButton";
|
||||
|
||||
interface FormProps {
|
||||
allowedDomains: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
onGoToNextStep: () => void;
|
||||
onGoToPreviousStep: () => void;
|
||||
data: { allowedDomains: string[] };
|
||||
onInstall: (newData: { allowedDomains: string[] }) => Promise<void>;
|
||||
}
|
||||
|
||||
class PermittedDomainsStep extends Component<Props> {
|
||||
private onSubmit: OnSubmit<FormProps> = async (input, form) => {
|
||||
try {
|
||||
const allowedDomains = input.allowedDomains.split(",");
|
||||
await this.props.onInstall({ allowedDomains });
|
||||
return this.props.onGoToNextStep();
|
||||
} catch (error) {
|
||||
return { [FORM_ERROR]: error.message };
|
||||
}
|
||||
};
|
||||
public render() {
|
||||
return (
|
||||
<Form
|
||||
onSubmit={this.onSubmit}
|
||||
initialValues={{
|
||||
allowedDomains: this.props.data.allowedDomains.join(","),
|
||||
}}
|
||||
>
|
||||
{({ handleSubmit, submitting, submitError }) => (
|
||||
<form autoComplete="off" onSubmit={handleSubmit}>
|
||||
<HorizontalGutter size="double">
|
||||
<Localized id="install-permittedDomains-title">
|
||||
<Typography variant="heading1" align="center">
|
||||
Permitted Domains
|
||||
</Typography>
|
||||
</Localized>
|
||||
<Localized id="install-permittedDomains-description">
|
||||
<Typography variant="bodyCopy" align="center">
|
||||
Enter the domains you would like to permit for Coral, e.g.
|
||||
your local, staging and production environments (ex.
|
||||
localhost:3000, staging.domain.com, domain.com).
|
||||
</Typography>
|
||||
</Localized>
|
||||
|
||||
{submitError && (
|
||||
<CallOut color="error" fullWidth>
|
||||
{submitError}
|
||||
</CallOut>
|
||||
)}
|
||||
|
||||
<Field name="allowedDomains">
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-permittedDomains-permittedDomains">
|
||||
<InputLabel>Permitted Domains</InputLabel>
|
||||
</Localized>
|
||||
<Localized id="install-permittedDomains-permittedDomainsDescription">
|
||||
<InputDescription>
|
||||
Insert domains separated by comma
|
||||
</InputDescription>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-permittedDomains-permittedDomainsTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Domains"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Flex direction="row-reverse" itemGutter>
|
||||
<Localized id="install-permittedDomains-finishInstall">
|
||||
<Button
|
||||
variant="filled"
|
||||
color="primary"
|
||||
size="large"
|
||||
type="submit"
|
||||
disabled={submitting}
|
||||
>
|
||||
Finish Install
|
||||
</Button>
|
||||
</Localized>
|
||||
<BackButton
|
||||
submitting={submitting}
|
||||
onGoToPreviousStep={this.props.onGoToPreviousStep}
|
||||
/>
|
||||
</Flex>
|
||||
</HorizontalGutter>
|
||||
</form>
|
||||
)}
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PermittedDomainsStep;
|
||||
@@ -4,7 +4,7 @@ import ReactDOM from "react-dom";
|
||||
|
||||
import { createManaged } from "coral-framework/lib/bootstrap";
|
||||
|
||||
import App from "./components/App";
|
||||
import App from "./App";
|
||||
import localesData from "./locales";
|
||||
|
||||
// Import css variables.
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { withInstallMutation, InstallMutation } from "./InstallMutation";
|
||||
@@ -1,201 +0,0 @@
|
||||
import { Localized } from "fluent-react/compat";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Field, Form } from "react-final-form";
|
||||
|
||||
import { OnSubmit } from "coral-framework/lib/form";
|
||||
import {
|
||||
composeValidators,
|
||||
required,
|
||||
validateEmail,
|
||||
validateURL,
|
||||
} from "coral-framework/lib/validation";
|
||||
import {
|
||||
CallOut,
|
||||
Flex,
|
||||
FormField,
|
||||
HorizontalGutter,
|
||||
InputDescription,
|
||||
InputLabel,
|
||||
TextField,
|
||||
Typography,
|
||||
ValidationMessage,
|
||||
} from "coral-ui/components";
|
||||
|
||||
import BackButton from "./BackButton";
|
||||
import NextButton from "./NextButton";
|
||||
|
||||
interface FormProps {
|
||||
organizationName: string;
|
||||
organizationContactEmail: string;
|
||||
organizationURL: string;
|
||||
}
|
||||
|
||||
export interface AddOrganizationForm {
|
||||
onSubmit: OnSubmit<FormProps>;
|
||||
onGoToPreviousStep: () => void;
|
||||
data: FormProps;
|
||||
}
|
||||
|
||||
const AddOrganization: FunctionComponent<AddOrganizationForm> = props => {
|
||||
return (
|
||||
<Form
|
||||
onSubmit={props.onSubmit}
|
||||
initialValues={{
|
||||
organizationName: props.data.organizationName,
|
||||
organizationContactEmail: props.data.organizationContactEmail,
|
||||
organizationURL: props.data.organizationURL,
|
||||
}}
|
||||
>
|
||||
{({ handleSubmit, submitting, submitError }) => (
|
||||
<form autoComplete="off" onSubmit={handleSubmit}>
|
||||
<HorizontalGutter size="double">
|
||||
<Localized id="install-addOrganization-title">
|
||||
<Typography variant="heading1" align="center">
|
||||
Add Organization
|
||||
</Typography>
|
||||
</Localized>
|
||||
<Localized id="install-addOrganization-description">
|
||||
<Typography variant="bodyCopy" align="center">
|
||||
Please tell us the name of your organization. This will appear
|
||||
in emails when inviting new team members.
|
||||
</Typography>
|
||||
</Localized>
|
||||
|
||||
{submitError && (
|
||||
<CallOut color="error" fullWidth>
|
||||
{submitError}
|
||||
</CallOut>
|
||||
)}
|
||||
|
||||
<Field
|
||||
name="organizationName"
|
||||
validate={composeValidators(required)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-addOrganization-orgName">
|
||||
<InputLabel>Organization Name</InputLabel>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-addOrganization-orgNameTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Organization Name"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
name="organizationContactEmail"
|
||||
validate={composeValidators(required, validateEmail)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-addOrganization-orgEmail">
|
||||
<InputLabel>Organization Contact Email</InputLabel>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-addOrganization-orgEmailTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Organization Contact Email"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
name="organizationURL"
|
||||
validate={composeValidators(required, validateURL)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-addOrganization-orgURL">
|
||||
<InputLabel>Organization URL</InputLabel>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-addOrganization-orgURLDescription"
|
||||
strong={<strong />}
|
||||
>
|
||||
<InputDescription>
|
||||
{/* Related: https://github.com/prettier/prettier/issues/2347 */}
|
||||
Be sure to include <strong>{"http://"}</strong> or{" "}
|
||||
<strong>{"https://"}</strong> in your URL
|
||||
</InputDescription>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-addOrganization-orgURLTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Organization URL"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
<Flex direction="row-reverse" itemGutter>
|
||||
<NextButton submitting={submitting} />
|
||||
<BackButton
|
||||
submitting={submitting}
|
||||
onGoToPreviousStep={props.onGoToPreviousStep}
|
||||
/>
|
||||
</Flex>
|
||||
</HorizontalGutter>
|
||||
</form>
|
||||
)}
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddOrganization;
|
||||
@@ -1,231 +0,0 @@
|
||||
import { Localized } from "fluent-react/compat";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Field, Form } from "react-final-form";
|
||||
|
||||
import { OnSubmit } from "coral-framework/lib/form";
|
||||
import {
|
||||
composeValidators,
|
||||
required,
|
||||
validateEmail,
|
||||
validateEqualPasswords,
|
||||
validatePassword,
|
||||
validateUsername,
|
||||
} from "coral-framework/lib/validation";
|
||||
import {
|
||||
CallOut,
|
||||
Flex,
|
||||
FormField,
|
||||
HorizontalGutter,
|
||||
InputDescription,
|
||||
InputLabel,
|
||||
TextField,
|
||||
Typography,
|
||||
ValidationMessage,
|
||||
} from "coral-ui/components";
|
||||
|
||||
import NextButton from "./NextButton";
|
||||
|
||||
interface FormProps {
|
||||
email: string;
|
||||
username: string;
|
||||
password: string;
|
||||
confirmPassword: string;
|
||||
}
|
||||
|
||||
export interface CreateYourAccountForm {
|
||||
onSubmit: OnSubmit<FormProps>;
|
||||
onGoToPreviousStep: () => void;
|
||||
data: FormProps;
|
||||
}
|
||||
|
||||
const CreateYourAccount: FunctionComponent<CreateYourAccountForm> = props => {
|
||||
return (
|
||||
<Form
|
||||
onSubmit={props.onSubmit}
|
||||
initialValues={{
|
||||
email: props.data.email,
|
||||
username: props.data.username,
|
||||
}}
|
||||
>
|
||||
{({ handleSubmit, submitting, submitError }) => (
|
||||
<form autoComplete="off" onSubmit={handleSubmit}>
|
||||
<HorizontalGutter size="double">
|
||||
<Localized id="install-createYourAccount-title">
|
||||
<Typography variant="heading1" align="center">
|
||||
Create an Administrator Account
|
||||
</Typography>
|
||||
</Localized>
|
||||
|
||||
{submitError && (
|
||||
<CallOut color="error" fullWidth>
|
||||
{submitError}
|
||||
</CallOut>
|
||||
)}
|
||||
|
||||
<Field
|
||||
name="email"
|
||||
validate={composeValidators(required, validateEmail)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-createYourAccount-email">
|
||||
<InputLabel>Email</InputLabel>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-createYourAccount-emailTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Email"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
name="username"
|
||||
validate={composeValidators(required, validateUsername)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-createYourAccount-username">
|
||||
<InputLabel>Username</InputLabel>
|
||||
</Localized>
|
||||
<Localized id="install-createYourAccount-usernameDescription">
|
||||
<InputDescription>
|
||||
An identifier displayed on your comments. You may use “_”
|
||||
and “.”
|
||||
</InputDescription>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-createYourAccount-usernameTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Username"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
name="password"
|
||||
validate={composeValidators(required, validatePassword)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-createYourAccount-password">
|
||||
<InputLabel>Password</InputLabel>
|
||||
</Localized>
|
||||
<Localized id="install-createYourAccount-passwordDescription">
|
||||
<InputDescription>
|
||||
Must be at least 8 characters
|
||||
</InputDescription>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-createYourAccount-passwordTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Password"
|
||||
type="password"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
<Field
|
||||
name="confirmPassword"
|
||||
validate={composeValidators(required, validateEqualPasswords)}
|
||||
>
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-createYourAccount-confirmPassword">
|
||||
<InputLabel>Confirm Password</InputLabel>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-createYourAccount-confirmPasswordTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Confirm Password"
|
||||
type="password"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Flex direction="row-reverse">
|
||||
<NextButton submitting={submitting} />
|
||||
</Flex>
|
||||
</HorizontalGutter>
|
||||
</form>
|
||||
)}
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateYourAccount;
|
||||
@@ -1,125 +0,0 @@
|
||||
import { OnSubmit } from "coral-framework/lib/form";
|
||||
import { Localized } from "fluent-react/compat";
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Field, Form } from "react-final-form";
|
||||
|
||||
import {
|
||||
Button,
|
||||
CallOut,
|
||||
Flex,
|
||||
FormField,
|
||||
HorizontalGutter,
|
||||
InputDescription,
|
||||
InputLabel,
|
||||
TextField,
|
||||
Typography,
|
||||
ValidationMessage,
|
||||
} from "coral-ui/components";
|
||||
|
||||
import BackButton from "./BackButton";
|
||||
|
||||
interface FormProps {
|
||||
allowedDomains: string;
|
||||
}
|
||||
|
||||
export interface PermittedDomainsForm {
|
||||
onSubmit: OnSubmit<FormProps>;
|
||||
onGoToPreviousStep: () => void;
|
||||
data: {
|
||||
allowedDomains: string[];
|
||||
};
|
||||
}
|
||||
|
||||
const PermittedDomains: FunctionComponent<PermittedDomainsForm> = props => {
|
||||
return (
|
||||
<Form
|
||||
onSubmit={props.onSubmit}
|
||||
initialValues={{
|
||||
allowedDomains: props.data.allowedDomains.join(","),
|
||||
}}
|
||||
>
|
||||
{({ handleSubmit, submitting, submitError }) => (
|
||||
<form autoComplete="off" onSubmit={handleSubmit}>
|
||||
<HorizontalGutter size="double">
|
||||
<Localized id="install-permittedDomains-title">
|
||||
<Typography variant="heading1" align="center">
|
||||
Permitted Domains
|
||||
</Typography>
|
||||
</Localized>
|
||||
<Localized id="install-permittedDomains-description">
|
||||
<Typography variant="bodyCopy" align="center">
|
||||
Enter the domains you would like to permit for Coral, e.g. your
|
||||
local, staging and production environments (ex. localhost:3000,
|
||||
staging.domain.com, domain.com).
|
||||
</Typography>
|
||||
</Localized>
|
||||
|
||||
{submitError && (
|
||||
<CallOut color="error" fullWidth>
|
||||
{submitError}
|
||||
</CallOut>
|
||||
)}
|
||||
|
||||
<Field name="allowedDomains">
|
||||
{({ input, meta }) => (
|
||||
<FormField>
|
||||
<Localized id="install-permittedDomains-permittedDomains">
|
||||
<InputLabel>Permitted Domains</InputLabel>
|
||||
</Localized>
|
||||
<Localized id="install-permittedDomains-permittedDomainsDescription">
|
||||
<InputDescription>
|
||||
Insert domains separated by comma
|
||||
</InputDescription>
|
||||
</Localized>
|
||||
<Localized
|
||||
id="install-permittedDomains-permittedDomainsTextField"
|
||||
attrs={{ placeholder: true }}
|
||||
>
|
||||
<TextField
|
||||
name={input.name}
|
||||
onChange={input.onChange}
|
||||
value={input.value}
|
||||
placeholder="Domains"
|
||||
color={
|
||||
meta.touched && (meta.error || meta.submitError)
|
||||
? "error"
|
||||
: "regular"
|
||||
}
|
||||
disabled={submitting}
|
||||
fullWidth
|
||||
/>
|
||||
</Localized>
|
||||
{meta.touched && (meta.error || meta.submitError) && (
|
||||
<ValidationMessage fullWidth>
|
||||
{meta.error || meta.submitError}
|
||||
</ValidationMessage>
|
||||
)}
|
||||
</FormField>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<Flex direction="row-reverse" itemGutter>
|
||||
<Localized id="install-permittedDomains-finishInstall">
|
||||
<Button
|
||||
variant="filled"
|
||||
color="primary"
|
||||
size="large"
|
||||
type="submit"
|
||||
disabled={submitting}
|
||||
>
|
||||
Finish Install
|
||||
</Button>
|
||||
</Localized>
|
||||
<BackButton
|
||||
submitting={submitting}
|
||||
onGoToPreviousStep={props.onGoToPreviousStep}
|
||||
/>
|
||||
</Flex>
|
||||
</HorizontalGutter>
|
||||
</form>
|
||||
)}
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default PermittedDomains;
|
||||
@@ -1,34 +0,0 @@
|
||||
import React, { Component } from "react";
|
||||
|
||||
import { PropTypesOf } from "coral-ui/types";
|
||||
|
||||
import AddOrganization, {
|
||||
AddOrganizationForm,
|
||||
} from "../components/AddOrganization";
|
||||
|
||||
interface AddOrganizationContainerProps {
|
||||
onGoToNextStep: () => void;
|
||||
onGoToPreviousStep: () => void;
|
||||
data: PropTypesOf<typeof AddOrganization>["data"];
|
||||
onSaveData: (newData: PropTypesOf<typeof AddOrganization>["data"]) => void;
|
||||
}
|
||||
|
||||
class AddOrganizationContainer extends Component<
|
||||
AddOrganizationContainerProps
|
||||
> {
|
||||
private onSubmit: AddOrganizationForm["onSubmit"] = async (input, form) => {
|
||||
this.props.onSaveData(input);
|
||||
return this.props.onGoToNextStep();
|
||||
};
|
||||
public render() {
|
||||
return (
|
||||
<AddOrganization
|
||||
data={this.props.data}
|
||||
onSubmit={this.onSubmit}
|
||||
onGoToPreviousStep={this.props.onGoToPreviousStep}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default AddOrganizationContainer;
|
||||
@@ -1,34 +0,0 @@
|
||||
import React, { Component } from "react";
|
||||
|
||||
import { PropTypesOf } from "coral-ui/types";
|
||||
|
||||
import CreateYourAccount, {
|
||||
CreateYourAccountForm,
|
||||
} from "../components/CreateYourAccount";
|
||||
|
||||
interface CreateYourAccountContainerProps {
|
||||
onGoToNextStep: () => void;
|
||||
onGoToPreviousStep: () => void;
|
||||
data: PropTypesOf<typeof CreateYourAccount>["data"];
|
||||
onSaveData: (newData: PropTypesOf<typeof CreateYourAccount>["data"]) => void;
|
||||
}
|
||||
|
||||
class CreateYourAccountContainer extends Component<
|
||||
CreateYourAccountContainerProps
|
||||
> {
|
||||
private onSubmit: CreateYourAccountForm["onSubmit"] = async (input, form) => {
|
||||
this.props.onSaveData(input);
|
||||
return this.props.onGoToNextStep();
|
||||
};
|
||||
public render() {
|
||||
return (
|
||||
<CreateYourAccount
|
||||
data={this.props.data}
|
||||
onSubmit={this.onSubmit}
|
||||
onGoToPreviousStep={this.props.onGoToPreviousStep}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CreateYourAccountContainer;
|
||||
@@ -1,42 +0,0 @@
|
||||
import { FORM_ERROR } from "final-form";
|
||||
import React, { Component } from "react";
|
||||
|
||||
import { PropTypesOf } from "coral-ui/types";
|
||||
|
||||
import PermittedDomains, {
|
||||
PermittedDomainsForm,
|
||||
} from "../components/PermittedDomains";
|
||||
|
||||
interface PermittedDomainsContainerProps {
|
||||
onGoToNextStep: () => void;
|
||||
onGoToPreviousStep: () => void;
|
||||
data: PropTypesOf<typeof PermittedDomains>["data"];
|
||||
onInstall: (
|
||||
newData: PropTypesOf<typeof PermittedDomains>["data"]
|
||||
) => Promise<void>;
|
||||
}
|
||||
|
||||
class PermittedDomainsContainer extends Component<
|
||||
PermittedDomainsContainerProps
|
||||
> {
|
||||
private onSubmit: PermittedDomainsForm["onSubmit"] = async (input, form) => {
|
||||
try {
|
||||
const allowedDomains = input.allowedDomains.split(",");
|
||||
await this.props.onInstall({ allowedDomains });
|
||||
return this.props.onGoToNextStep();
|
||||
} catch (error) {
|
||||
return { [FORM_ERROR]: error.message };
|
||||
}
|
||||
};
|
||||
public render() {
|
||||
return (
|
||||
<PermittedDomains
|
||||
data={this.props.data}
|
||||
onSubmit={this.onSubmit}
|
||||
onGoToPreviousStep={this.props.onGoToPreviousStep}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PermittedDomainsContainer;
|
||||
Reference in New Issue
Block a user