Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mission control 2.0 (Project Creation & Dashboard) #241

Open
wants to merge 3 commits into
base: redesign
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config-overrides.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module.exports = override(
addLessLoader({
javascriptEnabled: true,
modifyVars: {
'@primary-color': '#FF6700',
'@primary-color': '#1D66FF',
'@label-color': "rgba(0,0,0, 0.56)"
},
}),
Expand Down
1 change: 1 addition & 0 deletions src/assets/aws.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/azure.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions src/assets/gcp.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 35 additions & 20 deletions src/components/create-project-form/CreateProjectForm.jsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,57 @@
import React from "react"
import { Form, Input, Button } from "antd"
import { EditOutlined } from '@ant-design/icons';
import { Form, Input, Button, Radio } from "antd"
import FormItemLabel from "../../redesign-components/form-item-label/FormItemLabel";
import RadioCards from "../radio-cards/RadioCards";
import aws from '../../assets/aws.svg'
import gcp from '../../assets/gcp.svg'
import azure from "../../assets/azure.svg"

export default function CreateProjectForm({ projects = [], handleSubmit }) {
const [form] = Form.useForm()
const [projectName, setProjectName] = React.useState("")
const projectId = projectName.toLowerCase()
const handleValuesChange = (({ projectName }) => setProjectName(projectName))
const handleFormFinish = (values) => handleSubmit(values.projectName, projectId)
const handleFormFinish = (values) => handleSubmit(values.projectName, values.projectName.toLowerCase())
return (
<Form form={form} onFinish={handleFormFinish} onValuesChange={handleValuesChange}>
<p style={{ fontWeight: "bold" }}><b>Name your project</b></p>
<Form form={form} onFinish={handleFormFinish}>
<FormItemLabel name="Name your project" />
<Form.Item
name="projectName"
rules={[
{
validator: (_, value, cb) => {
validator: (_, value) => {
if (!value) {
cb("Please input a project name")
return
return Promise.reject("Please input a project name")
}
if (!(/^[0-9a-zA-Z]+$/.test(value))) {
cb("Project name can only contain alphanumeric characters!")
return
return Promise.reject("Project name can only contain alphanumeric characters!")
}
if (projects.some(project => project === value.toLowerCase())) {
cb("Project name already taken. Please provide a unique project name!")
return
return Promise.reject("Project name already taken. Please provide a unique project name!")
}
cb()
return Promise.resolve()
}
}]}>
<Input placeholder="Project name" prefix={<EditOutlined style={{ color: 'rgba(0,0,0,.25)' }} />} />
<Input placeholder="eg: MyProject" style={{ maxWidth: 600 }} />
</Form.Item>
{projectId && <span className="hint">ProjectID: {projectId}</span>}
<Form.Item>
<Button type="primary" htmlType="submit" className="project-btn">Create project</Button>
<Form.Item shouldUpdate noStyle>
{() => form.getFieldValue("projectName") && <div style={{ marginBottom: 22 }} className="hint">ProjectID: {form.getFieldValue("projectName").toLowerCase()}</div>}
</Form.Item>
<FormItemLabel name="Where do you want to deploy/host it" />
<Form.Item name="platform" rules={[{ required: true, message: "Please select a platform!" }]}>
<RadioCards size="large">
<Radio.Button value="aws" size="large">
<img src={aws} alt="aws" width="24px" height="24px" style={{ marginRight: 4 }} />
<span>AWS</span>
</Radio.Button>
<Radio.Button value="gcp">
<img src={gcp} alt="gcp" width="24px" height="24px" style={{ marginRight: 4 }} />
<span>Google Cloud</span>
</Radio.Button>
<Radio.Button value="azure">
<img src={azure} alt="azure" width="24px" height="24px" style={{ marginRight: 4 }} />
<span>MS Azure</span>
</Radio.Button>
</RadioCards>
</Form.Item>
<Button type="primary" size="large" style={{ float: "right" }} htmlType="submit">Next</Button>
</Form>
)
}
156 changes: 119 additions & 37 deletions src/components/database/create-database/CreateDatabase.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { dbTypes, defaultDbConnectionStrings } from '../../../constants';
import { Card, Input, Button, Alert, Radio, Form, Checkbox, AutoComplete } from 'antd';
import { Input, Button, Alert, Radio, Form, Checkbox, AutoComplete, Slider, Switch, Space, Divider } from 'antd';
import postgresIcon from '../../../assets/postgresIcon.svg'
import mysqlIcon from '../../../assets/mysqlIcon.svg'
import mongoIcon from '../../../assets/mongoIcon.svg'
Expand All @@ -10,7 +10,7 @@ import './create-db.css'
import { useSelector } from 'react-redux';
import { getDatabaseLabelFromType } from "../../../utils"
import RadioCards from "../../radio-cards/RadioCards"
import FormItemLabel from "../../form-item-label/FormItemLabel"
import FormItemLabel from "../../../redesign-components/form-item-label/FormItemLabel"
import { Controlled as CodeMirror } from 'react-codemirror2';
import 'codemirror/theme/material.css';
import 'codemirror/lib/codemirror.css';
Expand All @@ -22,10 +22,19 @@ import gqlPrettier from 'graphql-prettier';
import { getDbConfigs } from '../../../operations/database';
import ConditionalFormBlock from '../../conditional-form-block/ConditionalFormBlock';

const AutomatedBackupSwitch = ({ value, onChange }) => {
return (
<React.Fragment>
Disable <Switch style={{ margin: "0px 10px" }} checked={value} onChange={checked => onChange(checked)} /> Enable <br />
<span className="hint">Backups are retained for 7 days</span>
</React.Fragment>
)
}

const CreateDatabase = (props) => {
const [form] = Form.useForm();
const envSecrets = props.envSecrets ? props.envSecrets : [];
const formInitialValues = { alias: dbTypes.MONGO, dbType: dbTypes.MONGO, conn: defaultDbConnectionStrings[dbTypes.MONGO], loadFromSecret: false }
const formInitialValues = { method: "new", model: "shared", alias: dbTypes.MONGO, dbType: dbTypes.MONGO, conn: defaultDbConnectionStrings[dbTypes.MONGO], loadFromSecret: false, dbName: props.projectId }
const dbconfig = useSelector(state => getDbConfigs(state))

const dbAliasNames = dbconfig ? Object.keys(dbconfig) : [];
Expand All @@ -49,38 +58,110 @@ const CreateDatabase = (props) => {
}
}

const ModelRadioButtons = ({ value, onChange }) => {
return (
<React.Fragment>
<Radio.Group value={value} onChange={e => onChange(e.target.value)}>
<Radio value="new">Provision new database</Radio>
<Radio value="existing">Add existing database</Radio>
</Radio.Group>
<Divider type="vertical" />
<Button
type="link"
style={{ color: "#1D66FF", backgroundColor: "rgba(29, 102, 255, 0.1)" }}
onClick={props.handleSkipAddDatabase}
>
Skip this step
</Button>
</React.Fragment>
)
}

const alertMsg = <div>
<b>Note:</b> If your database is running inside a docker container, use the container IP address of that docker container as the host in the connection string.
</div>

return (
<Card>
<Form form={form} onFinish={handleOnFinish} initialValues={formInitialValues} onValuesChange={handleValuesChange} layout="vertical">
<FormItemLabel name="Select a database" />
<Form.Item name="dbType" rules={[{ required: true, message: "Please select a database type!" }]}>
<RadioCards size="large">
<Radio.Button value="mongo" size="large">
<img src={mongoIcon} width="24px" height="24px" style={{ marginRight: 4 }} />
<span>MongoDB</span>
</Radio.Button>
<Radio.Button value="postgres">
<img src={postgresIcon} width="24px" height="24px" style={{ marginRight: 4 }} />
<span>PostgreSQL</span>
</Radio.Button>
<Radio.Button value="mysql">
<img src={mysqlIcon} width="24px" height="24px" style={{ marginRight: 4 }} />
<span>MySQL</span>
</Radio.Button>
<Radio.Button value="sqlserver">
<img src={sqlserverIcon} width="24px" height="24px" style={{ marginRight: 4 }} />
<span>SQL Server</span>
</Radio.Button>
<Radio.Button value="embedded">
<img src={embeddedIcon} width="24px" height="24px" style={{ marginRight: 4 }} />
<span>Embedded</span>
</Radio.Button>
</RadioCards>
<Form
layout="horizontal"
colon={false}
labelAlign="left"
labelCol={{ span: 3 }}
form={form}
onFinish={handleOnFinish}
initialValues={formInitialValues}
onValuesChange={handleValuesChange}
>
<Form.Item name="method">
<ModelRadioButtons />
</Form.Item>
<FormItemLabel name="Select a database" />
<Form.Item name="dbType" rules={[{ required: true, message: "Please select a database type!" }]}>
<RadioCards size="large">
<Radio.Button value="mongo" size="large">
<img src={mongoIcon} alt="mongo" width="24px" height="24px" style={{ marginRight: 4 }} />
<span>MongoDB</span>
</Radio.Button>
<Radio.Button value="postgres">
<img src={postgresIcon} alt="postgres" width="24px" height="24px" style={{ marginRight: 4 }} />
<span>PostgreSQL</span>
</Radio.Button>
<Radio.Button value="mysql">
<img src={mysqlIcon} alt="mysql" width="24px" height="24px" style={{ marginRight: 4 }} />
<span>MySQL</span>
</Radio.Button>
<Radio.Button value="sqlserver">
<img src={sqlserverIcon} alt="sqlserver" width="24px" height="24px" style={{ marginRight: 4 }} />
<span>SQL Server</span>
</Radio.Button>
<Radio.Button value="embedded">
<img src={embeddedIcon} alt="embedded" width="24px" height="24px" style={{ marginRight: 4 }} />
<span>Embedded</span>
</Radio.Button>
</RadioCards>
</Form.Item>
<ConditionalFormBlock dependency="method" condition={() => form.getFieldValue("method") === "new"}>
<Form.Item name="model">
<Radio.Group>
<Radio value="shared">Shared</Radio>
<Radio value="dedicated">Dedicated</Radio>
</Radio.Group>
</Form.Item>
<Form.Item name="name" label="Name">
<Input placeholder="eg: MyDB1" style={{ maxWidth: 300 }} />
</Form.Item>
<ConditionalFormBlock dependency="model" condition={() => form.getFieldValue("model") === "shared"}>
<p style={{ fontWeight: 400 }}>In a shared environment, you get 1GB of space for your project</p>
</ConditionalFormBlock>
<ConditionalFormBlock dependency="model" condition={() => form.getFieldValue("model") === "dedicated"}>
<Form.Item name="computation" label="Computation">
<RadioCards size="large">
<Radio.Button value="2/8" size="large">
<span style={{ lineHeight: "22px" }}>CPU: 2 <br /> RAM: 8GB</span>
</Radio.Button>
<Radio.Button value="2/16">
<span style={{ lineHeight: "22px" }}>CPU: 2 <br /> RAM: 16GB</span>
</Radio.Button>
<Radio.Button value="3/16">
<span style={{ lineHeight: "22px" }}>CPU: 3 <br /> RAM: 16GB</span>
</Radio.Button>
<Radio.Button value="3/32">
<span style={{ lineHeight: "22px" }}>CPU: 3 <br /> RAM: 32GB</span>
</Radio.Button>
<Radio.Button value="4/32">
<span style={{ lineHeight: "22px" }}>CPU: 4 <br /> RAM: 32GB</span>
</Radio.Button>
</RadioCards>
</Form.Item>
<Form.Item name="storage" label="Storage">
<Slider style={{ maxWidth: 568 }} min={20} max={1000} marks={{ 20: "20GB", 1000: "1TB" }} />
</Form.Item>
<Form.Item name="backup" label="Automated Backup">
<AutomatedBackupSwitch />
</Form.Item>
</ConditionalFormBlock>
</ConditionalFormBlock>
<ConditionalFormBlock dependency="method" condition={() => form.getFieldValue("method") === "existing"}>
<FormItemLabel name="Provide a connection string" description="Space Cloud requires a connection string to connect to your database" />
<Form.Item name='loadFromSecret' valuePropName='checked'>
<Checkbox>Load connection string from a secret</Checkbox>
Expand All @@ -106,7 +187,7 @@ const CreateDatabase = (props) => {
<AutoComplete placeholder="secret name" options={envSecrets.map(secret => ({ value: secret }))} />
</Form.Item>
</ConditionalFormBlock>
<Form.Item noStyle shouldUpdate={(prev, curr) => prev.dbType != curr.dbType} dependencies={["dbType"]}>
<Form.Item noStyle shouldUpdate={(prev, curr) => prev.dbType !== curr.dbType} dependencies={["dbType"]}>
{() => {
const dbType = form.getFieldValue("dbType")
const databaseLabel = getDatabaseLabelFromType(dbType)
Expand All @@ -121,7 +202,7 @@ const CreateDatabase = (props) => {
)
}}
</Form.Item>
<Form.Item name="dbName" initialValue={props.projectId} rules={[{ required: true, message: 'Please input a Database Name' }]}>
<Form.Item name="dbName" rules={[{ required: true, message: 'Please input a Database Name' }]}>
<Input placeholder="" />
</Form.Item>
<FormItemLabel name="Alias" description="Alias name is used in your frontend queries to identify your database" />
Expand All @@ -145,7 +226,7 @@ const CreateDatabase = (props) => {
}]}>
<Input placeholder="eg: mongo" />
</Form.Item>
<Form.Item shouldUpdate={(prev, curr) => prev.alias != curr.alias} dependencies={["alias"]}>
<Form.Item shouldUpdate={(prev, curr) => prev.alias !== curr.alias} dependencies={["alias"]}>
{() => {
const aliasValue = form.getFieldValue("alias")
try {
Expand Down Expand Up @@ -181,11 +262,12 @@ const CreateDatabase = (props) => {
}
}}
</Form.Item>
<Form.Item noStyle>
<Button type="primary" htmlType="submit" block>Add database</Button>
</Form.Item>
</Form>
</Card >
</ConditionalFormBlock>
<Space style={{ float: "right" }}>
<Button type="primary" ghost size="large" onClick={props.handleOnBackClick}>Back</Button>
<Button type="primary" size="large" htmlType="submit">Add Database</Button>
</Space>
</Form>
);
}

Expand Down
Loading