This commit is contained in:
Hetu Nandu 2019-10-21 15:12:45 +00:00 committed by Abhinav Jha
parent 618ede4ffb
commit e0348cc1f3
51 changed files with 1691 additions and 193 deletions

View File

@ -1,3 +1,4 @@
{
"src/**/*.tsx": ["npx eslint --fix", "npx prettier --write", "git add"]
"src/**/*.tsx": ["npx eslint --fix", "npx prettier --write", "git add"],
"src/**/*.ts": ["npx eslint --fix", "npx prettier --write", "git add"],
}

View File

@ -42,17 +42,22 @@
"prettier": "^1.18.2",
"re-reselect": "^3.4.0",
"react": "^16.7.0",
"react-ace": "^8.0.0",
"react-dnd": "^9.3.4",
"react-dnd-html5-backend": "^9.3.4",
"react-dnd-touch-backend": "^9.4.0",
"react-dom": "^16.7.0",
"react-json-view": "^1.19.1",
"react-netlify-identity": "^0.1.9",
"react-redux": "^6.0.0",
"react-rnd": "^10.1.1",
"react-router": "^5.0.1",
"react-router-dom": "^5.0.1",
"react-scripts": "^3.1.1",
"react-select": "^3.0.8",
"react-tabs": "^3.0.0",
"redux": "^4.0.1",
"redux-form": "^8.2.6",
"redux-saga": "^1.0.0",
"reselect": "^4.0.0",
"styled-components": "^4.1.3",
@ -79,6 +84,9 @@
"not op_mini all"
],
"devDependencies": {
"@types/react-select": "^3.0.5",
"@types/react-tabs": "^2.3.1",
"@types/redux-form": "^8.1.9",
"@typescript-eslint/eslint-plugin": "^2.0.0",
"@typescript-eslint/parser": "^2.0.0",
"dotenv": "^8.1.0",

View File

@ -0,0 +1,58 @@
import { ReduxActionTypes } from "../constants/ReduxActionConstants";
import { RestAction } from "../api/ActionAPI";
export const createAction = (payload: RestAction) => {
return {
type: ReduxActionTypes.CREATE_ACTION,
payload,
};
};
export const fetchActions = () => {
return {
type: ReduxActionTypes.FETCH_ACTIONS_INIT,
};
};
export const selectAction = (payload: { id: string }) => {
return {
type: ReduxActionTypes.SELECT_ACTION,
payload,
};
};
export const fetchApiConfig = (payload: { id: string }) => {
return {
type: ReduxActionTypes.FETCH_ACTION,
payload,
};
};
export const runAction = (payload: { id: string }) => {
return {
type: ReduxActionTypes.RUN_ACTION,
payload,
};
};
export const deleteAction = (payload: { id: string }) => {
return {
type: ReduxActionTypes.DELETE_ACTION,
payload,
};
};
export const updateAction = (payload: { data: RestAction }) => {
return {
type: ReduxActionTypes.UPDATE_ACTION,
payload,
};
};
export default {
createAction,
fetchActions,
fetchApiConfig,
runAction,
deleteAction,
};

View File

@ -1,11 +1,11 @@
import API, { HttpMethod } from "./Api";
import { ApiResponse } from "./ApiResponses";
import { ApiResponse, GenericApiResponse } from "./ApiResponses";
import { APIRequest } from "../constants/ApiConstants";
import { mapToPropList } from "../utils/AppsmithUtils";
export interface CreateActionRequest<T> extends APIRequest {
resourceId: string;
actionName: string;
pageId: string;
name: string;
actionConfiguration: T;
}
@ -15,9 +15,10 @@ export interface UpdateActionRequest<T> extends CreateActionRequest<T> {
export interface APIConfig {
resourceId: string;
actionName: string;
pageId: string;
name: string;
requestHeaders: Record<string, string>;
method: HttpMethod;
httpMethod: HttpMethod;
path: string;
body: JSON;
queryParams: Record<string, string>;
@ -31,9 +32,9 @@ export interface Property {
export interface APIConfigRequest {
headers: Property[];
httpMethod: HttpMethod;
httpMethod: string;
path: string;
body: JSON;
body: JSON | string;
queryParameters: Property[];
}
@ -42,8 +43,17 @@ export interface QueryConfig {
}
export interface ActionCreateUpdateResponse extends ApiResponse {
actionId: string;
dynamicBindingMap: Record<string, string>;
id: string;
jsonPathKeys: Record<string, string>;
}
export interface RestAction {
id: string;
name: string;
resourceId: string;
pluginId: string;
pageId: string;
actionConfiguration: APIConfigRequest;
}
export interface ExecuteActionRequest extends APIRequest {
@ -59,35 +69,26 @@ export interface ExecuteActionResponse extends ApiResponse {
class ActionAPI extends API {
static url = "v1/actions";
static createAPI(apiConfig: APIConfig): Promise<ActionCreateUpdateResponse> {
const createAPI: CreateActionRequest<APIConfigRequest> = {
resourceId: apiConfig.resourceId,
actionName: apiConfig.actionName,
actionConfiguration: {
httpMethod: apiConfig.method,
path: apiConfig.path,
body: apiConfig.body,
headers: mapToPropList(apiConfig.requestHeaders),
queryParameters: mapToPropList(apiConfig.queryParams),
},
};
return API.post(ActionAPI.url, createAPI);
static fetchAPI(id: string): Promise<GenericApiResponse<RestAction>> {
return API.get(`${ActionAPI.url}/${id}`);
}
static updateAPI(apiConfig: APIConfig): Promise<ActionCreateUpdateResponse> {
const updateAPI: UpdateActionRequest<APIConfigRequest> = {
resourceId: apiConfig.resourceId,
actionName: apiConfig.actionName,
actionId: apiConfig.actionId,
actionConfiguration: {
httpMethod: apiConfig.method,
path: apiConfig.path,
body: apiConfig.body,
headers: mapToPropList(apiConfig.requestHeaders),
queryParameters: mapToPropList(apiConfig.queryParams),
},
};
return API.post(ActionAPI.url, updateAPI);
static createAPI(apiConfig: RestAction): Promise<ActionCreateUpdateResponse> {
return API.post(ActionAPI.url, apiConfig);
}
static fetchActions(): Promise<GenericApiResponse<RestAction[]>> {
return API.get(ActionAPI.url);
}
static updateAPI(
apiConfig: Partial<RestAction>,
): Promise<ActionCreateUpdateResponse> {
return API.put(`${ActionAPI.url}/${apiConfig.id}`, null, apiConfig);
}
static deleteAction(id: string) {
return API.delete(`${ActionAPI.url}/${id}`);
}
static createQuery(

View File

@ -64,6 +64,12 @@ class Api {
);
}
static delete(url: string, queryParams?: any) {
return axiosInstance.delete(
url + this.convertObjectToQueryParams(queryParams),
);
}
static convertObjectToQueryParams(object: any): string {
if (!_.isNil(object)) {
const paramArray: string[] = _.map(_.keys(object), key => {

View File

@ -14,6 +14,11 @@ export type ApiResponse = {
data: any;
};
export type GenericApiResponse<T> = {
responseMeta: ResponseMeta;
data: T;
};
// NO_RESOURCE_FOUND, 1000, "Unable to find {0} with id {1}"
// INVALID_PARAMTER, 4000, "Invalid parameter {0} provided in the input"
// PLUGIN_NOT_INSTALLED, 4001, "Plugin {0} not installed"

View File

@ -0,0 +1,9 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.33341 13.3333C8.33341 13.7916 7.95841 14.1666 7.50008 14.1666C7.04175 14.1666 6.66675 13.7916 6.66675 13.3333V9.99996C6.66675 9.54163 7.04175 9.16663 7.50008 9.16663C7.95841 9.16663 8.33341 9.54163 8.33341 9.99996V13.3333ZM13.3334 13.3333C13.3334 13.7916 12.9584 14.1666 12.5001 14.1666C12.0417 14.1666 11.6667 13.7916 11.6667 13.3333V9.99996C11.6667 9.54163 12.0417 9.16663 12.5001 9.16663C12.9584 9.16663 13.3334 9.54163 13.3334 9.99996V13.3333ZM15.0001 15.8333C15.0001 16.2925 14.6267 16.6666 14.1667 16.6666H5.83341C5.37341 16.6666 5.00008 16.2925 5.00008 15.8333V6.66663H15.0001V15.8333ZM8.33341 3.60663C8.33341 3.47746 8.51175 3.33329 8.75008 3.33329H11.2501C11.4884 3.33329 11.6667 3.47746 11.6667 3.60663V4.99996H8.33341V3.60663ZM17.5001 4.99996H16.6667H13.3334V3.60663C13.3334 2.53663 12.3992 1.66663 11.2501 1.66663H8.75008C7.60091 1.66663 6.66675 2.53663 6.66675 3.60663V4.99996H3.33341H2.50008C2.04175 4.99996 1.66675 5.37496 1.66675 5.83329C1.66675 6.29163 2.04175 6.66663 2.50008 6.66663H3.33341V15.8333C3.33341 17.2116 4.45508 18.3333 5.83342 18.3333H14.1667C15.5451 18.3333 16.6667 17.2116 16.6667 15.8333V6.66663H17.5001C17.9584 6.66663 18.3334 6.29163 18.3334 5.83329C18.3334 5.37496 17.9584 4.99996 17.5001 4.99996Z" fill="#231F20"/>
<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="1" y="1" width="18" height="18">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.33341 13.3333C8.33341 13.7916 7.95841 14.1666 7.50008 14.1666C7.04175 14.1666 6.66675 13.7916 6.66675 13.3333V9.99996C6.66675 9.54163 7.04175 9.16663 7.50008 9.16663C7.95841 9.16663 8.33341 9.54163 8.33341 9.99996V13.3333ZM13.3334 13.3333C13.3334 13.7916 12.9584 14.1666 12.5001 14.1666C12.0417 14.1666 11.6667 13.7916 11.6667 13.3333V9.99996C11.6667 9.54163 12.0417 9.16663 12.5001 9.16663C12.9584 9.16663 13.3334 9.54163 13.3334 9.99996V13.3333ZM15.0001 15.8333C15.0001 16.2925 14.6267 16.6666 14.1667 16.6666H5.83341C5.37341 16.6666 5.00008 16.2925 5.00008 15.8333V6.66663H15.0001V15.8333ZM8.33341 3.60663C8.33341 3.47746 8.51175 3.33329 8.75008 3.33329H11.2501C11.4884 3.33329 11.6667 3.47746 11.6667 3.60663V4.99996H8.33341V3.60663ZM17.5001 4.99996H16.6667H13.3334V3.60663C13.3334 2.53663 12.3992 1.66663 11.2501 1.66663H8.75008C7.60091 1.66663 6.66675 2.53663 6.66675 3.60663V4.99996H3.33341H2.50008C2.04175 4.99996 1.66675 5.37496 1.66675 5.83329C1.66675 6.29163 2.04175 6.66663 2.50008 6.66663H3.33341V15.8333C3.33341 17.2116 4.45508 18.3333 5.83342 18.3333H14.1667C15.5451 18.3333 16.6667 17.2116 16.6667 15.8333V6.66663H17.5001C17.9584 6.66663 18.3334 6.29163 18.3334 5.83329C18.3334 5.37496 17.9584 4.99996 17.5001 4.99996Z" fill="white"/>
</mask>
<g mask="url(#mask0)">
<rect width="20" height="20" fill="#A3B3BF"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,98 @@
import React from "react";
import { Button, IButtonProps, MaybeElement } from "@blueprintjs/core";
import styled, { css } from "styled-components";
import { Container } from "../../editorComponents/ContainerComponent";
import { TextComponentProps } from "./TextViewComponent";
const ButtonColorStyles = css<ButtonStyleProps>`
color: ${props => {
if (props.filled) return props.theme.colors.textOnDarkBG;
if (props.styleName) {
if (props.styleName === "secondary")
return props.theme.colors.OXFORD_BLUE;
return props.theme.colors[props.styleName];
}
}};
`;
const ButtonWrapper = styled(Button)<ButtonStyleProps>`
&& {
${ButtonColorStyles};
width: 100%;
height: 100%;
transition: background-color 0.2s;
background-color: ${props =>
props.filled && props.styleName && props.theme.colors[props.styleName]};
border: 1px solid
${props =>
props.styleName
? props.theme.colors[props.styleName]
: props.theme.colors.secondary};
border-radius: 4px;
font-weight: bold;
outline: none;
&&:hover,
&&:focus {
${ButtonColorStyles};
background-color: ${props => {
if (!props.filled) return props.theme.colors.secondaryDarker;
if (props.styleName !== "secondary") {
return props.theme.colors[`${props.styleName}Darker`];
}
}};
border-color: ${props => {
if (!props.filled) return;
if (props.styleName !== "secondary") {
return props.theme.colors[`${props.styleName}Darker`];
}
}};
}
&&:active {
${ButtonColorStyles};
background-color: ${props => {
if (!props.filled) return props.theme.colors.secondaryDarkest;
if (props.styleName !== "secondary") {
return props.theme.colors[`${props.styleName}Darkest`];
}
}};
border-color: ${props => {
if (!props.filled) return;
if (props.styleName !== "secondary") {
return props.theme.colors[`${props.styleName}Darkest`];
}
}};
}
}
`;
type ButtonStyleProps = {
styleName?: "primary" | "secondary" | "error";
filled?: boolean;
};
// To be used in any other part of the app
export const BaseButton = (props: IButtonProps & ButtonStyleProps) => {
return <ButtonWrapper {...props} />;
};
BaseButton.defaultProps = {
styleName: "secondary",
text: "Button Text",
minimal: true,
};
interface ButtonContainerProps extends TextComponentProps {
icon?: MaybeElement;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
}
// To be used with the canvas
const ButtonContainer = (props: ButtonContainerProps) => {
return (
<Container {...props}>
<BaseButton icon={props.icon} text={props.text} onClick={props.onClick} />
</Container>
);
};
export default ButtonContainer;

View File

@ -0,0 +1,31 @@
import React from "react";
import Creatable from "react-select/creatable";
type DropdownProps = {
options: Array<{
value: string;
label: string;
}>;
placeholder: string;
};
const selectStyles = {
container: (styles: any) => ({
...styles,
flex: 1,
}),
};
class CreatableDropdown extends React.Component<DropdownProps> {
render() {
return (
<Creatable
placeholder={this.props.placeholder}
options={this.props.options}
styles={selectStyles}
/>
);
}
}
export default CreatableDropdown;

View File

@ -0,0 +1,38 @@
import React from "react";
import Select from "react-select";
import { WrappedFieldInputProps } from "redux-form";
type DropdownProps = {
options: Array<{
value: string;
label: string;
}>;
input: WrappedFieldInputProps;
};
const selectStyles = {
control: (styles: any) => ({
...styles,
width: 100,
}),
};
export const BaseDropdown = (props: DropdownProps) => {
const { input, options } = props;
return (
<Select
defaultValue={options[0]}
options={options}
styles={selectStyles}
{...input}
onChange={value => input.onChange(value)}
onBlur={() => input.onBlur(input.value)}
/>
);
};
const Dropdown = (props: DropdownProps) => {
return <BaseDropdown {...props} />;
};
export default Dropdown;

View File

@ -0,0 +1,41 @@
import React from "react";
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
import "react-tabs/style/react-tabs.scss";
import styled from "styled-components";
const TabsWrapper = styled(Tabs)`
ul {
border-bottom-color: #d0d7dd;
li {
&.react-tabs__tab--selected {
border-color: #d0d7dd;
left: -1px;
border-radius: 0;
border-top: 5px solid ${props => props.theme.colors.primary};
}
}
}
`;
type TabbedViewComponentType = {
tabs: Array<{
key: string;
title: string;
panelComponent: () => React.ReactNode;
}>;
};
export const BaseTabbedView = (props: TabbedViewComponentType) => {
return (
<TabsWrapper>
<TabList>
{props.tabs.map(tab => (
<Tab key={tab.key}>{tab.title}</Tab>
))}
</TabList>
{props.tabs.map(tab => (
<TabPanel key={tab.key}>{tab.panelComponent()}</TabPanel>
))}
</TabsWrapper>
);
};

View File

@ -0,0 +1,53 @@
import React from "react";
import styled, { css } from "styled-components";
import { WrappedFieldInputProps, WrappedFieldMetaProps } from "redux-form";
import { ComponentProps } from "../../editorComponents/BaseComponent";
import { Container } from "../../editorComponents/ContainerComponent";
const InputStyles = css`
padding: 5px;
flex: 1;
border: 1px solid ${props => props.theme.colors.inputInactiveBorders};
border-radius: 4px;
height: 32px;
background-color: ${props => props.theme.colors.inputInactiveBG};
&:focus {
border-color: ${props => props.theme.colors.secondary};
background-color: ${props => props.theme.colors.textOnDarkBG};
outline: 0;
}
`;
const Input = styled.input`
${InputStyles}
`;
const TextArea = styled.textarea`
${InputStyles}
height: 100px;
`;
export interface TextInputProps {
placeholderMessage?: string;
multiline?: boolean;
input?: WrappedFieldInputProps;
meta?: WrappedFieldMetaProps;
}
export const BaseTextInput = (props: TextInputProps) => {
const { placeholderMessage, multiline, input } = props;
if (multiline) {
return <TextArea placeholder={placeholderMessage} {...input} />;
}
return <Input placeholder={placeholderMessage} {...input} />;
};
const TextInputComponent = (props: TextInputProps & ComponentProps) => {
return (
<Container {...props}>
<BaseTextInput {...props} />
</Container>
);
};
export default TextInputComponent;

View File

@ -1,7 +1,23 @@
import * as React from "react";
import { ComponentProps } from "./BaseComponent";
import { Text } from "@blueprintjs/core";
import { Container } from "./ContainerComponent";
import styled from "styled-components";
import { ComponentProps } from "../../editorComponents/BaseComponent";
import { Container } from "../../editorComponents/ContainerComponent";
type TextStyleProps = {
styleName: "primary" | "secondary" | "error";
};
export const BaseText = styled(Text)<TextStyleProps>`
color: ${props => props.theme.colors[props.styleName]};
`;
export interface TextComponentProps extends ComponentProps {
text?: string;
ellipsize?: boolean;
tagName?: keyof JSX.IntrinsicElements;
}
class TextComponent extends React.Component<TextComponentProps> {
render() {
return (
@ -14,10 +30,4 @@ class TextComponent extends React.Component<TextComponentProps> {
}
}
export interface TextComponentProps extends ComponentProps {
text?: string;
ellipsize?: boolean;
tagName?: keyof JSX.IntrinsicElements;
}
export default TextComponent;

View File

@ -0,0 +1,7 @@
import { Form } from "redux-form";
import styled from "styled-components";
export default styled(Form)`
display: flex;
flex-direction: column;
`;

View File

@ -0,0 +1,10 @@
import styled from "styled-components";
export default styled.p`
font-weight: 500;
font-size: 14px;
line-height: 16px;
letter-spacing: 0.02em;
color: #4e5d78;
margin-bottom: 5px;
`;

View File

@ -0,0 +1,9 @@
import styled from "styled-components";
export default styled.div`
display: flex;
flex: 1;
flex-direction: row;
justify-content: space-between;
align-items: center;
`;

View File

@ -0,0 +1,37 @@
import React from "react";
import AceEditor from "react-ace";
import "ace-builds/src-noconflict/mode-json";
import "ace-builds/src-noconflict/theme-textmate";
const aceOnBlur = (onBlur: any) => (_event: any, editor?: any) => {
const value = editor.getValue();
onBlur(value);
};
const JSONEditor = (props: any) => {
const { input } = props;
return (
<AceEditor
mode="json"
theme="textmate"
fontSize={14}
showPrintMargin={true}
showGutter={true}
highlightActiveLine={true}
width="100%"
setOptions={{
enableBasicAutocompletion: true,
enableLiveAutocompletion: false,
enableSnippets: false,
showLineNumbers: true,
tabSize: 2,
}}
name={input.name}
onBlur={aceOnBlur(input.onBlur)}
onChange={input.onChange}
onFocus={input.onFocus}
value={input.value}
/>
);
};
export default JSONEditor;

View File

@ -0,0 +1,28 @@
import React from "react";
import ReactJson from "react-json-view";
import styled from "styled-components";
const JSONViewWrapper = styled.div`
max-height: 600px;
overflow-y: auto;
`;
const JSONViewer = (props: { data: JSON }) => {
if (!props.data) return null;
return (
<JSONViewWrapper>
<ReactJson
src={props.data}
displayObjectSize={false}
displayDataTypes={false}
indentWidth={2}
enableClipboard={false}
style={{
fontSize: "10px",
}}
/>
</JSONViewWrapper>
);
};
export default JSONViewer;

View File

@ -1,8 +1,8 @@
import React from "react";
import styled from "styled-components";
import NavBarItem from "./NavBarItem";
import { MenuIcons } from "../icons/MenuIcons";
import { BUILDER_URL, API_EDITOR_URL } from "../constants/routes";
import { MenuIcons } from "../../icons/MenuIcons";
import { BUILDER_URL, API_EDITOR_URL } from "../../constants/routes";
import Sidebar from "./Sidebar";
const Container = styled.div`

View File

@ -1,9 +1,13 @@
import React from "react";
import { Switch, Route } from "react-router";
import styled from "styled-components";
import { API_EDITOR_URL, BUILDER_URL } from "../constants/routes";
import WidgetSidebar from "../pages/Editor/WidgetSidebar";
import ApiSidebar from "../pages/Editor/ApiSidebar";
import {
API_EDITOR_URL,
BUILDER_URL,
API_EDITOR_ID_URL,
} from "../../constants/routes";
import WidgetSidebar from "../../pages/Editor/WidgetSidebar";
import ApiSidebar from "../../pages/Editor/ApiSidebar";
const SidebarWrapper = styled.div`
flex: 7;
@ -20,6 +24,7 @@ class Sidebar extends React.Component {
<Switch>
<Route exact path={BUILDER_URL} component={WidgetSidebar} />
<Route exact path={API_EDITOR_URL} component={ApiSidebar} />
<Route exact path={API_EDITOR_ID_URL()} component={ApiSidebar} />
</Switch>
</SidebarWrapper>
</React.Fragment>

View File

@ -0,0 +1,26 @@
import React from "react";
import _ from "lodash";
import { BaseDropdown } from "../canvas/Dropdown";
import { Field } from "redux-form";
interface DropdownFieldProps {
name: string;
options: Array<{
label: string;
value: string;
}>;
}
const DropdownField = (props: DropdownFieldProps) => {
return (
<Field
name={props.name}
component={BaseDropdown}
options={props.options}
format={(value: string) => _.find(props.options, { value })}
normalize={(option: { value: string }) => option.value}
/>
);
};
export default DropdownField;

View File

@ -0,0 +1,17 @@
import React from "react";
import { Field } from "redux-form";
import JSONEditor from "../editor/JSONEditor";
const JSONEditorField = (props: { name: string }) => {
return (
<Field
name={props.name}
component={JSONEditor}
format={(value: string | object) =>
typeof value === "string" ? value : JSON.stringify(value)
}
/>
);
};
export default JSONEditorField;

View File

@ -0,0 +1,73 @@
import React from "react";
import { FieldArray, WrappedFieldArrayProps } from "redux-form";
import { Icon } from "@blueprintjs/core";
import { FormIcons } from "../../icons/FormIcons";
import TextField from "./TextField";
import FormRow from "../editor/FormRow";
import FormLabel from "../editor/FormLabel";
import styled from "styled-components";
const FormRowWithLabel = styled(FormRow)`
flex-wrap: wrap;
${FormLabel} {
width: 100%;
}
& svg {
cursor: pointer;
}
`;
const KeyValueRow = (props: Props & WrappedFieldArrayProps) => {
return (
<React.Fragment>
{props.fields.length === 0 && (
<FormRowWithLabel>
<FormLabel>{props.label}</FormLabel>
<TextField name={`${props.name}[0].key`} placeholderMessage="Key" />
<TextField
name={`${props.name}[0].value`}
placeholderMessage="Value"
/>
<Icon
icon="plus"
iconSize={20}
onClick={() => props.fields.push({ key: "", value: "" })}
color={"#A3B3BF"}
/>
</FormRowWithLabel>
)}
{props.fields.map((field: any, index: number) => (
<FormRowWithLabel key={index}>
{index === 0 && <FormLabel>{props.label}</FormLabel>}
<TextField name={`${field}.key`} placeholderMessage="Key" />
<TextField name={`${field}.value`} placeholderMessage="Value" />
{index === props.fields.length - 1 ? (
<Icon
icon="plus"
iconSize={20}
onClick={() => props.fields.push({ key: "", value: "" })}
color={"#A3B3BF"}
/>
) : (
<FormIcons.DELETE_ICON
height={20}
width={20}
onClick={() => props.fields.remove(index)}
/>
)}
</FormRowWithLabel>
))}
</React.Fragment>
);
};
type Props = {
name: string;
label: string;
};
const KeyValueFieldArray = (props: Props) => {
return <FieldArray name={props.name} component={KeyValueRow} {...props} />;
};
export default KeyValueFieldArray;

View File

@ -0,0 +1,16 @@
import React from "react";
import { Field } from "redux-form";
import { BaseTextInput, TextInputProps } from "../canvas/TextInputComponent";
interface TextFieldProps {
name: string;
}
class TextField extends React.Component<TextFieldProps & TextInputProps> {
render() {
const { name } = this.props;
return <Field name={name} component={BaseTextInput} {...this.props} />;
}
}
export default TextField;

View File

@ -0,0 +1,179 @@
import React from "react";
import { reduxForm, InjectedFormProps, FormSubmitHandler } from "redux-form";
import FormRow from "../editor/FormRow";
import TextField from "../fields/TextField";
import {
FORM_INITIAL_VALUES,
HTTP_METHOD_OPTIONS,
} from "../../constants/ApiEditorConstants";
import CreatableDropdown from "../canvas/CreatableDropdown";
import FormLabel from "../editor/FormLabel";
import { BaseText } from "../canvas/TextViewComponent";
import { BaseTabbedView } from "../canvas/TabbedView";
import styled from "styled-components";
import FormContainer from "../editor/FormContainer";
import { BaseButton } from "../canvas/Button";
import KeyValueFieldArray from "../fields/KeyValueFieldArray";
import JSONEditorField from "../fields/JSONEditorField";
import DropdownField from "../fields/DropdownField";
import { RestAction } from "../../api/ActionAPI";
import JSONViewer from "../../components/editor/JSONViewer";
const Form = styled(FormContainer)`
height: 100%;
width: 100%;
${FormRow} {
flex-wrap: wrap;
padding: ${props => props.theme.spaces[3]}px;
& > * {
margin-right: 5px;
}
${FormLabel} {
width: 100%;
}
}
`;
const SecondaryWrapper = styled.div`
display: flex;
border-top: 1px solid #d0d7dd;
height: 100%;
`;
const ForwardSlash = styled.div`
&& {
margin: 0 10px;
height: 22px;
width: 1px;
background-color: #d0d7dd;
transform: rotate(27deg);
}
`;
const RequestParamsWrapper = styled.div`
flex: 5;
border-right: 1px solid #d0d7dd;
`;
const ResponseWrapper = styled.div`
flex: 4;
`;
const ActionButton = styled(BaseButton)`
max-width: 72px;
margin: 0 5px;
`;
const ResponseMetaInfo = styled.div`
display: flex;
${BaseText} {
color: #768896;
margin: 0 5px;
}
`;
const JSONEditorFieldWrapper = styled.div`
flex: 1;
border: 1px solid #d0d7dd;
border-radius: 4px;
`;
interface APIFormProps {
onSubmit: FormSubmitHandler<RestAction>;
onSaveClick: () => void;
onRunClick: () => void;
onDeleteClick: () => void;
response: any;
}
type Props = APIFormProps & InjectedFormProps<RestAction, APIFormProps>;
class ApiEditorForm extends React.Component<Props> {
render() {
const { onSaveClick, onDeleteClick, onRunClick } = this.props;
return (
<Form>
<FormRow>
<TextField name="name" placeholderMessage="API Name" />
<ActionButton
text="Delete"
styleName="error"
onClick={onDeleteClick}
/>
<ActionButton text="Run" styleName="secondary" onClick={onRunClick} />
<ActionButton
text="Save"
styleName="primary"
filled
onClick={onSaveClick}
/>
</FormRow>
<FormRow>
<DropdownField
name="actionConfiguration.httpMethod"
options={HTTP_METHOD_OPTIONS}
/>
<CreatableDropdown options={[]} placeholder="Resource" />
<ForwardSlash />
<TextField
placeholderMessage="API Path"
name="actionConfiguration.path"
/>
</FormRow>
<SecondaryWrapper>
<RequestParamsWrapper>
<KeyValueFieldArray
name="actionConfiguration.headers"
label="Headers"
/>
<KeyValueFieldArray
name="actionConfiguration.queryParameters"
label="Params"
/>
<FormRow>
<FormLabel>Post Body</FormLabel>
<JSONEditorFieldWrapper>
<JSONEditorField name="actionConfiguration.body" />
</JSONEditorFieldWrapper>
</FormRow>
</RequestParamsWrapper>
<ResponseWrapper>
<FormRow>
<BaseText styleName="secondary">
{this.props.response.statusCode}
</BaseText>
<ResponseMetaInfo>
<BaseText styleName="secondary">300ms</BaseText>
<BaseText styleName="secondary">203 kb</BaseText>
</ResponseMetaInfo>
</FormRow>
<BaseTabbedView
tabs={[
{
key: "body",
title: "Response Body",
panelComponent: () => (
<JSONViewer data={this.props.response.body} />
),
},
{
key: "headers",
title: "Response Headers",
panelComponent: () => (
<JSONViewer data={this.props.response.headers} />
),
},
]}
/>
</ResponseWrapper>
</SecondaryWrapper>
</Form>
);
}
}
export default reduxForm<RestAction, APIFormProps>({
form: "ApiEditorForm",
enableReinitialize: true,
initialValues: FORM_INITIAL_VALUES,
})(ApiEditorForm);

View File

@ -61,8 +61,8 @@ export interface DownloadDataActionPayload extends ActionPayload {
}
export interface PageAction {
actionId: string;
id: string;
actionType: ActionType;
actionName: string;
dynamicBindings?: string[];
name: string;
jsonPathKeys?: string[];
}

View File

@ -0,0 +1,10 @@
export const HTTP_METHODS = ["GET", "POST", "PUT", "DELETE"];
export const HTTP_METHOD_OPTIONS = HTTP_METHODS.map(method => ({
label: method,
value: method,
}));
export const FORM_INITIAL_VALUES = {
resourceId: "5d808014795dc6000482bc83",
};

View File

@ -3,7 +3,11 @@ export const Colors: Record<string, string> = {
WHITE: "#FFFFFF",
POLAR: "#E9FAF3",
GEYSER: "#D3DEE3",
GEYSER_LIGHT: "#D0D7DD",
ATHENS_GRAY: "#FAFBFC",
CONCRETE: "#F3F3F3",
MYSTIC: "#E1E8ED",
AQUA_HAZE: "#EEF2F5",
BLACK: "#000000",
BLACK_PEARL: "#040627",
@ -14,8 +18,11 @@ export const Colors: Record<string, string> = {
PORCELAIN: "#EBEEF0",
HIT_GRAY: "#A1ACB3",
JUNGLE_MIST: "#BCCCD9",
MERCURY: "#E8E8E8",
GREEN: "#29CCA3",
JUNGLE_GREEN: "#24BA91",
JUNGLE_GREEN_DARKER: "#30A481",
RED: "#CE4257",
PURPLE: "#6871EF",
OXFORD_BLUE: "#2E3D49",

View File

@ -26,6 +26,7 @@ type PropertyPaneTheme = {
export type Theme = {
radii: Array<number>;
fontSizes: Array<number>;
drawerWidth: string;
spaces: Array<number>;
fontWeights: Array<number>;
colors: Record<string, Color>;
@ -62,10 +63,19 @@ export const theme: Theme = {
width: 250,
height: 600,
},
drawerWidth: "80%",
colors: {
primary: Colors.GREEN,
primaryDarker: Colors.JUNGLE_GREEN,
primaryDarkest: Colors.JUNGLE_GREEN_DARKER,
secondary: Colors.GEYSER_LIGHT,
secondaryDarker: Colors.CONCRETE,
secondaryDarkest: Colors.MERCURY,
error: Colors.RED,
info: Colors.SLATE_GRAY,
hover: Colors.POLAR,
inputInactiveBorders: Colors.MYSTIC,
inputInactiveBG: Colors.AQUA_HAZE,
textDefault: Colors.BLACK_PEARL,
textOnDarkBG: Colors.WHITE,
textAnchor: Colors.PURPLE,
@ -92,7 +102,7 @@ export const theme: Theme = {
color: Colors.FRENCH_PASS,
},
],
sidebarWidth: "350px",
sidebarWidth: "300px",
headerHeight: "50px",
};

View File

@ -1,5 +1,5 @@
import styled from "styled-components";
import { Color } from "../constants/Colors";
import { Color } from "./Colors";
export type IconProps = {
width: number;

View File

@ -40,6 +40,14 @@ export const ReduxActionTypes: { [key: string]: string } = {
FETCH_PROPERTY_PANE_CONFIGS_SUCCESS: "FETCH_PROPERTY_PANE_CONFIGS_SUCCESS",
FETCH_CONFIGS_INIT: "FETCH_CONFIGS_INIT",
ADD_WIDGET_REF: "ADD_WIDGET_REF",
CREATE_ACTION: "CREATE_ACTION",
FETCH_ACTIONS_INIT: "FETCH_ACTIONS_INIT",
FETCH_ACTIONS_SUCCESS: "FETCH_ACTIONS_SUCCESS",
FETCH_ACTION: "FETCH_ACTION",
RUN_ACTION: "RUN_ACTION",
RUN_ACTION_SUCCESS: "RUN_ACTION_SUCCESS",
UPDATE_ACTION: "UPDATE_ACTION",
DELETE_ACTION: "DELETE_ACTION",
};
export type ReduxActionType = (typeof ReduxActionTypes)[keyof typeof ReduxActionTypes];
@ -57,6 +65,7 @@ export const ReduxActionErrorTypes: { [key: string]: string } = {
FETCH_PROPERTY_PANE_CONFIGS_ERROR: "FETCH_PROPERTY_PANE_CONFIGS_ERROR",
FETCH_CONFIGS_ERROR: "FETCH_CONFIGS_ERROR",
PROPERTY_PANE_ERROR: "PROPERTY_PANE_ERROR",
FETCH_ACTIONS_ERROR: "FETCH_ACTIONS_ERROR",
};
export type ReduxActionErrorType = (typeof ReduxActionErrorTypes)[keyof typeof ReduxActionErrorTypes];

View File

@ -2,3 +2,4 @@ export const BASE_URL = "/";
export const LOGIN_URL = "/login";
export const BUILDER_URL = "/builder";
export const API_EDITOR_URL = `${BUILDER_URL}/api`;
export const API_EDITOR_ID_URL = (id = ":id") => `${API_EDITOR_URL}/${id}`;

View File

@ -1,23 +0,0 @@
import React from "react";
import { Button, MaybeElement } from "@blueprintjs/core";
import { TextComponentProps } from "./TextComponent";
import { Container } from "./ContainerComponent";
class ButtonComponent extends React.Component<ButtonComponentProps> {
render() {
return (
<Container {...this.props}>
<Button icon={this.props.icon} onClick={this.props.onClick}>
{this.props.text}
</Button>
</Container>
);
}
}
interface ButtonComponentProps extends TextComponentProps {
icon?: MaybeElement;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
}
export default ButtonComponent;

View File

@ -17,13 +17,11 @@ export const Container = styled("div")<ContainerProps>`
left: 0;
top: 0;
width: 100%;
padding: ${props => props.theme.spaces[8]}px ${props =>
props.theme.spaces[1]}px ${props => props.theme.spaces[1]}px;
padding: ${props => props.theme.spaces[1]}px;
&:after {
content: "${props => props.widgetName}";
position: absolute;
left: ${props => props.theme.spaces[1]}px;
top: ${props => props.theme.spaces[1]}px;
top: -${props => props.theme.spaces[8]}px;
font-size: ${props => props.theme.fontSizes[2]}px;
color: ${props => props.theme.colors.containerBorder};
text-align: left;

View File

@ -0,0 +1,22 @@
import React from "react";
import { Icon } from "@blueprintjs/core";
import { IconNames } from "@blueprintjs/icons";
import { IconProps, IconWrapper } from "../constants/IconConstants";
import { ReactComponent as DeleteIcon } from "../assets/icons/form/trash.svg";
/* eslint-disable react/display-name */
export const FormIcons: {
[id: string]: Function;
} = {
DELETE_ICON: (props: IconProps) => (
<IconWrapper {...props}>
<DeleteIcon />
</IconWrapper>
),
PLUS_ICON: (props: IconProps) => (
<IconWrapper {...props}>
<Icon icon={IconNames.PLUS} color={props.color} iconSize={props.height} />
</IconWrapper>
),
};

View File

@ -42,10 +42,10 @@ const PageMockResponse: FetchPageResponse = {
},
actions: [
{
actionId: "5d8082e2795dc6000482bc84",
id: "5d8082e2795dc6000482bc84",
actionType: "API" as ActionType,
actionName: "getUsers",
dynamicBindings: ["$.apiData.0.name"],
name: "getUsers",
jsonPathKeys: ["$.apiData.0.name"],
},
],
},

View File

@ -1,9 +1,120 @@
import React from "react";
import { connect } from "react-redux";
import { submit, initialize, getFormValues } from "redux-form";
import ApiEditorForm from "../../components/forms/ApiEditorForm";
import {
createAction,
runAction,
deleteAction,
updateAction,
} from "../../actions/actionActions";
import { RestAction } from "../../api/ActionAPI";
import { AppState } from "../../reducers";
import { RouteComponentProps } from "react-router";
import { API_EDITOR_URL } from "../../constants/routes";
interface ReduxStateProps {
actions: RestAction[];
response: any;
formData: any;
}
interface ReduxActionProps {
submitForm: (name: string) => void;
createAction: (values: RestAction) => void;
runAction: (id: string) => void;
deleteAction: (id: string) => void;
updateAction: (data: RestAction) => void;
initialize: (formName: string, data?: Partial<RestAction>) => void;
}
type Props = ReduxActionProps &
ReduxStateProps &
RouteComponentProps<{ id: string }>;
class ApiEditor extends React.Component<Props> {
componentDidMount(): void {
const currentId = this.props.match.params.id;
if (!currentId) return;
if (!this.props.actions.length) {
this.props.history.push(API_EDITOR_URL);
return;
}
const data = this.props.actions.filter(
action => action.id === currentId,
)[0];
this.props.initialize("ApiEditorForm", data);
}
componentDidUpdate(prevProps: Readonly<Props>): void {
const currentId = this.props.match.params.id;
if (currentId && currentId !== prevProps.match.params.id) {
const data = this.props.actions.filter(
action => action.id === currentId,
)[0];
this.props.initialize("ApiEditorForm", data);
}
}
handleSubmit = (values: RestAction) => {
const { formData } = this.props;
const data: RestAction = {
...formData,
actionConfiguration: {
...formData.actionConfiguration,
body: formData.actionConfiguration.body
? typeof formData.actionConfiguration.body === "string"
? JSON.parse(formData.actionConfiguration.body)
: formData.actionConfiguration.body
: null,
},
};
if (data.id) {
this.props.updateAction(data);
} else {
this.props.createAction(data);
}
};
handleSaveClick = () => {
this.props.submitForm("ApiEditorForm");
};
handleDeleteClick = () => {
this.props.deleteAction(this.props.match.params.id);
};
handleRunClick = () => {
this.props.runAction(this.props.match.params.id);
};
class ApiEditor extends React.Component {
render() {
return <span>API editor</span>;
return (
<ApiEditorForm
onSubmit={this.handleSubmit}
onSaveClick={this.handleSaveClick}
onDeleteClick={this.handleDeleteClick}
onRunClick={this.handleRunClick}
response={this.props.response}
/>
);
}
}
export default ApiEditor;
const mapStateToProps = (state: AppState): ReduxStateProps => ({
actions: state.entities.actions.data,
response: state.entities.actions.response,
formData: getFormValues("ApiEditorForm")(state),
});
const mapDispatchToProps = (dispatch: any): ReduxActionProps => ({
submitForm: (name: string) => dispatch(submit(name)),
createAction: (action: RestAction) => dispatch(createAction(action)),
runAction: (id: string) => dispatch(runAction({ id })),
deleteAction: (id: string) => dispatch(deleteAction({ id })),
updateAction: (data: RestAction) => dispatch(updateAction({ data })),
initialize: (formName: string, data?: Partial<RestAction>) =>
dispatch(initialize(formName, data)),
});
export default connect(
mapStateToProps,
mapDispatchToProps,
)(ApiEditor);

View File

@ -1,9 +1,98 @@
import React from "react";
import { connect } from "react-redux";
import { RouteComponentProps } from "react-router";
import styled from "styled-components";
import { AppState } from "../../reducers";
import { fetchActions } from "../../actions/actionActions";
import { ActionDataState } from "../../reducers/entityReducers/actionsReducer";
import { API_EDITOR_ID_URL } from "../../constants/routes";
const ApiItem = styled.div<{ isSelected: boolean }>`
width: 100%;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
display: flex;
background-color: ${props =>
props.isSelected ? props.theme.colors.paneCard : props.theme.colors.paneBG}
:hover {
background-color: ${props => props.theme.colors.paneCard};
}
`;
const HTTPMethod = styled.span<{ method: string }>`
flex: 1;
color: ${props => {
switch (props.method) {
case "GET":
return "#29CCA3";
case "POST":
return "#F7C75B";
case "PUT":
return "#30A5E0";
case "DELETE":
return "#CE4257";
default:
return "#333";
}
}};
`;
const ActionName = styled.span`
flex: 3;
`;
interface ReduxStateProps {
actions: ActionDataState;
}
interface ReduxActionProps {
fetchActions: () => void;
selectAction: (id: string) => void;
}
type Props = ReduxStateProps &
ReduxActionProps &
RouteComponentProps<{ id: string }>;
class ApiSidebar extends React.Component<Props> {
componentDidMount(): void {
this.props.fetchActions();
}
class ApiSidebar extends React.Component {
render() {
return <p>Apis</p>;
const { actions, history, match } = this.props;
const activeActionId = match.params.id;
return (
<React.Fragment>
{actions.loading && "Loading..."}
{actions.data.map(action => (
<ApiItem
key={action.id}
onClick={() => history.push(API_EDITOR_ID_URL(action.id))}
isSelected={activeActionId === action.id}
>
<HTTPMethod method={action.actionConfiguration.httpMethod}>
{action.actionConfiguration.httpMethod}
</HTTPMethod>
<ActionName>{action.name}</ActionName>
</ApiItem>
))}
</React.Fragment>
);
}
}
export default ApiSidebar;
const mapStateToProps = (state: AppState): ReduxStateProps => ({
actions: state.entities.actions,
});
const mapDispatchToProps = (dispatch: any) => ({
fetchActions: () => dispatch(fetchActions()),
});
export default connect(
mapStateToProps,
mapDispatchToProps,
)(ApiSidebar);

View File

@ -4,7 +4,7 @@ import styled from "styled-components";
import { AppState } from "../../reducers";
import EditorHeader from "./EditorHeader";
import EditorsRouter from "./routes";
import NavBar from "../../editorComponents/NavBar";
import NavBar from "../../components/editor/NavBar";
import WidgetsEditor from "./WidgetsEditor";
const MainContainer = styled.div`

View File

@ -6,9 +6,14 @@ import {
RouteComponentProps,
} from "react-router-dom";
import ApiEditor from "./ApiEditor";
import { API_EDITOR_URL, BUILDER_URL } from "../../constants/routes";
import {
API_EDITOR_ID_URL,
API_EDITOR_URL,
BUILDER_URL,
} from "../../constants/routes";
import { Drawer, Position } from "@blueprintjs/core";
import styled from "styled-components";
import { theme } from "../../constants/DefaultTheme";
const MainWrapper = styled.div`
position: absolute;
@ -44,10 +49,12 @@ class EditorsRouter extends React.Component<RouteComponentProps, RouterState> {
isOpen={drawerOpen}
position={Position.LEFT}
usePortal={false}
size="75%"
size={theme.drawerWidth}
canOutsideClickClose={true}
>
<Switch>
<Route exact path={API_EDITOR_URL} component={ApiEditor} />
<Route exact path={API_EDITOR_ID_URL()} component={ApiEditor} />
</Switch>
</Drawer>
</MainWrapper>

View File

@ -2,15 +2,34 @@ import { createReducer } from "../../utils/AppsmithUtils";
import {
ReduxActionTypes,
ReduxAction,
ReduxActionErrorTypes,
} from "../../constants/ReduxActionConstants";
import _ from "lodash";
import { ActionCreateUpdateResponse } from "../../api/ActionAPI";
import { PageAction } from "../../constants/ActionConstants";
import { RestAction } from "../../api/ActionAPI";
const initialState: ActionDataState = {};
const initialState: ActionDataState = {
list: {},
data: [],
response: {
body: null,
headers: null,
statusCode: "",
},
loading: false,
};
export interface ActionDataState {
[name: string]: ActionCreateUpdateResponse;
list: {
[name: string]: PageAction;
};
data: RestAction[];
response: {
body: any;
headers: any;
statusCode: string;
};
loading: boolean;
}
const actionsReducer = createReducer(initialState, {
@ -19,9 +38,27 @@ const actionsReducer = createReducer(initialState, {
action: ReduxAction<PageAction[]>,
) => {
const actionMap = _.mapKeys(action.payload, (action: PageAction) => {
return action.actionId;
return action.id;
});
return { ...state, ...actionMap };
return { ...state, list: { ...actionMap } };
},
[ReduxActionTypes.FETCH_ACTIONS_INIT]: (state: ActionDataState) => {
return { ...state, loading: true };
},
[ReduxActionTypes.FETCH_ACTIONS_SUCCESS]: (
state: ActionDataState,
action: ReduxAction<RestAction[]>,
) => {
return { ...state, data: action.payload, loading: false };
},
[ReduxActionErrorTypes.FETCH_ACTIONS_ERROR]: (state: ActionDataState) => {
return { ...state, data: [], loading: false };
},
[ReduxActionTypes.RUN_ACTION_SUCCESS]: (
state: ActionDataState,
action: ReduxAction<any>,
) => {
return { ...state, response: action.payload };
},
});

View File

@ -1,6 +1,7 @@
import { combineReducers } from "redux";
import entityReducer from "./entityReducers";
import uiReducer from "./uiReducers";
import { reducer as formReducer } from "redux-form";
import { CanvasWidgetsReduxState } from "./entityReducers/canvasWidgetsReducer";
import { EditorReduxState } from "./uiReducers/editorReducer";
import { ErrorReduxState } from "./uiReducers/errorReducer";
@ -15,6 +16,7 @@ import { WidgetSidebarReduxState } from "./uiReducers/widgetSidebarReducer";
const appReducer = combineReducers({
entities: entityReducer,
ui: uiReducer,
form: formReducer,
});
export default appReducer;

View File

@ -0,0 +1,175 @@
import {
ReduxAction,
ReduxActionErrorTypes,
ReduxActionTypes,
} from "../constants/ReduxActionConstants";
import { Intent } from "@blueprintjs/core";
import { all, call, select, put, takeEvery } from "redux-saga/effects";
import { initialize } from "redux-form";
import { ActionPayload, PageAction } from "../constants/ActionConstants";
import ActionAPI, {
ActionCreateUpdateResponse,
ExecuteActionRequest,
RestAction,
} from "../api/ActionAPI";
import { AppState } from "../reducers";
import { JSONPath } from "jsonpath-plus";
import _ from "lodash";
import { mapToPropList } from "../utils/AppsmithUtils";
import AppToaster from "../components/editor/ToastComponent";
import { GenericApiResponse } from "../api/ApiResponses";
import { fetchActions } from "../actions/actionActions";
const getDataTree = (state: AppState) => {
return state.entities;
};
const getAction = (state: AppState, actionId: string): PageAction => {
return state.entities.actions.list[actionId];
};
export function* evaluateJSONPathSaga(jsonPath: string): any {
const dataTree = yield select(getDataTree);
return JSONPath({ path: jsonPath, json: dataTree });
}
export function* executeAPIQueryActionSaga(apiAction: ActionPayload) {
const api: PageAction = yield select(getAction, apiAction.actionId);
const executeActionRequest: ExecuteActionRequest = {
actionId: apiAction.actionId,
};
if (!_.isNil(api.jsonPathKeys)) {
const responses: any = yield all(
api.jsonPathKeys.map((jsonPath: string) => {
return call(evaluateJSONPathSaga, jsonPath);
}),
);
const dynamicBindingMap: Record<string, any> = _.keyBy(
responses,
(response: string, index: number) => {
return api.jsonPathKeys ? api.jsonPathKeys[index] : undefined;
},
);
executeActionRequest.dynamicBindingList = mapToPropList(dynamicBindingMap);
}
yield ActionAPI.executeAction(executeActionRequest);
}
export function* executeActionSaga(action: ReduxAction<ActionPayload[]>) {
if (!_.isNil(action.payload)) {
yield all(
_.map(action.payload, (actionPayload: ActionPayload) => {
switch (actionPayload.actionType) {
case "API":
return call(executeAPIQueryActionSaga, actionPayload);
case "QUERY":
return call(executeAPIQueryActionSaga, actionPayload);
}
return undefined;
}),
);
}
}
export function* createActionSaga(actionPayload: ReduxAction<RestAction>) {
const response: ActionCreateUpdateResponse = yield ActionAPI.createAPI(
actionPayload.payload,
);
if (response.responseMeta.success) {
AppToaster.show({
message: `${actionPayload.payload.name} Action created`,
intent: Intent.SUCCESS,
});
yield put(fetchActions());
}
}
export function* fetchActionsSaga() {
const response: GenericApiResponse<
RestAction[]
> = yield ActionAPI.fetchActions();
if (response.responseMeta.success) {
yield put({
type: ReduxActionTypes.FETCH_ACTIONS_SUCCESS,
payload: response.data,
});
} else {
yield put({
type: ReduxActionErrorTypes.FETCH_ACTIONS_ERROR,
payload: response.responseMeta.status,
});
}
}
export function* fetchActionSaga(actionPayload: ReduxAction<{ id: string }>) {
const response: GenericApiResponse<RestAction> = yield ActionAPI.fetchAPI(
actionPayload.payload.id,
);
const data = response.data;
yield put(initialize("ApiEditorForm", data));
}
export function* runActionSaga(actionPayload: ReduxAction<{ id: string }>) {
const id = actionPayload.payload.id;
const response: any = yield ActionAPI.executeAction({ actionId: id });
yield put({
type: ReduxActionTypes.RUN_ACTION_SUCCESS,
payload: response,
});
}
export function* updateActionSaga(
actionPayload: ReduxAction<{ data: RestAction }>,
) {
const finalFields: Partial<RestAction> = _.omit(
actionPayload.payload.data,
"new",
);
const response: GenericApiResponse<RestAction> = yield ActionAPI.updateAPI(
finalFields,
);
if (response.responseMeta.success) {
AppToaster.show({
message: `${actionPayload.payload.data.name} Action updated`,
intent: Intent.SUCCESS,
});
yield put(fetchActions());
} else {
AppToaster.show({
message: "Error occurred when updating action",
intent: Intent.DANGER,
});
}
}
export function* deleteActionSaga(actionPayload: ReduxAction<{ id: string }>) {
const id = actionPayload.payload.id;
const response: GenericApiResponse<RestAction> = yield ActionAPI.deleteAction(
id,
);
if (response.responseMeta.success) {
AppToaster.show({
message: `${response.data.name} Action deleted`,
intent: Intent.SUCCESS,
});
yield put(fetchActions());
} else {
AppToaster.show({
message: "Error occurred when deleting action",
intent: Intent.DANGER,
});
}
}
export function* watchActionSagas() {
yield all([
takeEvery(ReduxActionTypes.FETCH_ACTIONS_INIT, fetchActionsSaga),
takeEvery(ReduxActionTypes.EXECUTE_ACTION, executeActionSaga),
takeEvery(ReduxActionTypes.CREATE_ACTION, createActionSaga),
takeEvery(ReduxActionTypes.FETCH_ACTION, fetchActionSaga),
takeEvery(ReduxActionTypes.RUN_ACTION, runActionSaga),
takeEvery(ReduxActionTypes.UPDATE_ACTION, updateActionSaga),
takeEvery(ReduxActionTypes.DELETE_ACTION, deleteActionSaga),
]);
}

View File

@ -1,74 +0,0 @@
import {
ReduxActionTypes,
ReduxAction,
} from "../constants/ReduxActionConstants";
import { call, takeEvery, select, all } from "redux-saga/effects";
import { PageAction, ActionPayload } from "../constants/ActionConstants";
import ActionAPI, {
ActionCreateUpdateResponse,
ExecuteActionRequest,
} from "../api/ActionAPI";
import { AppState } from "../reducers";
import { JSONPath } from "jsonpath-plus";
import _ from "lodash";
import { mapToPropList } from "../utils/AppsmithUtils";
const getDataTree = (state: AppState) => {
return state.entities;
};
const getAction = (
state: AppState,
actionId: string,
): ActionCreateUpdateResponse => {
return state.entities.actions[actionId];
};
export function* evaluateJSONPathSaga(jsonPath: string): any {
const dataTree = yield select(getDataTree);
const result = JSONPath({ path: jsonPath, json: dataTree });
return result;
}
export function* executeAPIQueryActionSaga(apiAction: ActionPayload) {
const api: PageAction = yield select(getAction, apiAction.actionId);
const executeActionRequest: ExecuteActionRequest = {
actionId: apiAction.actionId,
};
if (!_.isNil(api.dynamicBindings)) {
const responses: any = yield all(
api.dynamicBindings.map((jsonPath: string) => {
return call(evaluateJSONPathSaga, jsonPath);
}),
);
const dynamicBindingMap: Record<string, any> = _.keyBy(
responses,
(response: string, index: number) => {
return api.dynamicBindings ? api.dynamicBindings[index] : undefined;
},
);
executeActionRequest.dynamicBindingList = mapToPropList(dynamicBindingMap);
}
yield ActionAPI.executeAction(executeActionRequest);
}
export function* executeActionSaga(action: ReduxAction<ActionPayload[]>) {
if (!_.isNil(action.payload)) {
yield all(
_.map(action.payload, (actionPayload: ActionPayload) => {
switch (actionPayload.actionType) {
case "API":
return call(executeAPIQueryActionSaga, actionPayload);
case "QUERY":
return call(executeAPIQueryActionSaga, actionPayload);
}
return undefined;
}),
);
}
}
export function* watchExecuteActionSaga() {
yield takeEvery(ReduxActionTypes.EXECUTE_ACTION, executeActionSaga);
}

View File

@ -5,7 +5,7 @@ import {
ReduxActionErrorTypes,
ReduxAction,
} from "../constants/ReduxActionConstants";
import AppToaster from "../editorComponents/ToastComponent";
import AppToaster from "../components/editor/ToastComponent";
import {
DEFAULT_ERROR_MESSAGE,
DEFAULT_ACTION_ERROR,

View File

@ -1,7 +1,7 @@
import { all, spawn } from "redux-saga/effects";
import pageSagas from "../sagas/PageSagas";
import { fetchWidgetCardsSaga } from "./WidgetSidebarSagas";
import { watchExecuteActionSaga } from "./ActionSagas";
import { watchActionSagas } from "./ActionSagas";
import widgetOperationSagas from "./WidgetOperationSagas";
import errorSagas from "./ErrorSagas";
import configsSagas from "./ConfigsSagas";
@ -9,7 +9,7 @@ export function* rootSaga() {
yield all([
spawn(pageSagas),
spawn(fetchWidgetCardsSaga),
spawn(watchExecuteActionSaga),
spawn(watchActionSagas),
spawn(widgetOperationSagas),
spawn(errorSagas),
spawn(configsSagas),

View File

@ -1,7 +1,7 @@
import * as React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import { WidgetType } from "../constants/WidgetConstants";
import ButtonComponent from "../editorComponents/ButtonComponent";
import ButtonComponent from "../components/canvas/Button";
import { ActionPayload } from "../constants/ActionConstants";
class ButtonWidget extends BaseWidget<ButtonWidgetProps, WidgetState> {

View File

@ -1,12 +1,12 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import { WidgetType } from "../constants/WidgetConstants";
import TextComponent from "../editorComponents/TextComponent";
import TextViewComponent from "../components/canvas/TextViewComponent";
class TextWidget extends BaseWidget<TextWidgetProps, WidgetState> {
getPageView() {
return (
<TextComponent
<TextViewComponent
style={this.getPositionStyle()}
widgetId={this.props.widgetId}
key={this.props.widgetId}

View File

@ -861,6 +861,13 @@
dependencies:
regenerator-runtime "^0.13.2"
"@babel/runtime@^7.2.0", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5":
version "7.6.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.3.tgz#935122c74c73d2240cafd32ddb5fc2a6cd35cf1f"
integrity sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==
dependencies:
regenerator-runtime "^0.13.2"
"@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0":
version "7.6.0"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6"
@ -965,6 +972,42 @@
resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-9.0.1.tgz#c27b391d8457d1e893f1eddeaf5e5412d12ffbb5"
integrity sha512-6It2EVfGskxZCQhuykrfnALg7oVeiI6KclWSmGDqB0AiInVrTGB9Jp9i4/Ad21u9Jde/voVQz6eFX/eSg/UsPA==
"@emotion/cache@^10.0.17", "@emotion/cache@^10.0.9":
version "10.0.19"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.19.tgz#d258d94d9c707dcadaf1558def968b86bb87ad71"
integrity sha512-BoiLlk4vEsGBg2dAqGSJu0vJl/PgVtCYLBFJaEO8RmQzPugXewQCXZJNXTDFaRlfCs0W+quesayav4fvaif5WQ==
dependencies:
"@emotion/sheet" "0.9.3"
"@emotion/stylis" "0.8.4"
"@emotion/utils" "0.11.2"
"@emotion/weak-memoize" "0.2.4"
"@emotion/core@^10.0.9":
version "10.0.21"
resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.21.tgz#2e8398d2b92fd90d4ed6ac4d0b66214971de3458"
integrity sha512-U9zbc7ovZ2ceIwbLXYZPJy6wPgnOdTNT4jENZ31ee6v2lojetV5bTbCVk6ciT8G3wQRyVaTTfUCH9WCrMzpRIw==
dependencies:
"@babel/runtime" "^7.5.5"
"@emotion/cache" "^10.0.17"
"@emotion/css" "^10.0.14"
"@emotion/serialize" "^0.11.10"
"@emotion/sheet" "0.9.3"
"@emotion/utils" "0.11.2"
"@emotion/css@^10.0.14", "@emotion/css@^10.0.9":
version "10.0.14"
resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.14.tgz#95dacabdd0e22845d1a1b0b5968d9afa34011139"
integrity sha512-MozgPkBEWvorcdpqHZE5x1D/PLEHUitALQCQYt2wayf4UNhpgQs2tN0UwHYS4FMy5ROBH+0ALyCFVYJ/ywmwlg==
dependencies:
"@emotion/serialize" "^0.11.8"
"@emotion/utils" "0.11.2"
babel-plugin-emotion "^10.0.14"
"@emotion/hash@0.7.3":
version "0.7.3"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.7.3.tgz#a166882c81c0c6040975dd30df24fae8549bd96f"
integrity sha512-14ZVlsB9akwvydAdaEnVnvqu6J2P6ySv39hYyl/aoB6w/V+bXX0tay8cF6paqbgZsN2n5Xh15uF4pE+GvE+itw==
"@emotion/is-prop-valid@^0.8.1":
version "0.8.2"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.2.tgz#b9692080da79041683021fcc32f96b40c54c59dc"
@ -977,11 +1020,47 @@
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.2.tgz#7f4c71b7654068dfcccad29553520f984cc66b30"
integrity sha512-hnHhwQzvPCW1QjBWFyBtsETdllOM92BfrKWbUTmh9aeOlcVOiXvlPsK4104xH8NsaKfg86PTFsWkueQeUfMA/w==
"@emotion/unitless@^0.7.0":
"@emotion/memoize@0.7.3":
version "0.7.3"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.3.tgz#5b6b1c11d6a6dddf1f2fc996f74cf3b219644d78"
integrity sha512-2Md9mH6mvo+ygq1trTeVp2uzAKwE2P7In0cRpD/M9Q70aH8L+rxMLbb3JCN2JoSWsV2O+DdFjfbbXoMoLBczow==
"@emotion/serialize@^0.11.10", "@emotion/serialize@^0.11.11", "@emotion/serialize@^0.11.8":
version "0.11.11"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.11.tgz#c92a5e5b358070a7242d10508143306524e842a4"
integrity sha512-YG8wdCqoWtuoMxhHZCTA+egL0RSGdHEc+YCsmiSBPBEDNuVeMWtjEWtGrhUterSChxzwnWBXvzSxIFQI/3sHLw==
dependencies:
"@emotion/hash" "0.7.3"
"@emotion/memoize" "0.7.3"
"@emotion/unitless" "0.7.4"
"@emotion/utils" "0.11.2"
csstype "^2.5.7"
"@emotion/sheet@0.9.3":
version "0.9.3"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.3.tgz#689f135ecf87d3c650ed0c4f5ddcbe579883564a"
integrity sha512-c3Q6V7Df7jfwSq5AzQWbXHa5soeE4F5cbqi40xn0CzXxWW9/6Mxq48WJEtqfWzbZtW9odZdnRAkwCQwN12ob4A==
"@emotion/stylis@0.8.4":
version "0.8.4"
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.4.tgz#6c51afdf1dd0d73666ba09d2eb6c25c220d6fe4c"
integrity sha512-TLmkCVm8f8gH0oLv+HWKiu7e8xmBIaokhxcEKPh1m8pXiV/akCiq50FvYgOwY42rjejck8nsdQxZlXZ7pmyBUQ==
"@emotion/unitless@0.7.4", "@emotion/unitless@^0.7.0":
version "0.7.4"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.4.tgz#a87b4b04e5ae14a88d48ebef15015f6b7d1f5677"
integrity sha512-kBa+cDHOR9jpRJ+kcGMsysrls0leukrm68DmFQoMIWQcXdr2cZvyvypWuGYT7U+9kAExUE7+T7r6G3C3A6L8MQ==
"@emotion/utils@0.11.2":
version "0.11.2"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.2.tgz#713056bfdffb396b0a14f1c8f18e7b4d0d200183"
integrity sha512-UHX2XklLl3sIaP6oiMmlVzT0J+2ATTVpf0dHQVyPJHTkOITvXfaSqnRk6mdDhV9pR8T/tHc3cex78IKXssmzrA==
"@emotion/weak-memoize@0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.4.tgz#622a72bebd1e3f48d921563b4b60a762295a81fc"
integrity sha512-6PYY5DVdAY1ifaQW6XYTnOMihmBVT27elqSjEoodchsGjzYlEsTQMcEhSud99kVawatyTZRTiVkJ/c6lwbQ7nA==
"@hapi/address@2.x.x":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.1.tgz#61395b5ed94c4cb19c2dc4c85969cff3d40d583f"
@ -1590,6 +1669,13 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
"@types/react-dom@*":
version "16.9.2"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.2.tgz#90f9e6c161850be1feb31d2f448121be2a4f3b47"
integrity sha512-hgPbBoI1aTSTvZwo8HYw35UaTldW6n2ETLvHAcfcg1FaOuBV3olmyCe5eMpx2WybWMBPv0MdU2t5GOcQhP+3zA==
dependencies:
"@types/react" "*"
"@types/react-dom@^16.8.0":
version "16.9.0"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.0.tgz#ba6ddb00bf5de700b0eb91daa452081ffccbfdea"
@ -1632,6 +1718,29 @@
"@types/history" "*"
"@types/react" "*"
"@types/react-select@^3.0.5":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@types/react-select/-/react-select-3.0.5.tgz#c615c1f7a0ea98e828b469d0f5ddd39ba3f0d319"
integrity sha512-BodHwzj9WU1EWC1j8zx1iyAMDCrTURwdvMpOVvVFwDVU7fvs8Ks9fPTkUY3+BgYbpOJFr21bR3Jib/GonwanAQ==
dependencies:
"@types/react" "*"
"@types/react-dom" "*"
"@types/react-transition-group" "*"
"@types/react-tabs@^2.3.1":
version "2.3.1"
resolved "https://registry.yarnpkg.com/@types/react-tabs/-/react-tabs-2.3.1.tgz#62d3322667ac228c4d0f9f36ac9f86988c0b3971"
integrity sha512-4SZXSF8ibQAtHUqqfoYLO+8Rn4F7Hj/IX3CJf1712dWeFvRxYY1HjjwSoN4MgUB0SB0dY4GrdlZwNhhIKuRoNQ==
dependencies:
"@types/react" "*"
"@types/react-transition-group@*":
version "4.2.3"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.2.3.tgz#4924133f7268694058e415bf7aea2d4c21131470"
integrity sha512-Hk8jiuT7iLOHrcjKP/ZVSyCNXK73wJAUz60xm0mVhiRujrdiI++j4duLiL282VGxwAgxetHQFfqA29LgEeSkFA==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^16.8.2":
version "16.9.2"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.2.tgz#6d1765431a1ad1877979013906731aae373de268"
@ -1640,6 +1749,14 @@
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/redux-form@^8.1.9":
version "8.1.9"
resolved "https://registry.yarnpkg.com/@types/redux-form/-/redux-form-8.1.9.tgz#8e8800541ce191f7145b8ddf3d926ed5dfeb42d3"
integrity sha512-JdXoybK8gL4TDFzHASiUpK7YaoQ1HqBZzXkHEUUGlOR0t2i2y42EXEyWuRtMKm/8NdoO9kPANd+mFGgJ07HIFA==
dependencies:
"@types/react" "*"
redux "^3.6.0 || ^4.0.0"
"@types/resolve@0.0.8":
version "0.0.8"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194"
@ -1930,6 +2047,11 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
mime-types "~2.1.24"
negotiator "0.6.2"
ace-builds@^1.4.6:
version "1.4.7"
resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.4.7.tgz#56e5465270b6c48a48d30e70d6b8f6b92fbf2b08"
integrity sha512-gwQGVFewBopRLho08BfahyvRa9FlB43JUig5ItAKTYc9kJJsbA9QNz75p28QtQomoPQ9rJx82ymL21x4ZSZmdg==
acorn-globals@^4.1.0, acorn-globals@^4.3.0:
version "4.3.4"
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7"
@ -2195,7 +2317,7 @@ arrify@^1.0.1:
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
asap@^2.0.6, asap@~2.0.6:
asap@^2.0.6, asap@~2.0.3, asap@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
@ -2400,6 +2522,22 @@ babel-plugin-dynamic-import-node@2.3.0, babel-plugin-dynamic-import-node@^2.3.0:
dependencies:
object.assign "^4.1.0"
babel-plugin-emotion@^10.0.14:
version "10.0.21"
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.21.tgz#9ebeb12edeea3e60a5476b0e07c9868605e65968"
integrity sha512-03o+T6sfVAJhNDcSdLapgv4IeewcFPzxlvBUVdSf7o5PI57ZSxoDvmy+ZulVWSu+rOWAWkEejNcsb29TuzJHbg==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@emotion/hash" "0.7.3"
"@emotion/memoize" "0.7.3"
"@emotion/serialize" "^0.11.11"
babel-plugin-macros "^2.0.0"
babel-plugin-syntax-jsx "^6.18.0"
convert-source-map "^1.5.0"
escape-string-regexp "^1.0.5"
find-root "^1.1.0"
source-map "^0.5.7"
babel-plugin-istanbul@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz#df4ade83d897a92df069c4d9a25cf2671293c854"
@ -2417,7 +2555,7 @@ babel-plugin-jest-hoist@^24.9.0:
dependencies:
"@types/babel__traverse" "^7.0.6"
babel-plugin-macros@2.6.1:
babel-plugin-macros@2.6.1, babel-plugin-macros@^2.0.0:
version "2.6.1"
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.6.1.tgz#41f7ead616fc36f6a93180e89697f69f51671181"
integrity sha512-6W2nwiXme6j1n2erPOnmRiWfObUhWH7Qw1LMi9XZy8cj+KtESu3T6asZvtk5bMQQjX8te35o7CFueiSdL/2NmQ==
@ -2522,6 +2660,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
base16@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70"
integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=
base64-js@^1.0.2:
version "1.3.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
@ -3017,7 +3160,7 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
classnames@^2.2, classnames@^2.2.5:
classnames@^2.2, classnames@^2.2.0, classnames@^2.2.5:
version "2.2.6"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
@ -3299,7 +3442,7 @@ content-type@~1.0.4:
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
convert-source-map@1.6.0, convert-source-map@^1.1.0, convert-source-map@^1.4.0:
convert-source-map@1.6.0, convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.5.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==
@ -3351,6 +3494,11 @@ core-js@3.1.4:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.1.4.tgz#3a2837fc48e582e1ae25907afcd6cf03b0cc7a07"
integrity sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ==
core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=
core-js@^2.4.0, core-js@^2.6.5:
version "2.6.9"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
@ -3688,6 +3836,11 @@ csstype@^2.2.0:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.6.tgz#c34f8226a94bbb10c32cc0d714afdf942291fc41"
integrity sha512-RpFbQGUE74iyPgvr46U9t1xoQBM8T4BL8SxrN66Le2xYAPSaDJJKeztV3awugusb3g3G9iL8StmkBBXhcbbXhg==
csstype@^2.5.7:
version "2.6.7"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.7.tgz#20b0024c20b6718f4eda3853a1f5a1cce7f5e4a5"
integrity sha512-9Mcn9sFbGBAdmimWb2gLVDtFJzeKtDGIr76TUqmjZrw9LFXBMSU70lcs+C0/7fyCd6iBDqmksUcCOUIkisPHsQ==
currently-unhandled@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
@ -3932,6 +4085,11 @@ detect-port-alt@1.1.6:
address "^1.0.1"
debug "^2.6.0"
diff-match-patch@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.4.tgz#6ac4b55237463761c4daf0dc603eb869124744b1"
integrity sha512-Uv3SW8bmH9nAtHKaKSanOQmj2DnlH65fUpcrMdfdaOxUG02QQ4YGZ8AE7kKOMisF7UqvOlGKVYWRvezdncW9lg==
diff-sequences@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
@ -4190,6 +4348,13 @@ encodeurl@~1.0.2:
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
encoding@^0.1.11:
version "0.1.12"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=
dependencies:
iconv-lite "~0.4.13"
end-of-stream@^1.0.0, end-of-stream@^1.1.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
@ -4271,6 +4436,11 @@ es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@^0.10.51:
es6-symbol "~3.1.1"
next-tick "^1.0.0"
es6-error@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
es6-iterator@2.0.3, es6-iterator@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
@ -4808,6 +4978,26 @@ fb-watchman@^2.0.0:
dependencies:
bser "^2.0.0"
fbemitter@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-2.1.1.tgz#523e14fdaf5248805bb02f62efc33be703f51865"
integrity sha1-Uj4U/a9SSIBbsC9i78M75wP1GGU=
dependencies:
fbjs "^0.8.4"
fbjs@^0.8.0, fbjs@^0.8.4:
version "0.8.17"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=
dependencies:
core-js "^1.0.0"
isomorphic-fetch "^2.1.1"
loose-envify "^1.0.0"
object-assign "^4.1.0"
promise "^7.1.1"
setimmediate "^1.0.5"
ua-parser-js "^0.7.18"
figgy-pudding@^3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
@ -4896,6 +5086,11 @@ find-cache-dir@^2.0.0, find-cache-dir@^2.1.0:
make-dir "^2.0.0"
pkg-dir "^3.0.0"
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
find-up@3.0.0, find-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
@ -4958,6 +5153,14 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
flux@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/flux/-/flux-3.1.3.tgz#d23bed515a79a22d933ab53ab4ada19d05b2f08a"
integrity sha1-0jvtUVp5oi2TOrU6tK2hnQWy8Io=
dependencies:
fbemitter "^2.0.0"
fbjs "^0.8.0"
follow-redirects@1.5.10:
version "1.5.10"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
@ -5487,7 +5690,7 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0:
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.2.1, hoist-non-react-statics@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b"
integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==
@ -5670,7 +5873,7 @@ husky@^3.0.5:
run-node "^1.0.0"
slash "^3.0.0"
iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4:
iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
@ -5733,6 +5936,11 @@ immer@1.10.0:
resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d"
integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==
immutable@3.8.2:
version "3.8.2"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"
integrity sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=
import-cwd@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
@ -6185,7 +6393,7 @@ is-root@2.1.0:
resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c"
integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==
is-stream@^1.1.0:
is-stream@^1.0.1, is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
@ -6261,6 +6469,14 @@ isobject@^3.0.0, isobject@^3.0.1:
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
isomorphic-fetch@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=
dependencies:
node-fetch "^1.0.1"
whatwg-fetch ">=0.10.0"
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
@ -7146,11 +7362,36 @@ locate-path@^5.0.0:
dependencies:
p-locate "^4.1.0"
lodash-es@^4.17.15:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78"
integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==
lodash._reinterpolate@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
lodash.curry@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170"
integrity sha1-JI42By7ekGUB11lmIAqG2riyMXA=
lodash.flow@^3.3.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a"
integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=
lodash.get@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
lodash.memoize@4.x, lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@ -7729,6 +7970,14 @@ no-case@^2.2.0:
dependencies:
lower-case "^1.1.1"
node-fetch@^1.0.1:
version "1.7.3"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==
dependencies:
encoding "^0.1.11"
is-stream "^1.0.1"
node-forge@0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.8.2.tgz#b4bcc59fb12ce77a8825fc6a783dfe3182499c5a"
@ -9362,6 +9611,13 @@ promise@8.0.3:
dependencies:
asap "~2.0.6"
promise@^7.1.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
dependencies:
asap "~2.0.3"
prompts@^2.0.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.2.1.tgz#f901dd2a2dfee080359c0e20059b24188d75ad35"
@ -9370,7 +9626,7 @@ prompts@^2.0.1:
kleur "^3.0.3"
sisteransi "^1.0.3"
prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@^15.5.0, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -9454,6 +9710,11 @@ punycode@^2.1.0, punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
pure-color@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e"
integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=
q@^1.1.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
@ -9543,6 +9804,17 @@ re-resizable@6.1.0:
dependencies:
fast-memoize "^2.5.1"
react-ace@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-8.0.0.tgz#e6fc155ec3cf240e92bdf2e156a50458a78ed0a4"
integrity sha512-EvU14vXbZpAenb1ZVKdn8yTQs/shZ9RghFulHtt67bBXT6sjrNHcfOEXHYtSEmwMb6pQVVNNuulzzd8o+Uouig==
dependencies:
ace-builds "^1.4.6"
diff-match-patch "^1.0.4"
lodash.get "^4.4.2"
lodash.isequal "^4.5.0"
prop-types "^15.7.2"
react-app-polyfill@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-1.0.2.tgz#2a51175885c88245a2a356dc46df29f38ec9f060"
@ -9555,6 +9827,16 @@ react-app-polyfill@^1.0.2:
regenerator-runtime "0.13.3"
whatwg-fetch "3.0.0"
react-base16-styling@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c"
integrity sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw=
dependencies:
base16 "^1.0.0"
lodash.curry "^4.0.1"
lodash.flow "^3.3.0"
pure-color "^1.2.0"
react-day-picker@^7.3.2:
version "7.3.2"
resolved "https://registry.yarnpkg.com/react-day-picker/-/react-day-picker-7.3.2.tgz#b9b9b0000ba53b2c9df9bccb79664862aba6b60a"
@ -9643,11 +9925,28 @@ react-error-overlay@^6.0.1:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.1.tgz#b8d3cf9bb991c02883225c48044cb3ee20413e0f"
integrity sha512-V9yoTr6MeZXPPd4nV/05eCBvGH9cGzc52FN8fs0O0TVQ3HYYf1n7EgZVtHbldRq5xU9zEzoXIITjYNIfxDDdUw==
react-input-autosize@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.2.2.tgz#fcaa7020568ec206bc04be36f4eb68e647c4d8c2"
integrity sha512-jQJgYCA3S0j+cuOwzuCd1OjmBmnZLdqQdiLKRYrsMMzbjUrVDS5RvJUDwJqA7sKuksDuzFtm6hZGKFu7Mjk5aw==
dependencies:
prop-types "^15.5.8"
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.2, react-is@^16.8.4:
version "16.9.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.9.0.tgz#21ca9561399aad0ff1a7701c01683e8ca981edcb"
integrity sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==
react-json-view@^1.19.1:
version "1.19.1"
resolved "https://registry.yarnpkg.com/react-json-view/-/react-json-view-1.19.1.tgz#95d8e59e024f08a25e5dc8f076ae304eed97cf5c"
integrity sha512-u5e0XDLIs9Rj43vWkKvwL8G3JzvXSl6etuS5G42a8klMohZuYFQzSN6ri+/GiBptDqlrXPTdExJVU7x9rrlXhg==
dependencies:
flux "^3.1.3"
react-base16-styling "^0.6.0"
react-lifecycles-compat "^3.0.4"
react-textarea-autosize "^6.1.0"
react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
@ -9784,7 +10083,36 @@ react-scripts@^3.1.1:
optionalDependencies:
fsevents "2.0.7"
react-transition-group@^2.9.0:
react-select@^3.0.8:
version "3.0.8"
resolved "https://registry.yarnpkg.com/react-select/-/react-select-3.0.8.tgz#06ff764e29db843bcec439ef13e196865242e0c1"
integrity sha512-v9LpOhckLlRmXN5A6/mGGEft4FMrfaBFTGAnuPHcUgVId7Je42kTq9y0Z+Ye5z8/j0XDT3zUqza8gaRaI1PZIg==
dependencies:
"@babel/runtime" "^7.4.4"
"@emotion/cache" "^10.0.9"
"@emotion/core" "^10.0.9"
"@emotion/css" "^10.0.9"
memoize-one "^5.0.0"
prop-types "^15.6.0"
react-input-autosize "^2.2.2"
react-transition-group "^2.2.1"
react-tabs@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/react-tabs/-/react-tabs-3.0.0.tgz#60311a17c755eb6aa9b3310123e67db421605127"
integrity sha512-z90cDIb+5V7MzjXFHq1VLxYiMH7dDQWan7mXSw6BWQtw+9pYAnq/fEDvsPaXNyevYitvLetdW87C61uu27JVMA==
dependencies:
classnames "^2.2.0"
prop-types "^15.5.0"
react-textarea-autosize@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-6.1.0.tgz#df91387f8a8f22020b77e3833c09829d706a09a5"
integrity sha512-F6bI1dgib6fSvG8so1HuArPUv+iVEfPliuLWusLF+gAKz0FbB4jLrWUrTAeq1afnPT2c9toEZYUdz/y1uKMy4A==
dependencies:
prop-types "^15.6.0"
react-transition-group@^2.2.1, react-transition-group@^2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==
@ -9939,6 +10267,24 @@ redux-devtools@^3.5.0:
prop-types "^15.5.7"
redux-devtools-instrument "^1.9.0"
redux-form@^8.2.6:
version "8.2.6"
resolved "https://registry.yarnpkg.com/redux-form/-/redux-form-8.2.6.tgz#6840bbe9ed5b2aaef9dd82e6db3e5efcfddd69b1"
integrity sha512-krmF7wl1C753BYpEpWIVJ5NM4lUJZFZc5GFUVgblT+jprB99VVBDyBcgrZM3gWWLOcncFyNsHcKNQQcFg8Uanw==
dependencies:
"@babel/runtime" "^7.2.0"
es6-error "^4.1.1"
hoist-non-react-statics "^3.2.1"
invariant "^2.2.4"
is-promise "^2.1.0"
lodash "^4.17.15"
lodash-es "^4.17.15"
prop-types "^15.6.1"
react-is "^16.7.0"
react-lifecycles-compat "^3.0.4"
optionalDependencies:
immutable "3.8.2"
redux-saga@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-1.0.5.tgz#03317261bc5fa7ee2ecb778f4e4848f573557bbb"
@ -9946,7 +10292,7 @@ redux-saga@^1.0.0:
dependencies:
"@redux-saga/core" "^1.0.3"
"redux@>=0.10 <5", redux@^4.0.0, redux@^4.0.1, redux@^4.0.4:
"redux@>=0.10 <5", "redux@^3.6.0 || ^4.0.0", redux@^4.0.0, redux@^4.0.1, redux@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.4.tgz#4ee1aeb164b63d6a1bcc57ae4aa0b6e6fa7a3796"
integrity sha512-vKv4WdiJxOWKxK0yRoaK3Y4pxxB0ilzVx6dszU2W8wLxlb2yikRph4iV/ymtdJ6ZxpBLFbyrxklnT5yBbQSl3Q==
@ -10636,7 +10982,7 @@ set-value@^2.0.0, set-value@^2.0.1:
is-plain-object "^2.0.3"
split-string "^3.0.1"
setimmediate@^1.0.4:
setimmediate@^1.0.4, setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
@ -10845,7 +11191,7 @@ source-map@^0.4.2:
dependencies:
amdefine ">=0.0.4"
source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6:
source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
@ -11660,6 +12006,11 @@ typescript@^3.4.5, typescript@^3.6.3:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.3.tgz#fea942fabb20f7e1ca7164ff626f1a9f3f70b4da"
integrity sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==
ua-parser-js@^0.7.18:
version "0.7.20"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.20.tgz#7527178b82f6a62a0f243d1f94fd30e3e3c21098"
integrity sha512-8OaIKfzL5cpx8eCMAhhvTlft8GYF8b2eQr6JkCyVdrgjcytyOmPCXrqXFcUnhonRpLlh5yxEZVohm6mzaowUOw==
uglify-js@3.4.x:
version "3.4.10"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
@ -12101,7 +12452,7 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5:
dependencies:
iconv-lite "0.4.24"
whatwg-fetch@3.0.0:
whatwg-fetch@3.0.0, whatwg-fetch@>=0.10.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb"
integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==