From e71bd321ea6df714089fa167fa6cc0d10c959147 Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Mon, 13 Jan 2025 16:48:12 +0500 Subject: [PATCH 1/5] added onInputChange and onPageLoad triggers in query --- .../lowcoder/src/comps/queries/queryComp.tsx | 42 ++++++++++++++++--- .../queries/queryComp/queryPropertyView.tsx | 35 ++++++++++------ 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/client/packages/lowcoder/src/comps/queries/queryComp.tsx b/client/packages/lowcoder/src/comps/queries/queryComp.tsx index 1937bf289..1387ca73f 100644 --- a/client/packages/lowcoder/src/comps/queries/queryComp.tsx +++ b/client/packages/lowcoder/src/comps/queries/queryComp.tsx @@ -97,10 +97,18 @@ interface AfterExecuteQueryAction { result: QueryResult; } -const TriggerTypeOptions = [ +export const TriggerTypeOptions = [ + { label: "On Page Load", value: "onPageLoad"}, + { label: "On Input Change", value: "onInputChange"}, { label: trans("query.triggerTypeAuto"), value: "automatic" }, { label: trans("query.triggerTypeManual"), value: "manual" }, ] as const; + +export const JSTriggerTypeOptions = [ + { label: trans("query.triggerTypeAuto"), value: "automatic" }, + { label: trans("query.triggerTypeManual"), value: "manual" }, +]; + export type TriggerType = ValueFromOption; const EventOptions = [ @@ -174,6 +182,7 @@ export type QueryChildrenType = InstanceType extends MultiB ? X : never; +let blockInputChangeQueries = true; /** * Logic to automatically trigger execution */ @@ -222,10 +231,16 @@ QueryCompTmp = class extends QueryCompTmp { const isJsQuery = this.children.compType.getView() === "js"; const notExecuted = this.children.lastQueryStartTime.getView() === -1; const isAutomatic = getTriggerType(this) === "automatic"; + const isPageLoadTrigger = getTriggerType(this) === "onPageLoad"; + const isInputChangeTrigger = getTriggerType(this) === "onInputChange"; if ( action.type === CompActionTypes.UPDATE_NODES_V2 && - isAutomatic && + ( + isAutomatic + || isInputChangeTrigger + || (isPageLoadTrigger && notExecuted) + ) && (!isJsQuery || (isJsQuery && notExecuted)) // query which has deps can be executed on page load(first time) ) { const next = super.reduce(action); @@ -250,6 +265,18 @@ QueryCompTmp = class extends QueryCompTmp { const dependsChanged = !_.isEqual(preDepends, depends); const dslNotChanged = _.isEqual(preDsl, dsl); + if(isInputChangeTrigger && blockInputChangeQueries && dependsChanged) { + // block executing input change queries initially on page refresh + setTimeout(() => { + blockInputChangeQueries = false; + }, 500) + + return setFieldsNoTypeCheck(next, { + [lastDependsKey]: depends, + [lastDslKey]: dsl, + }); + } + // If the dsl has not changed, but the dependent node value has changed, then trigger the query execution // FIXME, this should be changed to a reference judgement, but for unknown reasons if the reference is modified once, it will change twice. if (dependsChanged) { @@ -277,7 +304,10 @@ function QueryView(props: QueryViewProps) { useEffect(() => { // Automatically load when page load if ( - getTriggerType(comp) === "automatic" && + ( + getTriggerType(comp) === "automatic" + || getTriggerType(comp) === "onPageLoad" + ) && (comp as any).isDepReady && !comp.children.isNewCreate.value ) { @@ -292,9 +322,9 @@ function QueryView(props: QueryViewProps) { getPromiseAfterDispatch(comp.dispatch, executeQueryAction({}), { notHandledError: trans("query.fixedDelayError"), }), - getTriggerType(comp) === "automatic" && comp.children.periodic.getView() - ? comp.children.periodicTime.getView() - : null + getTriggerType(comp) === "automatic" && comp.children.periodic.getView() + ? comp.children.periodicTime.getView() + : null ); return null; diff --git a/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx b/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx index 910365185..cfe8b8ccb 100644 --- a/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx +++ b/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx @@ -26,7 +26,7 @@ import { useSelector } from "react-redux"; import { getDataSource, getDataSourceTypes } from "redux/selectors/datasourceSelectors"; import { BottomResTypeEnum } from "types/bottomRes"; import { EditorContext } from "../../editorState"; -import { QueryComp } from "../queryComp"; +import { JSTriggerTypeOptions, QueryComp, TriggerType, TriggerTypeOptions } from "../queryComp"; import { ResourceDropdown } from "../resourceDropdown"; import { NOT_SUPPORT_GUI_SQL_QUERY, SQLQuery } from "../sqlQuery/SQLQuery"; import { StreamQuery } from "../httpQuery/streamQuery"; @@ -226,6 +226,13 @@ export const QueryGeneralPropertyView = (props: { comp.children.datasourceId.dispatchChangeValueAction(QUICK_REST_API_ID); } + const triggerOptions = useMemo(() => { + if (datasourceType === "js" || datasourceType === "streamApi") { + return JSTriggerTypeOptions; + } + return TriggerTypeOptions; + }, [datasourceType]); + return ( @@ -333,20 +340,22 @@ export const QueryGeneralPropertyView = (props: { children.triggerType.dispatchChangeValueAction(value)} + onChange={(value) => children.triggerType.dispatchChangeValueAction(value as TriggerType)} /> )} From fb3a52c41d0b5ee1228dd1091de41e4093dabf4d Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Mon, 13 Jan 2025 22:59:51 +0500 Subject: [PATCH 2/5] added onQueryExecution trigger in query --- .../lowcoder/src/comps/queries/queryComp.tsx | 27 ++++++- .../queries/queryComp/queryPropertyView.tsx | 75 +++++++++++++------ 2 files changed, 79 insertions(+), 23 deletions(-) diff --git a/client/packages/lowcoder/src/comps/queries/queryComp.tsx b/client/packages/lowcoder/src/comps/queries/queryComp.tsx index 1387ca73f..f1f657733 100644 --- a/client/packages/lowcoder/src/comps/queries/queryComp.tsx +++ b/client/packages/lowcoder/src/comps/queries/queryComp.tsx @@ -72,7 +72,7 @@ import { HttpQuery } from "./httpQuery/httpQuery"; import { StreamQuery } from "./httpQuery/streamQuery"; import { QueryConfirmationModal } from "./queryComp/queryConfirmationModal"; import { QueryNotificationControl } from "./queryComp/queryNotificationControl"; -import { QueryPropertyView } from "./queryComp/queryPropertyView"; +import { findDependentQueries, QueryPropertyView } from "./queryComp/queryPropertyView"; import { getTriggerType, onlyManualTrigger } from "./queryCompUtils"; import { messageInstance } from "lowcoder-design/src/components/GlobalInstances"; @@ -100,6 +100,7 @@ interface AfterExecuteQueryAction { export const TriggerTypeOptions = [ { label: "On Page Load", value: "onPageLoad"}, { label: "On Input Change", value: "onInputChange"}, + { label: "On Query Execution", value: "onQueryExecution"}, { label: trans("query.triggerTypeAuto"), value: "automatic" }, { label: trans("query.triggerTypeManual"), value: "manual" }, ] as const; @@ -159,6 +160,7 @@ const childrenMap = { }, }), cancelPrevious: withDefault(BoolPureControl, false), + depQueryName: SimpleNameComp, }; let QueryCompTmp = withTypeAndChildren>( @@ -639,6 +641,29 @@ export const QueryComp = withExposingConfigs(QueryCompTmp, [ const QueryListTmpComp = list(QueryComp); class QueryListComp extends QueryListTmpComp implements BottomResListComp { + override reduce(action: CompAction): this { + if (isCustomAction(action, "afterExecQuery")) { + if (action.path?.length === 1 && !isNaN(parseInt(action.path[0]))) { + const queryIdx = parseInt(action.path[0]); + const queryComps = this.getView(); + const queryName = queryComps?.[queryIdx]?.children.name.getView(); + const dependentQueries = queryComps.filter((query, idx) => { + if (queryIdx === idx) return false; + if ( + getTriggerType(query) === 'onQueryExecution' + && query.children.depQueryName.getView() === queryName + ) { + return true; + } + }) + dependentQueries?.forEach((query) => { + query.dispatch(deferAction(executeQueryAction({}))); + }) + } + } + return super.reduce(action); + } + nameAndExposingInfo(): NameAndExposingInfo { const result: NameAndExposingInfo = {}; Object.values(this.children).forEach((comp) => { diff --git a/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx b/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx index cfe8b8ccb..db75c33aa 100644 --- a/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx +++ b/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx @@ -37,6 +37,7 @@ import styled from "styled-components"; import { DataSourceButton } from "pages/datasource/pluginPanel"; import { Tooltip, Divider } from "antd"; import { uiCompRegistry } from "comps/uiCompRegistry"; +import { InputTypeEnum } from "@lowcoder-ee/comps/comps/moduleContainerComp/ioComp/inputListItemComp"; const Wrapper = styled.div` width: 100%; @@ -233,6 +234,35 @@ export const QueryGeneralPropertyView = (props: { return TriggerTypeOptions; }, [datasourceType]); + const getQueryOptions = useMemo(() => { + const options: { label: string; value: string }[] = + editorState + ?.queryCompInfoList() + .map((info) => ({ + label: info.name, + value: info.name, + })) + .filter((option) => { + // Filter out the current query under query + if (editorState.selectedBottomResType === BottomResTypeEnum.Query) { + return option.value !== editorState.selectedBottomResName; + } + return true; + }) || []; + + // input queries + editorState + ?.getModuleLayoutComp() + ?.getInputs() + .forEach((i) => { + const { name, type } = i.getView(); + if (type === InputTypeEnum.Query) { + options.push({ label: name, value: name }); + } + }); + return options; + }, [editorState]); + return ( @@ -336,28 +366,29 @@ export const QueryGeneralPropertyView = (props: { {placement === "editor" && ( - - children.triggerType.dispatchChangeValueAction(value as TriggerType)} - /> - + <> + + children.triggerType.dispatchChangeValueAction(value as TriggerType)} + /> + + {children.triggerType.getView() === 'onQueryExecution' && ( + + children.depQueryName.dispatchChangeValueAction(value)} + /> + + )} + )} From 85bc2db6ecdcf499d482b42df1e90a58993a2c0b Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Mon, 13 Jan 2025 23:00:35 +0500 Subject: [PATCH 3/5] removed import --- client/packages/lowcoder/src/comps/queries/queryComp.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/packages/lowcoder/src/comps/queries/queryComp.tsx b/client/packages/lowcoder/src/comps/queries/queryComp.tsx index f1f657733..e34b541ba 100644 --- a/client/packages/lowcoder/src/comps/queries/queryComp.tsx +++ b/client/packages/lowcoder/src/comps/queries/queryComp.tsx @@ -72,7 +72,7 @@ import { HttpQuery } from "./httpQuery/httpQuery"; import { StreamQuery } from "./httpQuery/streamQuery"; import { QueryConfirmationModal } from "./queryComp/queryConfirmationModal"; import { QueryNotificationControl } from "./queryComp/queryNotificationControl"; -import { findDependentQueries, QueryPropertyView } from "./queryComp/queryPropertyView"; +import { QueryPropertyView } from "./queryComp/queryPropertyView"; import { getTriggerType, onlyManualTrigger } from "./queryCompUtils"; import { messageInstance } from "lowcoder-design/src/components/GlobalInstances"; From ed1220665bc383999045f8788a72a0d18c02c57d Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Tue, 14 Jan 2025 16:52:18 +0500 Subject: [PATCH 4/5] added onTimeout trigger on query --- .../lowcoder/src/comps/queries/queryComp.tsx | 15 ++++++++++++++- .../comps/queries/queryComp/queryPropertyView.tsx | 10 ++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/client/packages/lowcoder/src/comps/queries/queryComp.tsx b/client/packages/lowcoder/src/comps/queries/queryComp.tsx index e34b541ba..b1cfd7042 100644 --- a/client/packages/lowcoder/src/comps/queries/queryComp.tsx +++ b/client/packages/lowcoder/src/comps/queries/queryComp.tsx @@ -101,12 +101,13 @@ export const TriggerTypeOptions = [ { label: "On Page Load", value: "onPageLoad"}, { label: "On Input Change", value: "onInputChange"}, { label: "On Query Execution", value: "onQueryExecution"}, + { label: "On Timeout", value: "onTimeout"}, { label: trans("query.triggerTypeAuto"), value: "automatic" }, { label: trans("query.triggerTypeManual"), value: "manual" }, ] as const; export const JSTriggerTypeOptions = [ - { label: trans("query.triggerTypeAuto"), value: "automatic" }, + { label: trans("query.triggerTypePageLoad"), value: "automatic" }, { label: trans("query.triggerTypeManual"), value: "manual" }, ]; @@ -160,7 +161,13 @@ const childrenMap = { }, }), cancelPrevious: withDefault(BoolPureControl, false), + // use only for onQueryExecution trigger depQueryName: SimpleNameComp, + // use only for onTimeout trigger, triggers query after x time passed on page load + delayTime: millisecondsControl({ + left: 0, + defaultValue: 5 * 1000, + }) }; let QueryCompTmp = withTypeAndChildren>( @@ -317,6 +324,12 @@ function QueryView(props: QueryViewProps) { comp.dispatch(deferAction(executeQueryAction({}))); }, 300); } + + if(getTriggerType(comp) === "onTimeout") { + setTimeout(() => { + comp.dispatch(deferAction(executeQueryAction({}))); + }, comp.children.delayTime.getView()); + } }, []); useFixedDelay( diff --git a/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx b/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx index db75c33aa..dc9a872ba 100644 --- a/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx +++ b/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx @@ -388,6 +388,16 @@ export const QueryGeneralPropertyView = (props: { /> )} + {children.triggerType.getView() === 'onTimeout' && ( + + {children.delayTime.propertyView({ + label: trans("query.timeout"), + placeholder: "5s", + tooltip: trans("query.timeoutTooltip", { maxSeconds: 3600, defaultSeconds: 5 }), + placement: "bottom", + })} + + )} )} From 9ce217204b28946d1c02f81daaa50bc4d9de34d1 Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Tue, 14 Jan 2025 22:08:49 +0500 Subject: [PATCH 5/5] Added onInputChange, onQueryExecution and onTimeout triggers on JS/Stream queries --- .../lowcoder/src/comps/queries/queryComp.tsx | 21 ++++++++++++------- .../queries/queryComp/queryPropertyView.tsx | 3 +-- .../packages/lowcoder/src/i18n/locales/en.ts | 4 ++++ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/client/packages/lowcoder/src/comps/queries/queryComp.tsx b/client/packages/lowcoder/src/comps/queries/queryComp.tsx index b1cfd7042..e90bf8d19 100644 --- a/client/packages/lowcoder/src/comps/queries/queryComp.tsx +++ b/client/packages/lowcoder/src/comps/queries/queryComp.tsx @@ -97,16 +97,21 @@ interface AfterExecuteQueryAction { result: QueryResult; } +const CommonTriggerOptions = [ + { label: trans("query.triggerTypeInputChange"), value: "onInputChange"}, + { label: trans("query.triggerTypeQueryExec"), value: "onQueryExecution"}, + { label: trans("query.triggerTypeTimeout"), value: "onTimeout"}, +] + export const TriggerTypeOptions = [ - { label: "On Page Load", value: "onPageLoad"}, - { label: "On Input Change", value: "onInputChange"}, - { label: "On Query Execution", value: "onQueryExecution"}, - { label: "On Timeout", value: "onTimeout"}, + { label: trans("query.triggerTypePageLoad"), value: "onPageLoad"}, + ...CommonTriggerOptions, { label: trans("query.triggerTypeAuto"), value: "automatic" }, { label: trans("query.triggerTypeManual"), value: "manual" }, ] as const; export const JSTriggerTypeOptions = [ + ...CommonTriggerOptions, { label: trans("query.triggerTypePageLoad"), value: "automatic" }, { label: trans("query.triggerTypeManual"), value: "manual" }, ]; @@ -244,13 +249,13 @@ QueryCompTmp = class extends QueryCompTmp { const isInputChangeTrigger = getTriggerType(this) === "onInputChange"; if ( - action.type === CompActionTypes.UPDATE_NODES_V2 && - ( + action.type === CompActionTypes.UPDATE_NODES_V2 + && ( isAutomatic || isInputChangeTrigger || (isPageLoadTrigger && notExecuted) - ) && - (!isJsQuery || (isJsQuery && notExecuted)) // query which has deps can be executed on page load(first time) + ) + // && (!isJsQuery || (isJsQuery && notExecuted)) // query which has deps can be executed on page load(first time) ) { const next = super.reduce(action); const depends = this.children.comp.node()?.dependValues(); diff --git a/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx b/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx index dc9a872ba..07f4ef1e0 100644 --- a/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx +++ b/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx @@ -391,9 +391,8 @@ export const QueryGeneralPropertyView = (props: { {children.triggerType.getView() === 'onTimeout' && ( {children.delayTime.propertyView({ - label: trans("query.timeout"), + label: trans("query.delayTime"), placeholder: "5s", - tooltip: trans("query.timeoutTooltip", { maxSeconds: 3600, defaultSeconds: 5 }), placement: "bottom", })} diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index baef755e8..be0378e20 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -738,6 +738,10 @@ export const en = { "triggerTypeAuto": "Inputs Change or On Page Load", "triggerTypePageLoad": "When the Application (Page) loads", "triggerTypeManual": "Only when you trigger it manually", + "triggerTypeInputChange": "When Inputs Change", + "triggerTypeQueryExec": "After Query Execution", + "triggerTypeTimeout": "After the Timeout Interval", + "delayTime": "Delay Time", "chooseDataSource": "Choose Data Source", "method": "Method", "updateExceptionDataSourceTitle": "Update Failing Data Source",