Merge branch 'release' of gitlab.com:theappsmith/internal-tools-client into fix/chart-component-title-align

This commit is contained in:
vicky_primathon.in 2020-03-21 10:10:17 +05:30
commit 5cf1a0dde6
54 changed files with 637 additions and 373 deletions

View File

@ -1,11 +1,13 @@
{
"baseUrl":"http://dev.appsmith.com:3000/",
"defaultCommandTimeout": 5000,
"pageLoadTimeout": 30000,
"reporter": "mochawesome",
"reporterOptions": {
"reportDir": "results",
"overwrite": false,
"html": false,
"json": true
"html": true,
"json": false
}
}

View File

@ -0,0 +1,4 @@
{
"appname": "Test App",
}

View File

@ -1,6 +1,6 @@
{
"username": "testowner@appsmith.com",
"password": "own3rT3st1ng",
"password": "own3rT3st1ng"
}

View File

@ -0,0 +1,15 @@
var widgetsPage= require('../../locators/Widgets.json')
var loginPage= require('../../locators/LoginPage.json')
const loginData=require('../../fixtures/user.json')
var commonlocators = require('../../locators/commonlocators.json')
context('Cypress test',function() {
it('Button Widget Functionality',function(){
cy.get(widgetsPage.buttonWidget).click({ force: true })
//Checking the edit props for Button
cy.get('.CodeMirror textarea').focus().type("{meta}a").clear({ force: true }).type("{{Text4.text}}", {parseSpecialCharSequences: false})
cy.get(commonlocators.editPropCrossButton).click()
})
})

View File

@ -0,0 +1,17 @@
var widgetsPage= require('../../locators/Widgets.json')
var loginPage= require('../../locators/LoginPage.json')
const loginData=require('../../fixtures/user.json')
var commonlocators = require('../../locators/commonlocators.json')
context('Cypress test',function() {
it('Container Widget Functionality',function(){
cy.get(widgetsPage.containerWidget).first().trigger('mouseover',{force:true})
cy.get(widgetsPage.containerWidget).children(commonlocators.editIcon).first().click()
//Checking the edit props for container and also the properties of container
cy.get('.CodeMirror textarea').focus().type("{meta}a").clear({ force: true }).type('#C0C0C0')
cy.get('.CodeMirror textarea').should('have.value', '#C0C0C0')
cy.get(commonlocators.editPropCrossButton).click()
})
})

View File

@ -0,0 +1,18 @@
var widgetsPage= require('../../locators/Widgets.json')
var loginPage= require('../../locators/LoginPage.json')
const loginData=require('../../fixtures/user.json')
var commonlocators = require('../../locators/commonlocators.json')
context('Cypress test',function() {
it('Input Widget Functionality',function(){
cy.get(widgetsPage.inputWidget).first().trigger('mouseover')
cy.get(widgetsPage.inputWidget).children(commonlocators.editicon).first().click()
//Checking the edit props for container and also the properties of container
cy.get('.CodeMirror textarea').first().focus().type("{meta}a").clear({ force: true }).type('Test Input Label')
cy.get('.CodeMirror textarea').first().should('have.value', 'Test Input Label')
cy.get(commonlocators.editPropCrossButton).click()
})
})

View File

@ -0,0 +1,15 @@
var widgetsPage= require('../../locators/Widgets.json')
var loginPage= require('../../locators/LoginPage.json')
const loginData=require('../../fixtures/user.json')
var commonlocators = require('../../locators/commonlocators.json')
context('Cypress test',function() {
it('Table Widget Functionality',function(){
cy.get(widgetsPage.tableWidget).first().trigger('mouseover',{force:true})
cy.get(widgetsPage.tableWidget).children(commonlocators.editicon).first().click()
cy.get('.CodeMirror textarea').focus().type("{meta}a").clear({ force: true }).type("{{MockUsersApi.data}}",{parseSpecialCharSequences: false})
cy.get(commonlocators.editPropCrossButton).click()
})
})

View File

@ -0,0 +1,16 @@
var widgetsPage= require('../../locators/Widgets.json')
var loginPage= require('../../locators/LoginPage.json')
const loginData=require('../../fixtures/user.json')
var commonlocators = require('../../locators/commonlocators.json')
context('Cypress test',function() {
it('Text Widget Functionality',function(){
cy.get(widgetsPage.textWidget).first().trigger('mouseover')
cy.get(widgetsPage.textWidget).children(commonlocators.editIcon).first().click()
cy.get('.CodeMirror textarea').first().focus().type("{meta}a").clear({ force: true }).type('Test text')
cy.get(commonlocators.editPropCrossButton).click()
})
})

View File

@ -1,20 +1,16 @@
var loginPage= require('../../locators/LoginPage.json')
const loginData=require('../../fixtures/user.json')
var homePage = require('../../locators/HomePage.json')
var commonlocators = require('../../locators/commonlocators.json')
var widgetsPage= require('../../locators/Widgets.json')
context('Cypress test',function() {
it('Login functionality',function(){
cy.LogintoApp(loginData.username,loginData.password)
cy.get('input[type="text"]').type('Test app')
cy.wait(3000)
cy.get('.t--application-edit-link').click()
cy.wait(5000)
cy.get('.t--draggable-buttonwidget').click({ force: true })
cy.wait(2000)
cy.get('textarea').first().click({ force: true }).clear({ force: true }).type('Test', { force: true })
cy.wait(5000)
cy.get('.t--application-publish-btn').click()
cy.get(widgetsPage.buttonWidget).click({ force: true })
cy.get('.CodeMirror textarea').focus().type("{meta}a").clear({ force: true }).type('Test', { force: true })
cy.get(commonlocators.editPropCrossButton).click()
})
})

View File

@ -1,43 +0,0 @@
describe("My First Test", function() {
it("Visits the Kitchen Sink", function() {
cy.visit(
"http://localhost:3000/applications/5d807e45795dc6000482bc74/pages/5df08f966ccd2400049dde1a/edit",
);
// cy.contains("Enter your Netlify Site URL");
// cy.get();
// Main button pressed (usually the left button)
// cy.get(".TABLE_WIDGET")
// .first()
// .trigger("mousedown")
// .trigger("mousemove", { which: 1, clientX: 400, clientY: 100 })
// .trigger("mouseup");
// cy.contains("Submit").click();
// cy.contains("Barbra", { timeout: 1000000 }).click();
// // cy.contains("{{fetchUsers2}}");
// cy.get('input[value="{{fetchUsers2}}"]')
// // .first()
// .clear()
// .type(
// "{{}{{}fetchUsers2.map(user => {{}return {{}'name': user.name}})}}",
// {
// force: true,
// },
// );
// .then(function($input) {
// $input[0].setAttribute(
// "value",
// "{{fetchUsers2.map(user => {return {'name': user.name}})}}",
// );
// });
// .invoke(
// "attr",
// "value",
// "{{fetchUsers2.map(user => {return {'name': user.name}})}}",
// );
expect(true).to.eq(true);
});
});

View File

@ -0,0 +1,7 @@
{
"searchInput": "input[type='text']",
"appEditIcon": ".t--application-edit-link",
"publishButton":".t--application-publish-btn",
"publishCrossButton":"span[icon='small-cross']"
}

