Merge branch 'release'
This commit is contained in:
commit
bd11fdef91
|
|
@ -205,7 +205,16 @@
|
||||||
"avatar_url": "https://avatars0.githubusercontent.com/u/25309929?v=4",
|
"avatar_url": "https://avatars0.githubusercontent.com/u/25309929?v=4",
|
||||||
"profile": "https://github.com/A-Scratchy",
|
"profile": "https://github.com/A-Scratchy",
|
||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "sumanthyedoti",
|
||||||
|
"name": "Sumanth Yedoti",
|
||||||
|
"avatar_url": "https://avatars3.githubusercontent.com/u/30371888?v=4",
|
||||||
|
"profile": "https://github.com/sumanthyedoti",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,9 @@ The Appsmith platform is available under the [Apache License 2.0](https://www.ap
|
||||||
<td align="center"><a href="http://prashantchaubey.com"><img src="https://avatars3.githubusercontent.com/u/14848874?v=4" width="100px;" alt=""/><br /><sub><b>Prashant Chaubey</b></sub></a><br /><a href="https://github.com/appsmithorg/appsmith/commits?author=pc9795" title="Code">💻</a></td>
|
<td align="center"><a href="http://prashantchaubey.com"><img src="https://avatars3.githubusercontent.com/u/14848874?v=4" width="100px;" alt=""/><br /><sub><b>Prashant Chaubey</b></sub></a><br /><a href="https://github.com/appsmithorg/appsmith/commits?author=pc9795" title="Code">💻</a></td>
|
||||||
<td align="center"><a href="https://github.com/A-Scratchy"><img src="https://avatars0.githubusercontent.com/u/25309929?v=4" width="100px;" alt=""/><br /><sub><b>Adam</b></sub></a><br /><a href="https://github.com/appsmithorg/appsmith/commits?author=A-Scratchy" title="Code">💻</a></td>
|
<td align="center"><a href="https://github.com/A-Scratchy"><img src="https://avatars0.githubusercontent.com/u/25309929?v=4" width="100px;" alt=""/><br /><sub><b>Adam</b></sub></a><br /><a href="https://github.com/appsmithorg/appsmith/commits?author=A-Scratchy" title="Code">💻</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://github.com/sumanthyedoti"><img src="https://avatars3.githubusercontent.com/u/30371888?v=4" width="100px;" alt=""/><br /><sub><b>Sumanth Yedoti</b></sub></a><br /><a href="#tool-sumanthyedoti" title="Tools">🔧</a> <a href="https://github.com/appsmithorg/appsmith/commits?author=sumanthyedoti" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<!-- markdownlint-enable -->
|
<!-- markdownlint-enable -->
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
const dsl = require("../../../fixtures/inputdsl.json");
|
||||||
|
const widgetsPage = require("../../../locators/Widgets.json");
|
||||||
|
const dynamicInput = require("../../../locators/DynamicInput.json");
|
||||||
|
|
||||||
|
describe("Binding prompt", function() {
|
||||||
|
before(() => {
|
||||||
|
cy.addDsl(dsl);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Show binding prompt when there are no bindings in the editor", () => {
|
||||||
|
cy.openPropertyPane("inputwidget");
|
||||||
|
cy.get(widgetsPage.defaultInput).type(" ");
|
||||||
|
cy.get(dynamicInput.bindingPrompt).should("be.visible");
|
||||||
|
|
||||||
|
cy.get(widgetsPage.defaultInput).type("{{");
|
||||||
|
cy.get(dynamicInput.bindingPrompt).should("not.be.visible");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -48,6 +48,9 @@ describe("Video Widget Functionality", function() {
|
||||||
|
|
||||||
it("Update video url and check play and pause functionality validation", function() {
|
it("Update video url and check play and pause functionality validation", function() {
|
||||||
cy.testCodeMirror(testdata.videoUrl);
|
cy.testCodeMirror(testdata.videoUrl);
|
||||||
|
cy.get(".CodeMirror textarea")
|
||||||
|
.first()
|
||||||
|
.blur();
|
||||||
cy.get(widgetsPage.autoPlay).click();
|
cy.get(widgetsPage.autoPlay).click();
|
||||||
cy.wait("@updateLayout").should(
|
cy.wait("@updateLayout").should(
|
||||||
"have.nested.property",
|
"have.nested.property",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"input": ".CodeMirror textarea",
|
"input": ".CodeMirror textarea",
|
||||||
"hints": "ul.CodeMirror-hints",
|
"hints": "ul.CodeMirror-hints",
|
||||||
"evaluatedValue": ".t--CodeEditor-evaluatedValue"
|
"evaluatedValue": ".t--CodeEditor-evaluatedValue",
|
||||||
|
"bindingPrompt": ".t--no-binding-prompt"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
import React, { useRef } from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { Colors } from "constants/Colors";
|
||||||
|
|
||||||
|
const Wrapper = styled.span<{ visible: boolean; bottomOffset: number }>`
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: ${Colors.GRAY_CHATEAU};
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: ${Colors.BLUE_CHARCOAL};
|
||||||
|
position: absolute;
|
||||||
|
bottom: ${props => -props.bottomOffset}px;
|
||||||
|
width: 100%;
|
||||||
|
line-height: 13px;
|
||||||
|
visibility: ${props => (props.visible ? "visible" : "hidden")};
|
||||||
|
z-index: 1;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const CurlyBraces = styled.span`
|
||||||
|
color: white;
|
||||||
|
background-color: #f3672a;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 2px;
|
||||||
|
margin: 0px 2px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const BindingPrompt = (props: { isOpen: boolean }): JSX.Element => {
|
||||||
|
const promptRef = useRef<HTMLDivElement>(null);
|
||||||
|
let bottomOffset = 30;
|
||||||
|
|
||||||
|
if (promptRef.current) {
|
||||||
|
const boundingRect = promptRef.current.getBoundingClientRect();
|
||||||
|
bottomOffset = boundingRect.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper
|
||||||
|
className="t--no-binding-prompt"
|
||||||
|
ref={promptRef}
|
||||||
|
visible={props.isOpen}
|
||||||
|
bottomOffset={bottomOffset}
|
||||||
|
>
|
||||||
|
Type <CurlyBraces>{"{{"}</CurlyBraces> to see a list of variables
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BindingPrompt;
|
||||||
|
|
@ -36,6 +36,7 @@ import {
|
||||||
import { bindingMarker } from "components/editorComponents/CodeEditor/markHelpers";
|
import { bindingMarker } from "components/editorComponents/CodeEditor/markHelpers";
|
||||||
import { bindingHint } from "components/editorComponents/CodeEditor/hintHelpers";
|
import { bindingHint } from "components/editorComponents/CodeEditor/hintHelpers";
|
||||||
import { retryPromise } from "utils/AppsmithUtils";
|
import { retryPromise } from "utils/AppsmithUtils";
|
||||||
|
import BindingPrompt from "./BindingPrompt";
|
||||||
|
|
||||||
const LightningMenu = lazy(() =>
|
const LightningMenu = lazy(() =>
|
||||||
retryPromise(() => import("components/editorComponents/LightningMenu")),
|
retryPromise(() => import("components/editorComponents/LightningMenu")),
|
||||||
|
|
@ -91,9 +92,7 @@ class CodeEditor extends Component<Props, State> {
|
||||||
};
|
};
|
||||||
|
|
||||||
textArea = React.createRef<HTMLTextAreaElement>();
|
textArea = React.createRef<HTMLTextAreaElement>();
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
editor!: CodeMirror.Editor;
|
||||||
// @ts-ignore
|
|
||||||
editor: CodeMirror.Editor;
|
|
||||||
hinters: Hinter[] = [];
|
hinters: Hinter[] = [];
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
|
|
@ -272,6 +271,7 @@ class CodeEditor extends Component<Props, State> {
|
||||||
theme,
|
theme,
|
||||||
disabled,
|
disabled,
|
||||||
className,
|
className,
|
||||||
|
placeholder,
|
||||||
showLightningMenu,
|
showLightningMenu,
|
||||||
dataTreePath,
|
dataTreePath,
|
||||||
dynamicData,
|
dynamicData,
|
||||||
|
|
@ -291,6 +291,10 @@ class CodeEditor extends Component<Props, State> {
|
||||||
("evaluatedValue" in this.props ||
|
("evaluatedValue" in this.props ||
|
||||||
("dataTreePath" in this.props && !!this.props.dataTreePath));
|
("dataTreePath" in this.props && !!this.props.dataTreePath));
|
||||||
|
|
||||||
|
const showBindingPrompt =
|
||||||
|
(!this.props.input.value?.includes("{{") || !this.props.input.value) &&
|
||||||
|
showEvaluatedValue;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DynamicAutocompleteInputWrapper
|
<DynamicAutocompleteInputWrapper
|
||||||
theme={this.props.theme}
|
theme={this.props.theme}
|
||||||
|
|
@ -346,12 +350,11 @@ class CodeEditor extends Component<Props, State> {
|
||||||
className="leftImageStyles"
|
className="leftImageStyles"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
ref={this.textArea}
|
ref={this.textArea}
|
||||||
{..._.omit(this.props.input, ["onChange", "value"])}
|
{..._.omit(this.props.input, ["onChange", "value"])}
|
||||||
defaultValue={input.value}
|
defaultValue={input.value}
|
||||||
placeholder={this.props.placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
{this.props.link && (
|
{this.props.link && (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
|
@ -368,6 +371,7 @@ class CodeEditor extends Component<Props, State> {
|
||||||
{this.props.rightIcon && (
|
{this.props.rightIcon && (
|
||||||
<IconContainer>{this.props.rightIcon}</IconContainer>
|
<IconContainer>{this.props.rightIcon}</IconContainer>
|
||||||
)}
|
)}
|
||||||
|
<BindingPrompt isOpen={showBindingPrompt} />
|
||||||
</EditorWrapper>
|
</EditorWrapper>
|
||||||
</EvaluatedValuePopup>
|
</EvaluatedValuePopup>
|
||||||
</DynamicAutocompleteInputWrapper>
|
</DynamicAutocompleteInputWrapper>
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ export const EditorWrapper = styled.div<{
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
`
|
`
|
||||||
: `z-index: 0; position: relative;`}
|
: `position: relative;`}
|
||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
height: ${props => props.height || "auto"};
|
height: ${props => props.height || "auto"};
|
||||||
background-color: ${props =>
|
background-color: ${props =>
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,5 @@ export default styled.div`
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
min-height: 50px;
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ const mapStateToProps = (
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: Function): ReduxDispatchProps => ({
|
const mapDispatchToProps = (dispatch: any): ReduxDispatchProps => ({
|
||||||
updateDatasource: datasource =>
|
updateDatasource: datasource =>
|
||||||
dispatch(change(API_EDITOR_FORM_NAME, "datasource", datasource)),
|
dispatch(change(API_EDITOR_FORM_NAME, "datasource", datasource)),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
|
||||||
selectionType: VALIDATION_TYPES.TEXT,
|
selectionType: VALIDATION_TYPES.TEXT,
|
||||||
isRequired: VALIDATION_TYPES.BOOLEAN,
|
isRequired: VALIDATION_TYPES.BOOLEAN,
|
||||||
// onOptionChange: VALIDATION_TYPES.ACTION_SELECTOR,
|
// onOptionChange: VALIDATION_TYPES.ACTION_SELECTOR,
|
||||||
selectedOptionValueArr: VALIDATION_TYPES.ARRAY,
|
|
||||||
selectedOptionValues: VALIDATION_TYPES.ARRAY,
|
selectedOptionValues: VALIDATION_TYPES.ARRAY,
|
||||||
defaultOptionValue: VALIDATION_TYPES.DEFAULT_OPTION_VALUE,
|
defaultOptionValue: VALIDATION_TYPES.DEFAULT_OPTION_VALUE,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,8 @@ const withMeta = (WrappedWidget: typeof BaseWidget) => {
|
||||||
Object.keys(metaProperties).forEach(metaProperty => {
|
Object.keys(metaProperties).forEach(metaProperty => {
|
||||||
const defaultProperty = defaultProperties[metaProperty];
|
const defaultProperty = defaultProperties[metaProperty];
|
||||||
if (
|
if (
|
||||||
prevProps[metaProperty] !== this.props[metaProperty] &&
|
!_.isEqual(prevProps[metaProperty], this.props[metaProperty]) &&
|
||||||
this.props[defaultProperty] === this.props[metaProperty]
|
_.isEqual(this.props[defaultProperty], this.props[metaProperty])
|
||||||
) {
|
) {
|
||||||
this.setState({ [metaProperty]: this.props[metaProperty] });
|
this.setState({ [metaProperty]: this.props[metaProperty] });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,9 @@ public class DatabaseChangelog {
|
||||||
* from an index with the fields `"organizationId", "name"`. If an index exists with the first ordering and we try
|
* from an index with the fields `"organizationId", "name"`. If an index exists with the first ordering and we try
|
||||||
* to **ensure** an index with the same name but the second ordering of fields, errors will show up and bad things
|
* to **ensure** an index with the same name but the second ordering of fields, errors will show up and bad things
|
||||||
* WILL happen.
|
* WILL happen.
|
||||||
|
*
|
||||||
|
* Also, please check out the following blog on how to best create indexes :
|
||||||
|
* https://emptysqua.re/blog/optimizing-mongodb-compound-indexes/
|
||||||
*/
|
*/
|
||||||
private static Index makeIndex(String... fields) {
|
private static Index makeIndex(String... fields) {
|
||||||
if (fields.length == 1) {
|
if (fields.length == 1) {
|
||||||
|
|
@ -1193,4 +1196,23 @@ public class DatabaseChangelog {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ChangeSet(order = "040", id = "new-page-new-action-add-indexes", author = "")
|
||||||
|
public void addNewPageAndNewActionNewIndexes(MongoTemplate mongoTemplate) {
|
||||||
|
|
||||||
|
dropIndexIfExists(mongoTemplate, NewAction.class, "createdAt");
|
||||||
|
|
||||||
|
ensureIndexes(mongoTemplate, NewAction.class,
|
||||||
|
makeIndex("applicationId", "deleted", "createdAt")
|
||||||
|
.named("applicationId_deleted_createdAt_compound_index")
|
||||||
|
);
|
||||||
|
|
||||||
|
dropIndexIfExists(mongoTemplate, NewPage.class, "createdAt");
|
||||||
|
|
||||||
|
ensureIndexes(mongoTemplate, NewPage.class,
|
||||||
|
makeIndex("applicationId", "deleted")
|
||||||
|
.named("applicationId_deleted_compound_index")
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import com.appsmith.server.domains.NewPage;
|
||||||
import com.appsmith.server.domains.Page;
|
import com.appsmith.server.domains.Page;
|
||||||
import com.appsmith.server.domains.Plugin;
|
import com.appsmith.server.domains.Plugin;
|
||||||
import com.appsmith.server.domains.PluginType;
|
import com.appsmith.server.domains.PluginType;
|
||||||
import com.appsmith.server.domains.QNewAction;
|
|
||||||
import com.appsmith.server.dtos.ActionDTO;
|
import com.appsmith.server.dtos.ActionDTO;
|
||||||
import com.appsmith.server.dtos.ActionViewDTO;
|
import com.appsmith.server.dtos.ActionViewDTO;
|
||||||
import com.appsmith.server.dtos.ExecuteActionDTO;
|
import com.appsmith.server.dtos.ExecuteActionDTO;
|
||||||
|
|
@ -66,7 +65,6 @@ import static com.appsmith.server.acl.AclPermission.MANAGE_DATASOURCES;
|
||||||
import static com.appsmith.server.acl.AclPermission.READ_ACTIONS;
|
import static com.appsmith.server.acl.AclPermission.READ_ACTIONS;
|
||||||
import static com.appsmith.server.acl.AclPermission.READ_PAGES;
|
import static com.appsmith.server.acl.AclPermission.READ_PAGES;
|
||||||
import static com.appsmith.server.helpers.BeanCopyUtils.copyNewFieldValuesIntoOldObject;
|
import static com.appsmith.server.helpers.BeanCopyUtils.copyNewFieldValuesIntoOldObject;
|
||||||
import static com.appsmith.server.repositories.BaseAppsmithRepositoryImpl.fieldName;
|
|
||||||
import static java.lang.Boolean.TRUE;
|
import static java.lang.Boolean.TRUE;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
|
@ -727,14 +725,14 @@ public class NewActionServiceImpl extends BaseService<NewActionRepository, NewAc
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<ActionViewDTO> getActionsForViewMode(String applicationId) {
|
public Flux<ActionViewDTO> getActionsForViewMode(String applicationId) {
|
||||||
Sort sort = Sort.by(fieldName(QNewAction.newAction.publishedAction) + "." + fieldName(QNewAction.newAction.publishedAction.name));
|
|
||||||
|
|
||||||
if (applicationId == null || applicationId.isEmpty()) {
|
if (applicationId == null || applicationId.isEmpty()) {
|
||||||
return Flux.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.APPLICATION_ID));
|
return Flux.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.APPLICATION_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch the published actions by applicationId
|
// fetch the published actions by applicationId
|
||||||
return findAllByApplicationIdAndViewMode(applicationId, true, EXECUTE_ACTIONS, sort)
|
// No need to sort the results
|
||||||
|
return findAllByApplicationIdAndViewMode(applicationId, true, EXECUTE_ACTIONS, null)
|
||||||
.map(action -> {
|
.map(action -> {
|
||||||
ActionViewDTO actionViewDTO = new ActionViewDTO();
|
ActionViewDTO actionViewDTO = new ActionViewDTO();
|
||||||
actionViewDTO.setId(action.getId());
|
actionViewDTO.setId(action.getId());
|
||||||
|
|
@ -783,7 +781,9 @@ public class NewActionServiceImpl extends BaseService<NewActionRepository, NewAc
|
||||||
public Flux<ActionDTO> getUnpublishedActions(MultiValueMap<String, String> params) {
|
public Flux<ActionDTO> getUnpublishedActions(MultiValueMap<String, String> params) {
|
||||||
String name = null;
|
String name = null;
|
||||||
List<String> pageIds = new ArrayList<>();
|
List<String> pageIds = new ArrayList<>();
|
||||||
Sort sort = Sort.by(FieldName.NAME);
|
|
||||||
|
// In the edit mode, the actions should be displayed in the order they were created.
|
||||||
|
Sort sort = Sort.by(FieldName.CREATED_AT);
|
||||||
|
|
||||||
if (params.getFirst(FieldName.NAME) != null) {
|
if (params.getFirst(FieldName.NAME) != null) {
|
||||||
name = params.getFirst(FieldName.NAME);
|
name = params.getFirst(FieldName.NAME);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user