Merge pull request #48 from appsmithorg/release

Release
This commit is contained in:
Nikhil Nandagopal 2020-09-16 11:30:19 +05:30 committed by GitHub
commit daf65bf2f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 108 additions and 58 deletions

View File

@ -58,7 +58,7 @@
"chartType": "LINE_CHART",
"chartName": "Sales on working days",
"allowHorizontalScroll": false,
"chartData": "[{\"seriesName\":\"\",\"data\":\"\"}]",
"chartData": [{"seriesName":"Sales","data":""}],
"xAxisName": "Last Week",
"yAxisName": "Total Order Revenue $",
"type": "CHART_WIDGET",

View File

@ -61,7 +61,7 @@ class SwitchControl extends BaseControl<SwitchControlProps> {
}
getControlType(): ControlType {
return "FILE_PICKER";
return "SWITCH";
}
}

View File

@ -12,6 +12,7 @@ import {
EditorTheme,
TabBehaviour,
} from "components/editorComponents/CodeEditor/EditorConfig";
import * as Sentry from "@sentry/react";
const StyledOptionControlWrapper = styled(ControlWrapper)`
display: flex;
@ -138,6 +139,11 @@ function DataControlComponent(props: RenderComponentProps) {
}
class ChartDataControl extends BaseControl<ControlProps> {
chartData: Array<{
seriesName: string;
data: string;
}> = [];
getValidations = (message: string, isValid: boolean, len: number) => {
const validations: Array<{
isValid: boolean;
@ -166,16 +172,36 @@ class ChartDataControl extends BaseControl<ControlProps> {
return validations;
};
render() {
const chartData: Array<{
seriesName: string;
data: Array<{ x: string; y: string }> | string;
}> =
this.props.propertyValue && _.isString(this.props.propertyValue)
? JSON.parse(this.props.propertyValue)
: this.props.propertyValue;
componentDidMount() {
const chartData = this.props.propertyValue;
// Added a migration script for older chart data that was strings
// deprecate after enough charts have moved to the new format
if (_.isString(chartData)) {
try {
const parsedData: Array<{
seriesName: string;
data: string;
}> = JSON.parse(chartData);
this.updateProperty("chartData", parsedData);
this.chartData = parsedData;
} catch (error) {
Sentry.captureException({
message: "Chart Migration Failed",
oldData: this.props.propertyValue,
});
}
} else {
this.chartData = this.props.propertyValue;
}
}
const dataLength = chartData.length;
componentDidUpdate() {
this.chartData = this.props.propertyValue;
}
render() {
const chartData = this.chartData;
const dataLength = this.chartData.length;
const { validationMessage, isValid } = this.props;
const validations: Array<{
isValid: boolean;
@ -187,7 +213,7 @@ class ChartDataControl extends BaseControl<ControlProps> {
);
return (
<React.Fragment>
{chartData.map((data, index) => {
{this.chartData.map((data, index) => {
return (
<DataControlComponent
key={index}
@ -214,12 +240,12 @@ class ChartDataControl extends BaseControl<ControlProps> {
}
deleteOption = (index: number) => {
const chartData: object[] =
this.props.propertyValue && _.isString(this.props.propertyValue)
? JSON.parse(this.props.propertyValue)
: this.props.propertyValue;
const chartData: Array<{
seriesName: string;
data: string;
}> = this.props.propertyValue;
chartData.splice(index, 1);
this.updateProperty(this.props.propertyName, JSON.stringify(chartData));
this.updateProperty(this.props.propertyName, chartData);
};
updateOption = (
@ -229,41 +255,28 @@ class ChartDataControl extends BaseControl<ControlProps> {
) => {
const chartData: Array<{
seriesName: string;
data: Array<{ x: string; y: string }> | any;
}> =
this.props.propertyValue && _.isString(this.props.propertyValue)
? JSON.parse(this.props.propertyValue)
: this.props.propertyValue;
data: string;
}> = this.props.propertyValue;
const updatedChartData = chartData.map((item, i) => {
if (index === i) {
if (propertyName === "seriesName") {
item.seriesName = updatedValue;
} else {
try {
item.data = JSON.parse(updatedValue);
} catch (err) {
item.data = updatedValue;
}
item.data = updatedValue;
}
}
return item;
});
this.updateProperty(
this.props.propertyName,
JSON.stringify(updatedChartData),
);
this.updateProperty(this.props.propertyName, updatedChartData);
};
addOption = () => {
const chartData: Array<{
seriesName: string;
data: Array<{ x: string; y: string }> | any;
}> =
this.props.propertyValue && _.isString(this.props.propertyValue)
? JSON.parse(this.props.propertyValue)
: this.props.propertyValue;
chartData.push({ seriesName: "", data: [{ x: "", y: "" }] });
this.updateProperty(this.props.propertyName, JSON.stringify(chartData));
data: string;
}> = this.props.propertyValue;
chartData.push({ seriesName: "", data: '[{ x: "", y: "" }]' });
this.updateProperty(this.props.propertyName, chartData);
};
static getControlType() {

View File

@ -10,6 +10,7 @@ import { PageListPayload } from "constants/ReduxActionConstants";
import WidgetFactory from "utils/WidgetFactory";
import { ActionConfig, PluginType, Property } from "entities/Action";
import { AppDataState } from "reducers/entityReducers/appReducer";
import _ from "lodash";
export type ActionDescription<T> = {
type: string;
@ -129,7 +130,7 @@ export class DataTreeFactory {
dataTree.actionPaths && dataTree.actionPaths.push();
});
Object.keys(widgets).forEach(w => {
const widget = widgets[w];
const widget = { ...widgets[w] };
const widgetMetaProps = widgetsMeta[w];
const defaultMetaProps = WidgetFactory.getWidgetMetaPropertiesMap(
widget.type,
@ -139,6 +140,12 @@ export class DataTreeFactory {
);
const derivedProps: any = {};
const dynamicBindings = widget.dynamicBindings || {};
Object.keys(dynamicBindings).forEach(propertyName => {
if (_.isObject(widget[propertyName])) {
// Stringify this because composite controls may have bindings in the sub controls
widget[propertyName] = JSON.stringify(widget[propertyName]);
}
});
Object.keys(derivedPropertyMap).forEach(propertyName => {
derivedProps[propertyName] = derivedPropertyMap[propertyName].replace(
/this./g,

View File

@ -298,9 +298,14 @@ function* updateDynamicTriggers(
function* updateDynamicBindings(
widget: WidgetProps,
propertyName: string,
propertyValue: string,
propertyValue: any,
) {
const isDynamic = isDynamicValue(propertyValue);
let stringProp = propertyValue;
if (_.isObject(propertyValue)) {
// Stringify this because composite controls may have bindings in the sub controls
stringProp = JSON.stringify(propertyValue);
}
const isDynamic = isDynamicValue(stringProp);
let dynamicBindings: Record<string, boolean> = widget.dynamicBindings || {};
if (!isDynamic && propertyName in dynamicBindings) {
dynamicBindings = _.omit(dynamicBindings, propertyName);

View File

@ -123,7 +123,12 @@ export const evaluateDynamicBoundValue = (
path: string,
callbackData?: any,
): JSExecutorResult => {
return JSExecutionManagerSingleton.evaluateSync(path, data, callbackData);
const unescapedJS = unescapeJS(path).replace(/(\r\n|\n|\r)/gm, "");
return JSExecutionManagerSingleton.evaluateSync(
unescapedJS,
data,
callbackData,
);
};
// For creating a final value where bindings could be in a template format
@ -332,14 +337,7 @@ export const createDependencyTree = (
if (entity.dynamicBindings) {
Object.keys(entity.dynamicBindings).forEach(propertyName => {
// using unescape to remove new lines from bindings which interfere with our regex extraction
let unevalPropValue = _.get(entity, propertyName);
if (
_.isString(unevalPropValue) &&
isDynamicValue(unevalPropValue)
) {
unevalPropValue = unescapeJS(unevalPropValue);
}
_.set(entity, propertyName, unevalPropValue);
const unevalPropValue = _.get(entity, propertyName);
const { jsSnippets } = getDynamicBindings(unevalPropValue);
const existingDeps =
dependencyMap[`${entityKey}.${propertyName}`] || [];
@ -358,14 +356,7 @@ export const createDependencyTree = (
if (entity.dynamicBindingPathList.length) {
entity.dynamicBindingPathList.forEach(prop => {
// using unescape to remove new lines from bindings which interfere with our regex extraction
let unevalPropValue = _.get(entity, prop.key);
if (
_.isString(unevalPropValue) &&
isDynamicValue(unevalPropValue)
) {
unevalPropValue = unescapeJS(unevalPropValue);
}
_.set(entity, prop.key, unevalPropValue);
const unevalPropValue = _.get(entity, prop.key);
const { jsSnippets } = getDynamicBindings(unevalPropValue);
const existingDeps =
dependencyMap[`${entityKey}.${prop.key}`] || [];

View File

@ -117,6 +117,7 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
onRowSelected: true,
onPageChange: true,
onSearchTextChanged: true,
columnActions: true,
};
}

View File

@ -16,6 +16,7 @@ public class ActionViewDTO {
String name;
String pageId;
Integer timeoutInMillisecond;
Boolean confirmBeforeExecute;
Set<String> jsonPathKeys;
// Overriding the getter to ensure that for actions missing action configuration, the timeout is

View File

@ -571,6 +571,7 @@ public class ActionServiceImpl extends BaseService<ActionRepository, Action, Str
actionViewDTO.setId(action.getId());
actionViewDTO.setName(action.getName());
actionViewDTO.setPageId(action.getPageId());
actionViewDTO.setConfirmBeforeExecute(action.getConfirmBeforeExecute());
if (action.getJsonPathKeys() != null && !action.getJsonPathKeys().isEmpty()) {
Set<String> jsonPathKeys;
jsonPathKeys = new HashSet<>();

View File

@ -582,4 +582,35 @@ public class ActionServiceTest {
Mono<ActionExecutionResult> actionExecutionResultMono = actionService.executeAction(executeActionDTO);
return actionExecutionResultMono;
}
@Test
@WithUserDetails(value = "api_user")
public void getActionInViewMode() {
Mockito.when(pluginExecutorHelper.getPluginExecutor(Mockito.any())).thenReturn(Mono.just(new MockPluginExecutor()));
Action action = new Action();
action.setName("view-mode-action-test");
action.setPageId(testPage.getId());
ActionConfiguration actionConfiguration = new ActionConfiguration();
actionConfiguration.setHttpMethod(HttpMethod.GET);
actionConfiguration.setPath("{{mustache}}");
action.setActionConfiguration(actionConfiguration);
action.setDatasource(datasource);
Mono<Action> createActionMono = actionService.create(action);
Mono<List<ActionViewDTO>> actionViewModeListMono = createActionMono
.then(actionService.getActionsForViewMode(testApp.getId()).collectList());
StepVerifier.create(actionViewModeListMono)
.assertNext(actions -> {
assertThat(actions.size()).isGreaterThan(0);
ActionViewDTO actionViewDTO = actions.get(0);
assertThat(actionViewDTO.getId()).isNotNull();
assertThat(actionViewDTO.getTimeoutInMillisecond()).isNotNull();
assertThat(actionViewDTO.getPageId()).isNotNull();
assertThat(actionViewDTO.getConfirmBeforeExecute()).isNotNull();
assertThat(actionViewDTO.getJsonPathKeys().size()).isEqualTo(1);
})
.verifyComplete();
}
}