View File

@ -2,4 +2,4 @@
"username":"input[name='username']",
"password":"input[name='password']",
"submitBtn":"button[type='submit']"
}
}

View File

@ -0,0 +1,13 @@
{
"containerWidget":".t--draggable-containerwidget",
"inputWidget":".t--draggable-inputwidget",
"togglebutton":"input[type='checkbox']",
"inputPropsDataType":".t--property-control-datatype",
"inputdatatypedropdownicon": "./html/body/div[6]/div/div[3]/div[2]/div[2]/div[2]/span/span/div/button/span[2]",
"inputdatatypeplaceholder":".t--property-control-placeholder",
"buttonWidget":".t--draggable-buttonwidget",
"textWidget":".t--draggable-textwidget",
"tableWidget":".t--draggable-tablewidget"
}

View File

@ -0,0 +1,4 @@
{
"editIcon":".t--widget-propertypane-toggle",
"editPropCrossButton":"span[icon='cross']"
}

View File

@ -1,9 +1,31 @@
var loginPage= require('../locators/LoginPage.json')
var homePage = require('../locators/HomePage.json')
Cypress.Commands.add("LogintoApp",(uname,pword)=>{
cy.visit('/')
cy.wait(6000)
cy.get(loginPage.username).should('be.visible')
cy.get(loginPage.username).type(uname)
cy.get(loginPage.password).type(pword)
cy.get(loginPage.submitBtn).click()
})
})
Cypress.Commands.add("SearchApp",(appname)=>{
cy.get(homePage.searchInput).type(appname)
cy.get(homePage.appEditIcon).should('have.length', 1)
cy.get(homePage.appEditIcon).click()
cy.get('#loading').should('not.exist')
})
Cypress.Commands.add("PublishtheApp",()=>{
cy.wait(4000)
cy.get(homePage.publishButton).click()
cy.window()
.then((win) => {
cy.get(homePage.publishCrossButton).click()
})
})

View File

@ -13,8 +13,26 @@
// https://on.cypress.io/configuration
// ***********************************************************
const loginData=require('../fixtures/user.json')
const inputData=require('../fixtures/inputdata.json')
// Import commands.js using ES2015 syntax:
import './commands'
before(function () {
cy.LogintoApp(loginData.username,loginData.password)
cy.SearchApp(inputData.appname)
})
beforeEach(function () {
Cypress.Cookies.preserveOnce('session_id', 'remember_token')
})
// Alternatively you can use CommonJS syntax:
// require('./commands')
after(function() {
cy.PublishtheApp()
})

View File

@ -1 +1 @@
$(npm bin)/cypress run CYPRESS_BASE_URL='http://dev.appsmith.com:3000/' --spec "cypress/integration/OnBoarding/Login_spec.js"
$(npm bin)/cypress run CYPRESS_BASE_URL='http://dev.appsmith.com:3000/' --spec "cypress/integration/*/*"

View File

@ -17,6 +17,7 @@
"@sentry/browser": "^5.6.3",
"@sentry/webpack-plugin": "^1.10.0",
"@syncfusion/ej2-react-grids": "^17.4.40",
"@tinymce/tinymce-react": "^3.5.0",
"@types/chance": "^1.0.7",
"@types/fontfaceobserver": "^0.0.6",
"@types/lodash": "^4.14.120",
@ -88,6 +89,7 @@
"source-map-explorer": "^2.1.1",
"styled-components": "^4.1.3",
"tinycolor2": "^1.4.1",
"tinymce": "^5.2.0",
"toposort": "^2.0.2",
"ts-loader": "^6.0.4",
"typescript": "^3.6.3",
@ -135,7 +137,7 @@
"@typescript-eslint/eslint-plugin": "^2.0.0",
"@typescript-eslint/parser": "^2.0.0",
"babel-loader": "^8.0.6",
"cypress": "^3.7.0",
"cypress": "^4.1.0",
"cypress-multi-reporters": "^1.2.4",
"dotenv": "^8.1.0",
"eslint": "^6.4.0",
@ -159,6 +161,7 @@
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
}
}

View File

@ -3,13 +3,12 @@
<head>
<script type="text/javascript" src="/shims/realms-shim.umd.min.js"></script>
<script type="text/javascript" src="/tinymce/tinymce.min.js"></script>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="theme-color" content="#000000" />
<link href="https://fonts.googleapis.com/css?family=DM+Sans:400,500,700&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=DM+Sans:400,500,700&display=swap" rel="stylesheet" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>Appsmith</title>

File diff suppressed because one or more lines are too long

View File

@ -1,16 +1,15 @@
import { FetchPageRequest } from "api/PageApi";
import { WidgetProps, WidgetOperation } from "widgets/BaseWidget";
import { WidgetOperation, WidgetProps } from "widgets/BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
import {
ReduxActionTypes,
ReduxAction,
UpdateCanvasPayload,
SavePagePayload,
SavePageSuccessPayload,
FetchPageListPayload,
} from "constants/ReduxActionConstants";
import { ContainerWidgetProps } from "widgets/ContainerWidget";
import { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsReducer";
import { ContainerWidgetProps } from "widgets/ContainerWidget";
export const fetchPageList = (
applicationId: string,
@ -31,37 +30,30 @@ export const fetchPage = (pageId: string): ReduxAction<FetchPageRequest> => {
},
};
};
export const fetchPageSuccess = () => {
return {
type: ReduxActionTypes.FETCH_PAGE_SUCCESS,
};
};
export const addWidget = (
pageId: string,
widget: WidgetProps,
): ReduxAction<{ pageId: string; widget: WidgetProps }> => {
return {
type: ReduxActionTypes.ADD_PAGE_WIDGET,
payload: {
pageId,
widget,
},
};
export type FetchPublishedPageSuccessPayload = {
pageId: string;
dsl: ContainerWidgetProps<WidgetProps>;
pageWidgetId: string;
};
export const removeWidget = (
pageId: string,
widgetId: string,
): ReduxAction<{ pageId: string; widgetId: string }> => {
return {
type: ReduxActionTypes.REMOVE_PAGE_WIDGET,
payload: {
pageId,
widgetId,
},
};
};
export const fetchPublishedPageSuccess = (
payload: FetchPublishedPageSuccessPayload,
) => ({
type: ReduxActionTypes.FETCH_PUBLISHED_PAGE_SUCCESS,
payload,
});
export const updateCurrentPage = (id: string) => ({
type: ReduxActionTypes.UPDATE_CURRENT_PAGE,
payload: { id },
});
export const updateCanvas = (
payload: UpdateCanvasPayload,
@ -72,17 +64,6 @@ export const updateCanvas = (
};
};
export const savePage = (
pageId: string,
layoutId: string,
dsl: ContainerWidgetProps<WidgetProps>,
): ReduxAction<SavePagePayload> => {
return {
type: ReduxActionTypes.SAVE_PAGE_INIT,
payload: { pageId, layoutId, dsl },
};
};
export const savePageSuccess = (payload: SavePageSuccessPayload) => {
return {
type: ReduxActionTypes.SAVE_PAGE_SUCCESS,

View File

@ -42,7 +42,7 @@ class FilePickerComponent extends React.Component<
// plugins={["GoogleDrive", "Url", "OneDrive", "Webcam"]}
onRequestClose={this.closeModal}
uppy={this.props.uppy}
/> */}
/>**/}
</React.Fragment>
);
}

