Add widget cta in query pane (#1157)
This commit is contained in:
parent
05380a9c43
commit
47847cbc7c
|
|
@ -0,0 +1,37 @@
|
||||||
|
const queryLocators = require("../../../locators/QueryEditor.json");
|
||||||
|
const queryEditor = require("../../../locators/QueryEditor.json");
|
||||||
|
|
||||||
|
let datasourceName;
|
||||||
|
|
||||||
|
describe("Add widget", function() {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.createPostgresDatasource();
|
||||||
|
cy.get("@createDatasource").then(httpResponse => {
|
||||||
|
datasourceName = httpResponse.response.body.data.name;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Add widget", () => {
|
||||||
|
cy.NavigateToQueryEditor();
|
||||||
|
cy.get(".t--datasource-name")
|
||||||
|
.contains(datasourceName)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.get(queryLocators.templateMenu).click();
|
||||||
|
cy.get(".CodeMirror textarea")
|
||||||
|
.first()
|
||||||
|
.focus()
|
||||||
|
.type("select * from configs");
|
||||||
|
|
||||||
|
cy.get(queryEditor.runQuery).click();
|
||||||
|
cy.wait("@postExecute").should(
|
||||||
|
"have.nested.property",
|
||||||
|
"response.body.responseMeta.status",
|
||||||
|
200,
|
||||||
|
);
|
||||||
|
|
||||||
|
cy.get(".t--add-widget").click();
|
||||||
|
|
||||||
|
cy.SearchEntityandOpen("Table1");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -127,3 +127,10 @@ export const cutWidget = () => {
|
||||||
type: ReduxActionTypes.CUT_SELECTED_WIDGET,
|
type: ReduxActionTypes.CUT_SELECTED_WIDGET,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const addTableWidgetFromQuery = (queryName: string) => {
|
||||||
|
return {
|
||||||
|
type: ReduxActionTypes.ADD_TABLE_WIDGET_FROM_QUERY,
|
||||||
|
payload: queryName,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,7 @@ export const ReduxActionTypes: { [key: string]: string } = {
|
||||||
FOCUS_WIDGET: "FOCUS_WIDGET",
|
FOCUS_WIDGET: "FOCUS_WIDGET",
|
||||||
SET_WIDGET_DRAGGING: "SET_WIDGET_DRAGGING",
|
SET_WIDGET_DRAGGING: "SET_WIDGET_DRAGGING",
|
||||||
SET_WIDGET_RESIZING: "SET_WIDGET_RESIZING",
|
SET_WIDGET_RESIZING: "SET_WIDGET_RESIZING",
|
||||||
|
ADD_TABLE_WIDGET_FROM_QUERY: "ADD_TABLE_WIDGET_FROM_QUERY",
|
||||||
SEARCH_APPLICATIONS: "SEARCH_APPLICATIONS",
|
SEARCH_APPLICATIONS: "SEARCH_APPLICATIONS",
|
||||||
UPDATE_PAGE_INIT: "UPDATE_PAGE_INIT",
|
UPDATE_PAGE_INIT: "UPDATE_PAGE_INIT",
|
||||||
UPDATE_PAGE_SUCCESS: "UPDATE_PAGE_SUCCESS",
|
UPDATE_PAGE_SUCCESS: "UPDATE_PAGE_SUCCESS",
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ export const QueryTemplates = (props: QueryTemplatesProps) => {
|
||||||
currentPageId,
|
currentPageId,
|
||||||
params.applicationId,
|
params.applicationId,
|
||||||
props.datasourceId,
|
props.datasourceId,
|
||||||
|
dataSource,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export type WidgetTree = WidgetProps & { children?: WidgetTree[] };
|
||||||
|
|
||||||
const UNREGISTERED_WIDGETS: WidgetType[] = [WidgetTypes.ICON_WIDGET];
|
const UNREGISTERED_WIDGETS: WidgetType[] = [WidgetTypes.ICON_WIDGET];
|
||||||
|
|
||||||
const navigateToCanvas = (
|
export const navigateToCanvas = (
|
||||||
params: ExplorerURLParams,
|
params: ExplorerURLParams,
|
||||||
currentPath: string,
|
currentPath: string,
|
||||||
widgetPageId: string,
|
widgetPageId: string,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import { Colors } from "constants/Colors";
|
||||||
import JSONViewer from "./JSONViewer";
|
import JSONViewer from "./JSONViewer";
|
||||||
import Table from "./Table";
|
import Table from "./Table";
|
||||||
import { RestAction } from "entities/Action";
|
import { RestAction } from "entities/Action";
|
||||||
import { connect } from "react-redux";
|
import { connect, useDispatch } from "react-redux";
|
||||||
import { AppState } from "reducers";
|
import { AppState } from "reducers";
|
||||||
import ActionNameEditor from "components/editorComponents/ActionNameEditor";
|
import ActionNameEditor from "components/editorComponents/ActionNameEditor";
|
||||||
import CollapsibleHelp from "components/designSystems/appsmith/help/CollapsibleHelp";
|
import CollapsibleHelp from "components/designSystems/appsmith/help/CollapsibleHelp";
|
||||||
|
|
@ -37,6 +37,7 @@ import { ControlProps } from "components/formControls/BaseControl";
|
||||||
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
|
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
|
||||||
import ActionSettings from "pages/Editor/ActionSettings";
|
import ActionSettings from "pages/Editor/ActionSettings";
|
||||||
import { queryActionSettingsConfig } from "mockResponses/ActionSettings";
|
import { queryActionSettingsConfig } from "mockResponses/ActionSettings";
|
||||||
|
import { addTableWidgetFromQuery } from "actions/widgetActions";
|
||||||
|
|
||||||
const QueryFormContainer = styled.div`
|
const QueryFormContainer = styled.div`
|
||||||
padding: 20px 32px;
|
padding: 20px 32px;
|
||||||
|
|
@ -230,6 +231,21 @@ const SettingsWrapper = styled.div`
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const AddWidgetButton = styled(BaseButton)`
|
||||||
|
&&&& {
|
||||||
|
max-width: 125px;
|
||||||
|
border: 1px solid ${Colors.GEYSER_LIGHT};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const OutputHeader = styled.div`
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
type QueryFormProps = {
|
type QueryFormProps = {
|
||||||
onDeleteClick: () => void;
|
onDeleteClick: () => void;
|
||||||
onRunClick: () => void;
|
onRunClick: () => void;
|
||||||
|
|
@ -279,6 +295,7 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
|
||||||
documentationLink,
|
documentationLink,
|
||||||
loadingFormConfigs,
|
loadingFormConfigs,
|
||||||
editorConfig,
|
editorConfig,
|
||||||
|
actionName,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
let error = runErrorMessage;
|
let error = runErrorMessage;
|
||||||
|
|
@ -294,6 +311,11 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
|
||||||
|
|
||||||
const isSQL = responseType === "TABLE";
|
const isSQL = responseType === "TABLE";
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const onAddWidget = () => {
|
||||||
|
dispatch(addTableWidgetFromQuery(actionName));
|
||||||
|
};
|
||||||
|
|
||||||
const MenuList = (props: MenuListComponentProps<{ children: Node }>) => {
|
const MenuList = (props: MenuListComponentProps<{ children: Node }>) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -523,9 +545,19 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
|
||||||
|
|
||||||
{!error && output && dataSources.length && (
|
{!error && output && dataSources.length && (
|
||||||
<>
|
<>
|
||||||
|
<OutputHeader>
|
||||||
<p className="statementTextArea">
|
<p className="statementTextArea">
|
||||||
{output.length ? "Query response" : "No data records to display"}
|
{output.length ? "Query response" : "No data records to display"}
|
||||||
</p>
|
</p>
|
||||||
|
{!!output.length && (
|
||||||
|
<AddWidgetButton
|
||||||
|
className="t--add-widget"
|
||||||
|
icon={"plus"}
|
||||||
|
text="Add Widget"
|
||||||
|
onClick={onAddWidget}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</OutputHeader>
|
||||||
{isSQL ? <Table data={output} /> : <JSONViewer src={output} />}
|
{isSQL ? <Table data={output} /> : <JSONViewer src={output} />}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -127,9 +127,8 @@ type QueryHomeScreenProps = {
|
||||||
|
|
||||||
class QueryHomeScreen extends React.Component<QueryHomeScreenProps> {
|
class QueryHomeScreen extends React.Component<QueryHomeScreenProps> {
|
||||||
handleCreateNewQuery = (dataSource: Datasource, params: string) => {
|
handleCreateNewQuery = (dataSource: Datasource, params: string) => {
|
||||||
const { actions, pages } = this.props;
|
const { actions } = this.props;
|
||||||
const pageId = new URLSearchParams(params).get("importTo");
|
const pageId = new URLSearchParams(params).get("importTo");
|
||||||
const page = pages.find(page => page.pageId === pageId);
|
|
||||||
if (pageId) {
|
if (pageId) {
|
||||||
const newQueryName = createNewQueryName(actions, pageId);
|
const newQueryName = createNewQueryName(actions, pageId);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import React from "react";
|
|
||||||
import { createReducer } from "utils/AppsmithUtils";
|
import { createReducer } from "utils/AppsmithUtils";
|
||||||
import { ReduxActionTypes, ReduxAction } from "constants/ReduxActionConstants";
|
import { ReduxActionTypes, ReduxAction } from "constants/ReduxActionConstants";
|
||||||
import { Datasource } from "api/DatasourcesApi";
|
import { Datasource } from "api/DatasourcesApi";
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ import {
|
||||||
selectPlugin,
|
selectPlugin,
|
||||||
createDatasource,
|
createDatasource,
|
||||||
changeDatasource,
|
changeDatasource,
|
||||||
testDatasource,
|
|
||||||
setDatsourceEditorMode,
|
setDatsourceEditorMode,
|
||||||
expandDatasourceEntity,
|
expandDatasourceEntity,
|
||||||
fetchDatasourceStructure,
|
fetchDatasourceStructure,
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import { convertToString, getNextEntityName } from "utils/AppsmithUtils";
|
||||||
import {
|
import {
|
||||||
SetWidgetDynamicPropertyPayload,
|
SetWidgetDynamicPropertyPayload,
|
||||||
updateWidgetProperty,
|
updateWidgetProperty,
|
||||||
|
updateWidgetPropertyRequest,
|
||||||
UpdateWidgetPropertyRequestPayload,
|
UpdateWidgetPropertyRequestPayload,
|
||||||
} from "actions/controlActions";
|
} from "actions/controlActions";
|
||||||
import { isDynamicValue } from "utils/DynamicBindingUtils";
|
import { isDynamicValue } from "utils/DynamicBindingUtils";
|
||||||
|
|
@ -71,6 +72,12 @@ import { flashElementById } from "utils/helpers";
|
||||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
|
import { navigateToCanvas } from "pages/Editor/Explorer/Widgets/WidgetEntity";
|
||||||
|
import {
|
||||||
|
getCurrentApplicationId,
|
||||||
|
getCurrentPageId,
|
||||||
|
} from "selectors/editorSelectors";
|
||||||
|
import { forceOpenPropertyPane } from "actions/widgetActions";
|
||||||
|
|
||||||
function getChildWidgetProps(
|
function getChildWidgetProps(
|
||||||
parent: FlattenedWidgetProps,
|
parent: FlattenedWidgetProps,
|
||||||
|
|
@ -946,8 +953,90 @@ function* cutWidgetSaga() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* addTableWidgetFromQuerySaga(action: ReduxAction<string>) {
|
||||||
|
try {
|
||||||
|
const columns = 8;
|
||||||
|
const rows = 7;
|
||||||
|
const queryName = action.payload;
|
||||||
|
const widgets = yield select(getWidgets);
|
||||||
|
const widgetName = getNextWidgetName(widgets, "TABLE_WIDGET");
|
||||||
|
|
||||||
|
let newWidget = {
|
||||||
|
type: WidgetTypes.TABLE_WIDGET,
|
||||||
|
newWidgetId: generateReactKey(),
|
||||||
|
widgetId: "0",
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: rows,
|
||||||
|
leftColumn: 0,
|
||||||
|
rightColumn: columns,
|
||||||
|
columns,
|
||||||
|
rows,
|
||||||
|
parentId: "0",
|
||||||
|
widgetName,
|
||||||
|
renderMode: RenderModes.CANVAS,
|
||||||
|
parentRowSpace: 1,
|
||||||
|
parentColumnSpace: 1,
|
||||||
|
isLoading: false,
|
||||||
|
};
|
||||||
|
const {
|
||||||
|
leftColumn,
|
||||||
|
topRow,
|
||||||
|
rightColumn,
|
||||||
|
bottomRow,
|
||||||
|
} = yield calculateNewWidgetPosition(newWidget, "0", widgets);
|
||||||
|
|
||||||
|
newWidget = {
|
||||||
|
...newWidget,
|
||||||
|
leftColumn,
|
||||||
|
topRow,
|
||||||
|
rightColumn,
|
||||||
|
bottomRow,
|
||||||
|
};
|
||||||
|
|
||||||
|
yield put({
|
||||||
|
type: ReduxActionTypes.WIDGET_ADD_CHILD,
|
||||||
|
payload: newWidget,
|
||||||
|
});
|
||||||
|
|
||||||
|
const applicationId = yield select(getCurrentApplicationId);
|
||||||
|
const pageId = yield select(getCurrentPageId);
|
||||||
|
|
||||||
|
navigateToCanvas(
|
||||||
|
{
|
||||||
|
applicationId,
|
||||||
|
pageId,
|
||||||
|
},
|
||||||
|
window.location.pathname,
|
||||||
|
pageId,
|
||||||
|
newWidget.newWidgetId,
|
||||||
|
);
|
||||||
|
yield put({
|
||||||
|
type: ReduxActionTypes.SELECT_WIDGET,
|
||||||
|
payload: { widgetId: newWidget.newWidgetId },
|
||||||
|
});
|
||||||
|
yield put(forceOpenPropertyPane(newWidget.newWidgetId));
|
||||||
|
yield put(
|
||||||
|
updateWidgetPropertyRequest(
|
||||||
|
newWidget.newWidgetId,
|
||||||
|
"tableData",
|
||||||
|
`{{${queryName}.data}}`,
|
||||||
|
RenderModes.CANVAS,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
AppToaster.show({
|
||||||
|
message: "Failed to add the widget",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default function* widgetOperationSagas() {
|
export default function* widgetOperationSagas() {
|
||||||
yield all([
|
yield all([
|
||||||
|
takeEvery(
|
||||||
|
ReduxActionTypes.ADD_TABLE_WIDGET_FROM_QUERY,
|
||||||
|
addTableWidgetFromQuerySaga,
|
||||||
|
),
|
||||||
takeEvery(ReduxActionTypes.WIDGET_ADD_CHILD, addChildSaga),
|
takeEvery(ReduxActionTypes.WIDGET_ADD_CHILD, addChildSaga),
|
||||||
takeEvery(ReduxActionTypes.WIDGET_DELETE, deleteSaga),
|
takeEvery(ReduxActionTypes.WIDGET_DELETE, deleteSaga),
|
||||||
takeLatest(ReduxActionTypes.WIDGET_MOVE, moveSaga),
|
takeLatest(ReduxActionTypes.WIDGET_MOVE, moveSaga),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user