View File

@ -0,0 +1,39 @@
import React from "react";
import { Editor } from "@tinymce/tinymce-react";
require("tinymce/tinymce");
require("tinymce/themes/silver");
export interface RichtextEditorComponentProps {
defaultValue?: string;
placeholder?: string;
widgetId: string;
isDisabled?: boolean;
isVisible?: boolean;
onValueChange: (valueAsString: string) => void;
}
export const RichtextEditorComponent = (
props: RichtextEditorComponentProps,
) => {
return (
<Editor
value={props.defaultValue}
disabled={props.isDisabled}
init={{
height: "100%",
menubar: false,
branding: false,
resize: false,
plugins: [
"advlist autolink lists link image charmap print preview anchor",
"searchreplace visualblocks code fullscreen",
"insertdatetime media table paste code help",
],
toolbar:
"undo redo | formatselect | bold italic backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help",
}}
onEditorChange={(content: any) => props.onValueChange(content)}
/>
);
};
export default RichtextEditorComponent;

View File

@ -43,7 +43,17 @@ const StyledControlGroup = styled(ControlGroup)`
max-width: calc(30% - ${WIDGET_PADDING}px);
}
}
&&& {
input {
border: 1px solid #a1acb3;
border-radius: 4px;
box-shadow: none;
color: #2e3d49;
font-size: 14px;
}
}
`;
class DatePickerComponent extends React.Component<DatePickerComponentProps> {
render() {
return (
@ -97,12 +107,16 @@ class DatePickerComponent extends React.Component<DatePickerComponentProps> {
}
formatDate = (date: Date): string => {
let dateFormat = "DD/MM/YYYY";
if (this.props.enableTimePicker) {
dateFormat = "DD/MM/YYYY HH:mm";
}
if (this.props.timezone) {
return moment(date)
.tz(this.props.timezone)
.format(this.props.dateFormat);
.format(dateFormat);
}
return moment(date).format(this.props.dateFormat);
return moment(date).format(dateFormat);
};
parseDate = (dateStr: string): Date => {
@ -128,6 +142,7 @@ export interface DatePickerComponentProps extends ComponentProps {
maxDate?: Date;
timezone?: string;
datePickerType: DatePickerType;
isDisabled: boolean;
onDateSelected: (date: Date) => void;
isLoading: boolean;
}

View File

@ -14,11 +14,11 @@ class DatePickerControl extends BaseControl<DatePickerControlProps> {
showActionsBar={true}
timePickerProps={{
useAmPm: true,
value: this.props.propertyValue || new Date(),
value: new Date(this.props.propertyValue),
showArrowButtons: true,
}}
onChange={this.onDateSelected}
value={this.props.propertyValue || new Date()}
value={new Date(this.props.propertyValue)}
/>
);
}
@ -43,6 +43,7 @@ class DatePickerControl extends BaseControl<DatePickerControlProps> {
export interface DatePickerControlProps extends ControlProps {
placeholderText: string;
propertyValue: Date;
enableTimePicker: boolean;
}
export default DatePickerControl;

View File

@ -41,17 +41,22 @@ export const ControlWrapper = styled.div<ControlWrapperProps>`
export const ControlPropertyLabelContainer = styled.div`
display: flex;
align-items: center;
& > label {
label {
color: ${props => props.theme.colors.paneText};
margin-bottom: ${props => props.theme.spaces[1]}px;
font-size: ${props => props.theme.fontSizes[3]}px;
}
.underline {
color: ${props => props.theme.colors.paneTextUnderline};
}
`;
export const JSToggleButton = styled.span<{ active: boolean }>`
margin: 0 3px;
cursor: pointer;
height: 24px;
svg {
height: 24px;
rect {
fill: ${props =>
props.active
@ -243,10 +248,13 @@ export const StyledInputGroup = styled(InputGroup)`
`;
export const StyledDatePicker = styled(DateInput)`
& > input {
placeholderText: ${props => props.placeholder}
color: ${props => props.theme.colors.textOnDarkBG};
background: ${props => props.theme.colors.paneInputBG};
& {
input {
placeholderText: ${props => props.placeholder};
color: ${props => props.theme.colors.textOnDarkBG};
background: ${props => props.theme.colors.paneInputBG};
}
}
}
`;

View File

@ -10,6 +10,7 @@ export const Colors: Record<string, string> = {
MYSTIC: "#E1E8ED",
AQUA_HAZE: "#EEF2F5",
GRAY_CHATEAU: "#A2A6A8",
LIGHT_GREYISH_BLUE: "#B0BFCB",
SUNGLOW: "#FFCB33",
BLACK: "#000000",

View File

@ -332,6 +332,7 @@ export const theme: Theme = {
paneInputBG: Colors.SHARK,
paneBG: Colors.OUTER_SPACE,
paneText: Colors.GRAY_CHATEAU,
paneTextUnderline: Colors.LIGHT_GREYISH_BLUE,
paneSectionLabel: Colors.CADET_BLUE,
navBG: Colors.SHARK,
grid: Colors.GEYSER_LIGHT,

View File

@ -1,5 +1,6 @@
export type ControlType =
| "INPUT_TEXT"
| "RICH_TEXT_EDITOR"
| "ICON_PICKER"
| "SEGMENT_CONTROL"
| "SWITCH"

View File

@ -151,6 +151,7 @@ export const ReduxActionTypes: { [key: string]: string } = {
EXECUTE_API_ACTION_REQUEST: "EXECUTE_API_ACTION_REQUEST",
EXECUTE_API_ACTION_SUCCESS: "EXECUTE_API_ACTION_SUCCESS",
SET_WIDGET_DYNAMIC_PROPERTY: "SET_WIDGET_DYNAMIC_PROPERTY",
UPDATE_CURRENT_PAGE: "UPDATE_CURRENT_PAGE",
};
export type ReduxActionType = typeof ReduxActionTypes[keyof typeof ReduxActionTypes];

View File

@ -1,5 +1,6 @@
export type WidgetType =
| "TEXT_WIDGET"
| "RICH_TEXT_EDITOR_WIDGET"
| "IMAGE_WIDGET"
| "CONTAINER_WIDGET"
| "SPINNER_WIDGET"
@ -29,6 +30,7 @@ export const WidgetTypes: { [id: string]: WidgetType } = {
DROP_DOWN_WIDGET: "DROP_DOWN_WIDGET",
CHECKBOX_WIDGET: "CHECKBOX_WIDGET",
RADIO_GROUP_WIDGET: "RADIO_GROUP_WIDGET",
RICH_TEXT_EDITOR_WIDGET: "RICH_TEXT_EDITOR_WIDGET",
CHART_WIDGET: "CHART_WIDGET",
FORM_WIDGET: "FORM_WIDGET",
FORM_BUTTON_WIDGET: "FORM_BUTTON_WIDGET",

View File

@ -1,7 +1,11 @@
import { ActionData } from "reducers/entityReducers/actionsReducer";
import {
ActionData,
ActionDataState,
} from "reducers/entityReducers/actionsReducer";
import { WidgetProps } from "widgets/BaseWidget";
import { AppState } from "reducers";
import { ActionResponse } from "api/ActionAPI";
import { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer";
import { MetaState } from "reducers/entityReducers/metaReducer";
export type ActionDescription<T> = {
type: string;
@ -42,11 +46,17 @@ export type DataTree = {
[entityName: string]: DataTreeEntity;
} & { actionPaths?: string[] };
type DataTreeSeed = {
actions: ActionDataState;
widgets: CanvasWidgetsReduxState;
widgetsMeta: MetaState;
};
export class DataTreeFactory {
static create(state: AppState["entities"]): DataTree {
static create({ actions, widgets, widgetsMeta }: DataTreeSeed): DataTree {
const dataTree: DataTree = {};
dataTree.actionPaths = ["navigateTo", "navigateToUrl", "showAlert"];
state.actions.forEach(a => {
actions.forEach(a => {
dataTree[a.config.name] = {
...a,
data: a.data ? a.data.body : {},
@ -64,9 +74,9 @@ export class DataTreeFactory {
};
dataTree.actionPaths && dataTree.actionPaths.push(`${a.config.name}.run`);
});
Object.keys(state.canvasWidgets).forEach(w => {
const widget = state.canvasWidgets[w];
const widgetMetaProps = state.meta[w];
Object.keys(widgets).forEach(w => {
const widget = widgets[w];
const widgetMetaProps = widgetsMeta[w];
dataTree[widget.widgetName] = {
...widget,
...widgetMetaProps,

View File

@ -14,6 +14,7 @@ import { ReactComponent as SwitchIcon } from "assets/icons/widget/switch.svg";
import { ReactComponent as TextIcon } from "assets/icons/widget/text.svg";
import { ReactComponent as ImageIcon } from "assets/icons/widget/image.svg";
import { ReactComponent as FilePickerIcon } from "assets/icons/widget/filepicker.svg";
import { ReactComponent as RichTextEditorIcon } from "assets/icons/widget/rich-text.svg";
import { ReactComponent as ChartIcon } from "assets/icons/widget/chart.svg";
import { ReactComponent as FormIcon } from "assets/icons/widget/form.svg";
@ -72,6 +73,11 @@ export const WidgetIcons: {
<InputIcon />
</IconWrapper>
),
RICH_TEXT_EDITOR_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<RichTextEditorIcon />
</IconWrapper>
),
SWITCH_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<SwitchIcon />

View File

@ -38,7 +38,6 @@ const PageNotFound = lazy(() => import("./pages/common/PageNotFound"));
const AppViewer = lazy(() => import("./pages/AppViewer"));
const Organization = lazy(() => import("./pages/organization"));
const Users = lazy(() => import("./pages/users"));
appInitializer();
ReactDOM.render(

View File

@ -702,26 +702,19 @@ const PropertyPaneConfigResponse = {
children: [
{
id: "19.1",
propertyName: "defaultValue",
propertyName: "text",
label: "Text",
controlType: "INPUT_TEXT",
placeholderText: "Enter your HTML text",
},
{
id: "19.2",
propertyName: "placeholder",
label: "Placeholder",
controlType: "INPUT_TEXT",
placeholderText: "Enter your placeholder",
},
{
id: "19.3",
propertyName: "isVisible",
label: "Visible",
controlType: "SWITCH",
},
{
id: "19.4",
id: "19.3",
propertyName: "isDisabled",
label: "Disable",
controlType: "SWITCH",

View File

@ -19,6 +19,14 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
columns: 3,
widgetName: "Text",
},
RICH_TEXT_EDITOR_WIDGET: {
text: "This is the initial <b>content</b> of the editor",
rows: 5,
columns: 8,
isDisabled: false,
isVisible: true,
widgetName: "RichTextEditor",
},
IMAGE_WIDGET: {
defaultImage:
"https://www.cowgirlcontractcleaning.com/wp-content/uploads/sites/360/2018/05/placeholder-img-5.jpg",
@ -55,6 +63,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
},
DATE_PICKER_WIDGET: {
enableTimePicker: true,
isDisabled: false,
datePickerType: "DATE_PICKER",
rows: 1,
dateFormat: "DD/MM/YYYY",

View File

@ -79,6 +79,11 @@ const WidgetSidebarResponse: {
widgetCardName: "Button",
key: generateReactKey(),
},
{
type: "RICH_TEXT_EDITOR_WIDGET",
widgetCardName: "Rich Text Editor",
key: generateReactKey(),
},
],
["View widgets"]: [
{

View File

@ -9,7 +9,7 @@ import { ControlIcons } from "icons/ControlIcons";
import PropertyControlFactory from "utils/PropertyControlFactory";
import { WidgetProps } from "widgets/BaseWidget";
import { ControlConfig } from "reducers/entityReducers/propertyPaneConfigReducer";
import { Tooltip } from "@blueprintjs/core";
import { Tooltip, Position } from "@blueprintjs/core";
type Props = {
widgetProperties: WidgetProps;
@ -27,21 +27,30 @@ function UnderlinedLabel({
}) {
const toolTipDefined = tooltip !== undefined;
return (
<Tooltip disabled={!toolTipDefined} content={tooltip} hoverOpenDelay={200}>
<Tooltip
disabled={!toolTipDefined}
content={tooltip}
position={Position.TOP}
hoverOpenDelay={200}
>
<div
style={
toolTipDefined
? {
height: "20px",
cursor: "help",
}
: {
height: "20px",
}
}
style={{
height: "22px",
}}
>
{label}
<label
style={
toolTipDefined
? {
cursor: "help",
}
: {}
}
>
{label}
</label>
<span
className={"underline"}
style={
toolTipDefined
? {

View File

@ -64,12 +64,20 @@ const pageListReducer = createReducer(initialState, {
}
return state;
},
[ReduxActionTypes.UPDATE_CURRENT_PAGE]: (
state: PageListReduxState,
action: ReduxAction<{ id: string }>,
) => ({
...state,
currentPageId: action.payload.id,
}),
});
export interface PageListReduxState {
pages: PageListPayload;
applicationId?: string;
defaultPageId?: string;
currentPageId?: string;
}
export default pageListReducer;

View File

@ -7,6 +7,7 @@ import { TextWidgetProps } from "widgets/TextWidget";
import { ContainerWidgetProps } from "widgets/ContainerWidget";
import { ImageWidgetProps } from "widgets/ImageWidget";
import { InputWidgetProps } from "widgets/InputWidget";
import { RichTextEditorWidgetProps } from "widgets/RichTextEditorWidget";
import { SwitchWidgetProps } from "widgets/SwitchWidget";
import { SpinnerWidgetProps } from "widgets/SpinnerWidget";
import { DatePickerWidgetProps } from "../../widgets/DatePickerWidget";
@ -43,6 +44,8 @@ export interface WidgetConfigReducerState {
TEXT_WIDGET: Partial<TextWidgetProps> & WidgetConfigProps;
IMAGE_WIDGET: Partial<ImageWidgetProps> & WidgetConfigProps;
INPUT_WIDGET: Partial<InputWidgetProps> & WidgetConfigProps;
RICH_TEXT_EDITOR_WIDGET: Partial<RichTextEditorWidgetProps> &
WidgetConfigProps;
SWITCH_WIDGET: Partial<SwitchWidgetProps> & WidgetConfigProps;
CONTAINER_WIDGET: Partial<ContainerWidgetProps<WidgetProps>> &
WidgetConfigProps;

View File

@ -6,6 +6,7 @@ import {
ReduxActionTypes,
PageListPayload,
} from "constants/ReduxActionConstants";
import { FetchPublishedPageSuccessPayload } from "actions/pageActions";
const initialState: AppViewReduxState = {
isFetchingPage: false,
@ -31,16 +32,11 @@ const appViewReducer = createReducer(initialState, {
},
[ReduxActionTypes.FETCH_PUBLISHED_PAGE_SUCCESS]: (
state: AppViewReduxState,
action: ReduxAction<{
pageId: string;
dsl: ContainerWidgetProps<WidgetProps>;
pageWidgetId: string;
}>,
action: ReduxAction<FetchPublishedPageSuccessPayload>,
) => {
return {
...state,
dsl: action.payload.dsl,
currentPageId: action.payload.pageId,
isFetchingPage: false,
pageWidgetId: action.payload.pageWidgetId,
};
@ -51,7 +47,6 @@ export interface AppViewReduxState {
initialized: boolean;
dsl?: ContainerWidgetProps<WidgetProps>;
isFetchingPage: boolean;
currentPageId?: string;
currentLayoutId?: string;
pages: PageListPayload;
pageWidgetId: string;

View File

@ -89,7 +89,6 @@ const editorReducer = createReducer(initialState, {
action: ReduxAction<UpdateCanvasPayload>,
) => {
const {
currentPageId,
currentPageName,
currentLayoutId,
pageWidgetId,
@ -99,7 +98,6 @@ const editorReducer = createReducer(initialState, {
state.loadingStates.publishingError = false;
return {
...state,
currentPageId,
currentPageName,
currentLayoutId,
pageWidgetId,
@ -155,7 +153,6 @@ export interface EditorReduxState {
initialized: boolean;
dsl?: ContainerWidgetProps<WidgetProps>;
pageWidgetId?: string;
currentPageId?: string;
currentLayoutId?: string;
currentPageName?: string;
selectedWidget?: string;

View File

@ -3,9 +3,14 @@ import styled, { StyledComponent } from "styled-components";
import { useDrag } from "react-use-gesture";
import { Spring } from "react-spring/renderprops";
const ResizeWrapper = styled.div`
const ResizeWrapper = styled.div<{ pevents: boolean }>`
position: absolute;
display: block;
& {
* {
pointer-events: ${props => !props.pevents && "none"};
}
}
`;
const getSnappedValues = (
@ -72,6 +77,7 @@ type ResizableProps = {
};
export const Resizable = (props: ResizableProps) => {
const [pointerEvents, togglePointerEvents] = useState(true);
const [newDimensions, set] = useState({
width: props.componentWidth,
height: props.componentHeight,
@ -195,6 +201,7 @@ export const Resizable = (props: ResizableProps) => {
];
const onResizeStop = () => {
togglePointerEvents(true);
props.onStop(
{
width: newDimensions.width,
@ -211,12 +218,14 @@ export const Resizable = (props: ResizableProps) => {
<ResizableHandle
{...handle}
key={index}
onStart={props.onStart}
onStart={() => {
togglePointerEvents(false);
props.onStart();
}}
onStop={onResizeStop}
snapGrid={props.snapGrid}
/>
));
return (
<Spring
from={{
@ -236,7 +245,7 @@ export const Resizable = (props: ResizableProps) => {
immediate={newDimensions.reset ? true : false}
>
{_props => (
<ResizeWrapper style={_props}>
<ResizeWrapper style={_props} pevents={pointerEvents}>
{props.children}
{props.enable && renderHandles}
</ResizeWrapper>

View File

@ -14,6 +14,8 @@ import {
fetchPageSuccess,
updateWidgetNameSuccess,
deletePageSuccess,
updateCurrentPage,
fetchPublishedPageSuccess,
} from "actions/pageActions";
import PageApi, {
FetchPageResponse,
@ -125,6 +127,8 @@ export function* fetchPageSaga(
const canvasWidgetsPayload = getCanvasWidgetsPayload(fetchPageResponse);
// Update the canvas
yield put(updateCanvas(canvasWidgetsPayload));
// set current page
yield put(updateCurrentPage(pageId));
// dispatch fetch page success
yield put(fetchPageSuccess());
// Execute page load actions
@ -156,15 +160,14 @@ export function* fetchPublishedPageSaga(
if (isValidResponse) {
const canvasWidgetsPayload = getCanvasWidgetsPayload(response);
yield put(updateCanvas(canvasWidgetsPayload));
yield put({
type: ReduxActionTypes.FETCH_PUBLISHED_PAGE_SUCCESS,
payload: {
yield put(updateCurrentPage(pageId));
yield put(
fetchPublishedPageSuccess({
dsl: response.data.layouts[0].dsl,
layoutId: response.data.layouts[0].id,
pageId: request.pageId,
pageWidgetId: canvasWidgetsPayload.pageWidgetId,
},
});
}),
);
// Execute page load actions
yield put(executePageLoadActions(canvasWidgetsPayload.pageActions));
}

View File

@ -37,6 +37,7 @@ import { WidgetTypes } from "constants/WidgetConstants";
import WidgetFactory from "utils/WidgetFactory";
import { buildWidgetBlueprint } from "sagas/WidgetBlueprintSagas";
import { resetWidgetMetaProperty } from "actions/metaActions";
import ValidationFactory from "utils/ValidationFactory";
export function* addChildSaga(addChildAction: ReduxAction<WidgetAddChild>) {
try {
@ -257,16 +258,22 @@ function* setWidgetDynamicPropertySaga(
) {
const { isDynamic, propertyName, widgetId } = action.payload;
const widget: WidgetProps = yield select(getWidget, widgetId);
const propertyValue = widget[propertyName];
const dynamicProperties: Record<string, true> = {
...widget.dynamicProperties,
};
if (isDynamic) {
dynamicProperties[propertyName] = true;
const value = convertToString(widget[propertyName]);
const value = convertToString(propertyValue);
yield put(updateWidgetProperty(widgetId, propertyName, value));
} else {
delete dynamicProperties[propertyName];
yield put(updateWidgetProperty(widgetId, propertyName, undefined));
const { parsed } = ValidationFactory.validateWidgetProperty(
widget.type,
propertyName,
propertyValue,
);
yield put(updateWidgetProperty(widgetId, propertyName, parsed));
}
yield put(
updateWidgetProperty(widgetId, "dynamicProperties", dynamicProperties),

View File

@ -9,6 +9,8 @@ export const getWidgets = (
return state.entities.canvasWidgets;
};
export const getWidgetsMeta = (state: AppState) => state.entities.meta;
export const getWidget = (state: AppState, widgetId: string): WidgetProps => {
return state.entities.canvasWidgets[widgetId];
};
@ -16,13 +18,10 @@ export const getWidget = (state: AppState, widgetId: string): WidgetProps => {
export const getEditorConfigs = (
state: AppState,
): { pageId: string; layoutId: string } | undefined => {
const { currentLayoutId, currentPageId } = state.ui.editor;
return currentLayoutId && currentPageId
? {
pageId: currentPageId,
layoutId: currentLayoutId,
}
: undefined;
const pageId = state.entities.pageList.currentPageId;
const layoutId = state.ui.editor.currentLayoutId;
if (!pageId || !layoutId) return undefined;
return { pageId, layoutId };
};
export const getDefaultWidgetConfig = (

View File

@ -32,6 +32,6 @@ export const getIsInitialized = createSelector(
);
export const getCurrentDSLPageId = createSelector(
getAppViewState,
(view: AppViewReduxState) => view.currentPageId,
getPageListState,
(pageList: PageListReduxState) => pageList.currentPageId,
);

View File

@ -1,14 +1,20 @@
import { AppState } from "reducers";
import { createSelector } from "reselect";
import { getActions } from "./entitiesSelector";
import { getActionsForCurrentPage } from "./entitiesSelector";
import { ActionDataState } from "reducers/entityReducers/actionsReducer";
import { getEvaluatedDataTree } from "utils/DynamicBindingUtils";
import { extraLibraries } from "jsExecution/JSExecutionManagerSingleton";
import { DataTree, DataTreeFactory } from "entities/DataTree/dataTreeFactory";
import _ from "lodash";
import { getWidgets, getWidgetsMeta } from "sagas/selectors";
export const getUnevaluatedDataTree = (state: AppState): DataTree =>
DataTreeFactory.create(state.entities);
export const getUnevaluatedDataTree = createSelector(
getActionsForCurrentPage,
getWidgets,
getWidgetsMeta,
(actions, widgets, widgetsMeta) => {
return DataTreeFactory.create({ actions, widgets, widgetsMeta });
},
);
export const evaluateDataTree = createSelector(
getUnevaluatedDataTree,
@ -21,7 +27,7 @@ export const evaluateDataTree = createSelector(
// there isn't a response already
export const getDataTreeForAutocomplete = createSelector(
evaluateDataTree,
getActions,
getActionsForCurrentPage,
(tree: DataTree, actions: ActionDataState) => {
const cachedResponses: Record<string, any> = {};
if (actions && actions.length) {

View File

@ -59,8 +59,8 @@ export const getPageList = createSelector(
);
export const getCurrentPageId = createSelector(
getEditorState,
(editor: EditorReduxState) => editor.currentPageId,
getPageListState,
(pageList: PageListReduxState) => pageList.currentPageId,
);
export const getCurrentLayoutId = createSelector(

View File

@ -1,6 +1,7 @@
import { AppState } from "reducers";
import { ActionDataState } from "reducers/entityReducers/actionsReducer";
import { ActionResponse } from "api/ActionAPI";
import { createSelector } from "reselect";
export const getEntities = (state: AppState): AppState["entities"] =>
state.entities;
@ -19,6 +20,18 @@ export const getPluginIdOfName = (
export const getActions = (state: AppState): ActionDataState =>
state.entities.actions;
const getCurrentPageId = (state: AppState) =>
state.entities.pageList.currentPageId;
export const getActionsForCurrentPage = createSelector(
getCurrentPageId,
getActions,
(pageId, actions) => {
if (!pageId) return [];
return actions.filter(a => a.config.pageId === pageId);
},
);
export const getActionResponses = (
state: AppState,
): Record<string, ActionResponse | undefined> => {

View File

@ -13,6 +13,9 @@ import ButtonWidget, { ButtonWidgetProps } from "widgets/ButtonWidget";
import DropdownWidget, { DropdownWidgetProps } from "widgets/DropdownWidget";
import ImageWidget, { ImageWidgetProps } from "widgets/ImageWidget";
import TableWidget, { TableWidgetProps } from "widgets/TableWidget";
import RichTextEditorWidget, {
RichTextEditorWidgetProps,
} from "widgets/RichTextEditorWidget";
import ChartWidget, { ChartWidgetProps } from "widgets/ChartWidget";
import FilePickerWidget, {
@ -170,6 +173,17 @@ class WidgetBuilderRegistry {
DatePickerWidget.getDerivedPropertiesMap(),
DatePickerWidget.getTriggerPropertyMap(),
);
WidgetFactory.registerWidgetBuilder(
"RICH_TEXT_EDITOR_WIDGET",
{
buildWidget(widgetData: RichTextEditorWidgetProps): JSX.Element {
return <RichTextEditorWidget {...widgetData} />;
},
},
RichTextEditorWidget.getPropertyValidationMap(),
RichTextEditorWidget.getDerivedPropertiesMap(),
RichTextEditorWidget.getTriggerPropertyMap(),
);
WidgetFactory.registerWidgetBuilder(
"CHART_WIDGET",
{

View File

@ -47,6 +47,7 @@ class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
if (
(this.props.selectedDate !== prevProps.selectedDate &&
this.props.selectedDate === undefined) ||
prevProps.defaultDate === undefined ||
this.props.defaultDate.toDateString() !==
prevProps.defaultDate.toDateString()
) {
@ -63,6 +64,7 @@ class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
widgetId={this.props.widgetId}
timezone={this.props.timezone}
enableTimePicker={this.props.enableTimePicker}
isDisabled={this.props.isDisabled}
datePickerType={"DATE_PICKER"}
onDateSelected={this.onDateSelected}
selectedDate={this.props.selectedDate}
@ -95,6 +97,7 @@ export interface DatePickerWidgetProps extends WidgetProps {
selectedDate: Date;
timezone?: string;
enableTimePicker: boolean;
isDisabled: boolean;
dateFormat: string;
label: string;
datePickerType: DatePickerType;

View File

@ -0,0 +1,90 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
import { EventType } from "constants/ActionConstants";
import RichtextEditorComponent from "components/designSystems/appsmith/RichTextEditorComponent";
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
import { TriggerPropertiesMap } from "utils/WidgetFactory";
class RichTextEditorWidget extends BaseWidget<
RichTextEditorWidgetProps,
WidgetState
> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
placeholder: VALIDATION_TYPES.TEXT,
defaultValue: VALIDATION_TYPES.TEXT,
isDisabled: VALIDATION_TYPES.BOOLEAN,
isVisible: VALIDATION_TYPES.BOOLEAN,
};
}
static getTriggerPropertyMap(): TriggerPropertiesMap {
return {
onTextChange: true,
};
}
componentDidMount() {
super.componentDidMount();
if (this.props.text) {
this.updateWidgetMetaProperty("value", this.props.text);
}
}
componentDidUpdate(prevProps: RichTextEditorWidgetProps) {
super.componentDidUpdate(prevProps);
if (this.props.text) {
if (this.props.text !== prevProps.text) {
this.updateWidgetMetaProperty("value", this.props.text);
}
}
}
onValueChange = (value: string) => {
this.updateWidgetMetaProperty("value", value);
if (this.props.onTextChange) {
super.executeAction({
dynamicString: this.props.onTextChange,
event: {
type: EventType.ON_TEXT_CHANGE,
},
});
}
};
getPageView() {
return (
<RichtextEditorComponent
onValueChange={this.onValueChange}
defaultValue={this.props.value}
widgetId={this.props.widgetId}
placeholder={this.props.placeholder}
key={this.props.widgetId}
isDisabled={this.props.isDisabled}
isVisible={this.props.isVisible}
/>
);
}
getWidgetType(): WidgetType {
return "RICH_TEXT_EDITOR_WIDGET";
}
}
export interface InputValidator {
validationRegex: string;
errorMessage: string;
}
export interface RichTextEditorWidgetProps extends WidgetProps {
text?: string;
value?: string;
placeholder?: string;
onTextChange?: string;
isDisabled?: boolean;
isVisible?: boolean;
}
export default RichTextEditorWidget;

View File

@ -2149,6 +2149,12 @@
"@syncfusion/ej2-base" "~17.4.47"
"@syncfusion/ej2-popups" "~17.4.47"
"@tinymce/tinymce-react@^3.5.0":
version "3.5.0"
resolved "https://registry.yarnpkg.com/@tinymce/tinymce-react/-/tinymce-react-3.5.0.tgz#5017be56aeab1077f09d3f74a386883e5524a33f"
dependencies:
prop-types "^15.6.2"
"@types/anymatch@*":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
@ -3021,10 +3027,6 @@ ansi-colors@^3.0.0:
version "3.2.4"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
ansi-escapes@^1.0.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
ansi-escapes@^3.0.0, ansi-escapes@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
@ -3285,18 +3287,17 @@ async-limiter@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
async@2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
dependencies:
lodash "^4.17.10"
async@^2.1.4, async@^2.6.2:
version "2.6.3"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
dependencies:
lodash "^4.17.14"
async@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@ -3766,11 +3767,7 @@ block-stream@*:
dependencies:
inherits "~2.0.0"
bluebird@3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c"
bluebird@^3.3.5, bluebird@^3.5.5:
bluebird@3.7.2, bluebird@^3.3.5, bluebird@^3.5.5:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
@ -4039,11 +4036,10 @@ cache-base@^1.0.1:
union-value "^1.0.0"
unset-value "^1.0.0"
cachedir@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-1.3.0.tgz#5e01928bf2d95b5edd94b0942188246740e0dbc4"
dependencies:
os-homedir "^1.0.1"
cachedir@2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8"
integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==
call-me-maybe@^1.0.1:
version "1.0.1"
@ -4268,10 +4264,6 @@ chrome-trace-event@^1.0.2:
dependencies:
tslib "^1.9.0"
ci-info@^1.5.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
ci-info@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
@ -4328,10 +4320,6 @@ cli-cursor@^3.1.0:
dependencies:
restore-cursor "^3.1.0"
cli-spinners@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c"
cli-table3@0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202"
@ -4501,9 +4489,10 @@ comma-separated-tokens@^1.0.0:
version "1.0.8"
resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea"
commander@2.15.1:
version "2.15.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
commander@4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.0.tgz#545983a0603fe425bc672d66c9e3c89c42121a83"
integrity sha512-NIQrwvv9V39FHgGFm36+U9SMQzbiHvU79k+iADraJTpmrFFfx7Ds0IvDoAdZsDrknlkRk14OYoWXb57uTh7/sw==
commander@^2.11.0, commander@^2.19.0, commander@^2.20.0:
version "2.20.3"
@ -5003,41 +4992,44 @@ cypress-multi-reporters@^1.2.4:
debug "^4.1.1"
lodash "^4.17.11"
cypress@^3.7.0:
version "3.8.3"
resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.8.3.tgz#e921f5482f1cbe5814891c878f26e704bbffd8f4"
cypress@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/cypress/-/cypress-4.1.0.tgz#295f115d2e8a08fff2760ab49d94d876f5877aee"
integrity sha512-FFV8pS9iuriSX4M9rna6awJUhiqozZD1D5z5BprCUJoho1ctbcgpkEUIUnqxli2OwjQqVz07egO+iqoGL+tw7g==
dependencies:
"@cypress/listr-verbose-renderer" "0.4.1"
"@cypress/xvfb" "1.2.4"
"@types/sizzle" "2.3.2"
arch "2.1.1"
bluebird "3.5.0"
cachedir "1.3.0"
bluebird "3.7.2"
cachedir "2.3.0"
chalk "2.4.2"
check-more-types "2.24.0"
commander "2.15.1"
commander "4.1.0"
common-tags "1.8.0"
debug "3.2.6"
debug "4.1.1"
eventemitter2 "4.1.2"
execa "0.10.0"
execa "1.0.0"
executable "4.1.1"
extract-zip "1.6.7"
fs-extra "5.0.0"
getos "3.1.1"
is-ci "1.2.1"
fs-extra "8.1.0"
getos "3.1.4"
is-ci "2.0.0"
is-installed-globally "0.1.0"
lazy-ass "1.6.0"
listr "0.12.0"
listr "0.14.3"
lodash "4.17.15"
log-symbols "2.2.0"
log-symbols "3.0.0"
minimist "1.2.0"
moment "2.24.0"
ramda "0.24.1"
ospath "1.2.2"
pretty-bytes "5.3.0"
ramda "0.26.1"
request "2.88.0"
request-progress "3.0.0"
supports-color "5.5.0"
supports-color "7.1.0"
tmp "0.1.0"
untildify "3.0.3"
untildify "4.0.0"
url "0.11.0"
yauzl "2.10.0"
@ -5090,7 +5082,7 @@ debug@3.2.6, debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5:
dependencies:
ms "^2.1.1"
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
debug@4, debug@4.1.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
dependencies:
@ -5905,19 +5897,7 @@ exec-sh@^0.3.2:
version "0.3.4"
resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5"
execa@0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50"
dependencies:
cross-spawn "^6.0.0"
get-stream "^3.0.0"
is-stream "^1.1.0"
npm-run-path "^2.0.0"
p-finally "^1.0.0"
signal-exit "^3.0.0"
strip-eof "^1.0.0"
execa@^1.0.0:
execa@1.0.0, execa@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
dependencies:
@ -6434,11 +6414,11 @@ fs-copy-file-sync@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/fs-copy-file-sync/-/fs-copy-file-sync-1.1.1.tgz#11bf32c096c10d126e5f6b36d06eece776062918"
fs-extra@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd"
fs-extra@8.1.0, fs-extra@^8.0.1, fs-extra@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
dependencies:
graceful-fs "^4.1.2"
graceful-fs "^4.2.0"
jsonfile "^4.0.0"
universalify "^0.1.0"
@ -6468,14 +6448,6 @@ fs-extra@^7.0.0:
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-extra@^8.0.1, fs-extra@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
dependencies:
graceful-fs "^4.2.0"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-minipass@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
@ -6608,10 +6580,6 @@ get-stdin@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6"
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
get-stream@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
@ -6628,11 +6596,12 @@ get-value@^2.0.3, get-value@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
getos@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/getos/-/getos-3.1.1.tgz#967a813cceafee0156b0483f7cffa5b3eff029c5"
getos@3.1.4:
version "3.1.4"
resolved "https://registry.yarnpkg.com/getos/-/getos-3.1.4.tgz#29cdf240ed10a70c049add7b6f8cb08c81876faf"
integrity sha512-UORPzguEB/7UG5hqiZai8f0vQ7hzynMQyJLxStoQ8dPGAcmgsfXOPA4iE/fGtweHYkK+z4zc9V0g+CIFRf5HYw==
dependencies:
async "2.6.1"
async "^3.1.0"
getpass@^0.1.1:
version "0.1.7"
@ -7484,13 +7453,7 @@ is-callable@^1.1.4, is-callable@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab"
is-ci@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
dependencies:
ci-info "^1.5.0"
is-ci@^2.0.0:
is-ci@2.0.0, is-ci@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
dependencies:
@ -8574,19 +8537,6 @@ listr-silent-renderer@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e"
listr-update-renderer@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.2.0.tgz#ca80e1779b4e70266807e8eed1ad6abe398550f9"
dependencies:
chalk "^1.1.3"
cli-truncate "^0.2.1"
elegant-spinner "^1.0.1"
figures "^1.7.0"
indent-string "^3.0.0"
log-symbols "^1.0.2"
log-update "^1.0.2"
strip-ansi "^3.0.1"
listr-update-renderer@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz#4ea8368548a7b8aecb7e06d8c95cb45ae2ede6a2"
@ -8600,15 +8550,6 @@ listr-update-renderer@^0.5.0:
log-update "^2.3.0"
strip-ansi "^3.0.1"
listr-verbose-renderer@^0.4.0:
version "0.4.1"
resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#8206f4cf6d52ddc5827e5fd14989e0e965933a35"
dependencies:
chalk "^1.1.3"
cli-cursor "^1.0.2"
date-fns "^1.27.2"
figures "^1.7.0"
listr-verbose-renderer@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz#f1132167535ea4c1261102b9f28dac7cba1e03db"
@ -8618,28 +8559,7 @@ listr-verbose-renderer@^0.5.0:
date-fns "^1.27.2"
figures "^2.0.0"
listr@0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/listr/-/listr-0.12.0.tgz#6bce2c0f5603fa49580ea17cd6a00cc0e5fa451a"
dependencies:
chalk "^1.1.3"
cli-truncate "^0.2.1"
figures "^1.7.0"
indent-string "^2.1.0"
is-promise "^2.1.0"
is-stream "^1.1.0"
listr-silent-renderer "^1.1.1"
listr-update-renderer "^0.2.0"
listr-verbose-renderer "^0.4.0"
log-symbols "^1.0.2"
log-update "^1.0.2"
ora "^0.2.3"
p-map "^1.1.1"
rxjs "^5.0.0-beta.11"
stream-to-observable "^0.1.0"
strip-ansi "^3.0.1"
listr@^0.14.3:
listr@0.14.3, listr@^0.14.3:
version "0.14.3"
resolved "https://registry.yarnpkg.com/listr/-/listr-0.14.3.tgz#2fea909604e434be464c50bddba0d496928fa586"
dependencies:
@ -8791,16 +8711,10 @@ lodash.uniq@4.5.0, lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
lodash@4.17.15, "lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.0.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@~4.17.10:
lodash@4.17.15, "lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@~4.17.10:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
log-symbols@2.2.0, log-symbols@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
dependencies:
chalk "^2.0.1"
log-symbols@3.0.0, log-symbols@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4"
@ -8813,12 +8727,11 @@ log-symbols@^1.0.2:
dependencies:
chalk "^1.0.0"
log-update@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/log-update/-/log-update-1.0.2.tgz#19929f64c4093d2d2e7075a1dad8af59c296b8d1"
log-symbols@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
dependencies:
ansi-escapes "^1.0.0"
cli-cursor "^1.0.2"
chalk "^2.0.1"
log-update@^2.3.0:
version "2.3.0"
@ -9822,15 +9735,6 @@ optionator@^0.8.1, optionator@^0.8.3:
type-check "~0.3.2"
word-wrap "~1.2.3"
ora@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4"
dependencies:
chalk "^1.1.1"
cli-cursor "^1.0.2"
cli-spinners "^0.1.2"
object-assign "^4.0.1"
original@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f"
@ -9841,7 +9745,7 @@ os-browserify@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
os-homedir@^1.0.0, os-homedir@^1.0.1:
os-homedir@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
@ -9870,6 +9774,11 @@ osenv@0:
os-homedir "^1.0.0"
os-tmpdir "^1.0.0"
ospath@1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b"
integrity sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=
p-defer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
@ -9922,10 +9831,6 @@ p-locate@^4.1.0:
dependencies:
p-limit "^2.2.0"
p-map@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
p-map@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
@ -10874,7 +10779,7 @@ prettier@^1.16.4, prettier@^1.18.2:
version "1.19.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
pretty-bytes@^5.1.0:
pretty-bytes@5.3.0, pretty-bytes@^5.1.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2"
@ -11195,9 +11100,10 @@ raf@^3.4.1:
dependencies:
performance-now "^2.1.0"
ramda@0.24.1:
version "0.24.1"
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.24.1.tgz#c3b7755197f35b8dc3502228262c4c91ddb6b857"
ramda@0.26.1:
version "0.26.1"
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06"
integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==
ramda@^0.21.0:
version "0.21.0"
@ -12352,12 +12258,6 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
rxjs@^5.0.0-beta.11:
version "5.5.12"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.12.tgz#6fa61b8a77c3d793dbaf270bee2f43f652d741cc"
dependencies:
symbol-observable "1.0.1"
rxjs@^6.3.3, rxjs@^6.4.0, rxjs@^6.5.3:
version "6.5.4"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c"
@ -12986,10 +12886,6 @@ stream-shift@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
stream-to-observable@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/stream-to-observable/-/stream-to-observable-0.1.0.tgz#45bf1d9f2d7dc09bed81f1c307c430e68b84cffe"
strict-uri-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
@ -13228,34 +13124,35 @@ stylis@^3.5.0:
version "3.5.4"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe"
supports-color@5.5.0, supports-color@^5.3.0, supports-color@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
dependencies:
has-flag "^3.0.0"
supports-color@6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a"
dependencies:
has-flag "^3.0.0"
supports-color@7.1.0, supports-color@^7.0.0, supports-color@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
dependencies:
has-flag "^4.0.0"
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
supports-color@^5.3.0, supports-color@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
dependencies:
has-flag "^3.0.0"
supports-color@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3"
dependencies:
has-flag "^3.0.0"
supports-color@^7.0.0, supports-color@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
dependencies:
has-flag "^4.0.0"
svg-parser@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.3.tgz#a38f2e4e5442986f7ecb554c11f1411cfcf8c2b9"
@ -13278,10 +13175,6 @@ svgo@^1.0.0, svgo@^1.2.2:
unquote "~1.1.1"
util.promisify "~1.0.0"
symbol-observable@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4"
symbol-observable@^1.0.2, symbol-observable@^1.1.0, symbol-observable@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
@ -13459,6 +13352,10 @@ tinycolor2@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
tinymce@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-5.2.0.tgz#e838640f61c8a936317bc27a5d2e16c297df3418"
tmp@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877"
@ -13858,9 +13755,10 @@ unset-value@^1.0.0:
has-value "^0.3.1"
isobject "^3.0.0"
untildify@3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.3.tgz#1e7b42b140bcfd922b22e70ca1265bfe3634c7c9"
untildify@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
upath@^1.1.1:
version "1.2.0"