diff --git a/client/packages/lowcoder-design/src/components/keyValueList.tsx b/client/packages/lowcoder-design/src/components/keyValueList.tsx index 7bd9f317a..6cedce3c4 100644 --- a/client/packages/lowcoder-design/src/components/keyValueList.tsx +++ b/client/packages/lowcoder-design/src/components/keyValueList.tsx @@ -76,20 +76,25 @@ export const KeyValueList = (props: { list: ReactNode[]; onAdd: () => void; onDelete: (item: ReactNode, index: number) => void; + isStatic?: boolean; }) => ( <> {props.list.map((item, index) => ( {item} - props.list.length > 1 && props.onDelete(item, index)} - $forbidden={props.list.length === 1} - /> + {!props.isStatic && + props.list.length > 1 && props.onDelete(item, index)} + $forbidden={props.list.length === 1} + /> + } ))} + {!props.isStatic && {trans("addItem")} + } ); diff --git a/client/packages/lowcoder/src/comps/controls/actionSelector/executeQueryAction.tsx b/client/packages/lowcoder/src/comps/controls/actionSelector/executeQueryAction.tsx index 720fc93fe..cc4018bd5 100644 --- a/client/packages/lowcoder/src/comps/controls/actionSelector/executeQueryAction.tsx +++ b/client/packages/lowcoder/src/comps/controls/actionSelector/executeQueryAction.tsx @@ -7,10 +7,100 @@ import { BranchDiv, Dropdown } from "lowcoder-design"; import { BottomResTypeEnum } from "types/bottomRes"; import { getPromiseAfterDispatch } from "util/promiseUtils"; import { trans } from "i18n"; +import {keyValueListControl, keyValueListToSearchStr, withDefault} from "lowcoder-sdk"; +import {KeyValue} from "@lowcoder-ee/types/common"; +import { useCallback, useContext, useEffect, useMemo } from "react"; +const ExecuteQueryPropertyView = ({ + comp, + placement, +}: { + comp: any, + placement?: "query" | "table" +}) => { + const getQueryOptions = useCallback((editorState?: EditorState) => { + const options: { label: string; value: string; variable?: Record }[] = + editorState + ?.queryCompInfoList() + .map((info) => { + return { + label: info.name, + value: info.name, + variable: info.data.variable, + } + }) + .filter( + // Filter out the current query under query + (option) => { + if ( + placement === "query" && + 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; + }, [placement]); + + const getVariableOptions = useCallback((editorState?: EditorState) => { + return comp.children.queryVariables.propertyView({ + label: trans("eventHandler.queryVariables"), + layout: "vertical", + isStatic: true, + keyFixed: true, + }); + }, [comp.children.queryVariables.getView()]) + + return ( + <> + + + {(editorState) => ( + <> + { + const options = getQueryOptions(editorState); + const selectedQuery = options.find(option => option.value === value); + const variables = selectedQuery ? Object.keys(selectedQuery.variable || {}) : []; + comp.dispatchChangeValueAction({ + queryName: value, + queryVariables: variables.map((variable) => ({key: variable, value: ''})), + }); + }} + /> + + )} + + + + + {(editorState) => getVariableOptions(editorState)} + + + + ); +} const ExecuteQueryTmpAction = (function () { const childrenMap = { queryName: SimpleNameComp, + queryVariables: withDefault(keyValueListControl(false, [], "string"), []) }; return new MultiCompBuilder(childrenMap, () => { return () => Promise.resolve(undefined as unknown); @@ -22,6 +112,15 @@ const ExecuteQueryTmpAction = (function () { export class ExecuteQueryAction extends ExecuteQueryTmpAction { override getView() { const queryName = this.children.queryName.getView(); + // const queryParams = keyValueListToSearchStr(Array.isArray(this?.children?.query) ? (this.children.query as unknown as any[]).map((i: any) => i.getView() as KeyValue) : []); + const result = Object.values(this.children.queryVariables.children as Record) + .filter(item => item.children.key.unevaledValue !== "" && item.children.value.unevaledValue !== "") + .map(item => ({[item.children.key.unevaledValue]: item.children.value.unevaledValue})) + .reduce((acc, curr) => Object.assign(acc, curr), {}); if (!queryName) { return () => Promise.resolve(); } @@ -30,9 +129,7 @@ export class ExecuteQueryAction extends ExecuteQueryTmpAction { this.dispatch, routeByNameAction( queryName, - executeQueryAction({ - // can add context in the future - }) + executeQueryAction({args: result}) ), { notHandledError: trans("eventHandler.notHandledError") } ); @@ -46,55 +143,11 @@ export class ExecuteQueryAction extends ExecuteQueryTmpAction { } propertyView({ placement }: { placement?: "query" | "table" }) { - const getQueryOptions = (editorState?: EditorState) => { - const options: { label: string; value: string }[] = - editorState - ?.queryCompInfoList() - .map((info) => ({ - label: info.name, - value: info.name, - })) - .filter( - // Filter out the current query under query - (option) => { - if ( - placement === "query" && - 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; - }; return ( - - - {(editorState) => ( - <> - this.dispatchChangeValueAction({ queryName: value })} - /> - - )} - - - ); + + ) } } diff --git a/client/packages/lowcoder/src/comps/controls/actionSelector/goToURLAction.tsx b/client/packages/lowcoder/src/comps/controls/actionSelector/goToURLAction.tsx index 462cd6213..2223079ef 100644 --- a/client/packages/lowcoder/src/comps/controls/actionSelector/goToURLAction.tsx +++ b/client/packages/lowcoder/src/comps/controls/actionSelector/goToURLAction.tsx @@ -20,7 +20,7 @@ const childrenMap = { }; export const GoToURLAction = new MultiCompBuilder(childrenMap, (props) => { - return () => { + return () => { const queryParams = keyValueListToSearchStr( props.query.map((i) => i.getView() as KeyValue) ); diff --git a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx index 3a22afe71..70bf77962 100644 --- a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx @@ -167,12 +167,18 @@ const EventHandlerControlPropertyView = (props: { if (eventConfigs.length === 0) { return; } + + const queryVariables = editorState + ?.selectedOrFirstQueryComp() + ?.children.variables.children.variables.toJsonValue(); + const queryExecHandler = { compType: "executeQuery", comp: { queryName: editorState ?.selectedOrFirstQueryComp() ?.children.name.getView(), + queryVariables: queryVariables?.map((variable) => ({...variable, value: ''})), }, }; const messageHandler = { diff --git a/client/packages/lowcoder/src/comps/controls/keyValueControl.tsx b/client/packages/lowcoder/src/comps/controls/keyValueControl.tsx index 89cc6d276..1f4d722a2 100644 --- a/client/packages/lowcoder/src/comps/controls/keyValueControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/keyValueControl.tsx @@ -47,6 +47,8 @@ export type KeyValueControlParams = ControlParams & { typeTooltip?: ReactNode; keyFlexBasics?: number; valueFlexBasics?: number; + isStatic?: boolean; + keyFixed?: boolean; }; /** @@ -82,16 +84,20 @@ function keyValueControl( return ( - {this.children.key.propertyView({ placeholder: "key", indentWithTab: false })} - {hasType && params.showType && ( - - {this.children.type.propertyView({ - placeholder: "key", - indentWithTab: false, - tooltip: params.typeTooltip, - })} - - )} + {params.keyFixed? + <>{this.children.key.getView()} + :<> + {this.children.key.propertyView({ placeholder: "key", indentWithTab: false })} + {hasType && params.showType && ( + + {this.children.type.propertyView({ + placeholder: "key", + indentWithTab: false, + tooltip: params.typeTooltip, + })} + + )} + } {this.children.value.propertyView({ @@ -136,6 +142,7 @@ export function keyValueListControl( list={this.getView().map((child) => child.propertyView(params))} onAdd={() => this.dispatch(this.pushAction({}))} onDelete={(item, index) => this.dispatch(this.deleteAction(index))} + isStatic={params.isStatic} /> ); diff --git a/client/packages/lowcoder/src/comps/queries/queryComp.tsx b/client/packages/lowcoder/src/comps/queries/queryComp.tsx index e90bf8d19..fbfabeaaa 100644 --- a/client/packages/lowcoder/src/comps/queries/queryComp.tsx +++ b/client/packages/lowcoder/src/comps/queries/queryComp.tsx @@ -67,7 +67,7 @@ import { JSONObject, JSONValue } from "../../util/jsonTypes"; import { BoolPureControl } from "../controls/boolControl"; import { millisecondsControl } from "../controls/millisecondControl"; import { paramsMillisecondsControl } from "../controls/paramsControl"; -import { NameConfig, withExposingConfigs } from "../generators/withExposing"; +import { DepsConfig, NameConfig, withExposingConfigs } from "../generators/withExposing"; import { HttpQuery } from "./httpQuery/httpQuery"; import { StreamQuery } from "./httpQuery/streamQuery"; import { QueryConfirmationModal } from "./queryComp/queryConfirmationModal"; @@ -75,6 +75,7 @@ import { QueryNotificationControl } from "./queryComp/queryNotificationControl"; import { QueryPropertyView } from "./queryComp/queryPropertyView"; import { getTriggerType, onlyManualTrigger } from "./queryCompUtils"; import { messageInstance } from "lowcoder-design/src/components/GlobalInstances"; +import {VariablesComp} from "@lowcoder-ee/comps/queries/queryComp/variablesComp"; const latestExecution: Record = {}; @@ -153,6 +154,7 @@ const childrenMap = { defaultValue: 10 * 1000, }), confirmationModal: QueryConfirmationModal, + variables: VariablesComp, periodic: BoolPureControl, periodicTime: millisecondsControl({ defaultValue: Number.NaN, @@ -361,6 +363,8 @@ QueryCompTmp = class extends QueryCompTmp { } if (action.type === CompActionTypes.EXECUTE_QUERY) { if (getReduceContext().disableUpdateState) return this; + if(!action.args) action.args = this.children.variables.children.variables.toJsonValue().reduce((acc, curr) => Object.assign(acc, {[curr.key as string]:curr.value}), {}); + return this.executeQuery(action); } if (action.type === CompActionTypes.CHANGE_VALUE) { @@ -404,16 +408,21 @@ QueryCompTmp = class extends QueryCompTmp { return this; } + + + /** * Process the execution result */ private processResult(result: QueryResult, action: ExecuteQueryAction, startTime: number) { const lastQueryStartTime = this.children.lastQueryStartTime.getView(); + if (lastQueryStartTime > startTime) { // There are more new requests, ignore this result // FIXME: cancel this request in advance in the future return; } + const changeAction = multiChangeAction({ code: this.children.code.changeValueAction(result.code ?? QUERY_EXECUTION_OK), success: this.children.success.changeValueAction(result.success ?? true), @@ -470,6 +479,7 @@ QueryCompTmp = class extends QueryCompTmp { applicationId: applicationId, applicationPath: parentApplicationPath, args: action.args, + variables: action.args, timeout: this.children.timeout, callback: (result) => this.processResult(result, action, startTime) }); @@ -653,6 +663,23 @@ export const QueryComp = withExposingConfigs(QueryCompTmp, [ new NameConfig("isFetching", trans("query.isFetchingExportDesc")), new NameConfig("runTime", trans("query.runTimeExportDesc")), new NameConfig("latestEndTime", trans("query.latestEndTimeExportDesc")), + new DepsConfig( + "variable", + (children: any) => { + return {data: children.variables.children.variables.node()}; + }, + (input) => { + if (!input.data) { + return undefined; + } + const newNode = Object.values(input.data) + .filter((kvNode: any) => kvNode.key.text.value) + .map((kvNode: any) => ({[kvNode.key.text.value]: kvNode.value.text.value})) + .reduce((prev, obj) => ({...prev, ...obj}), {}); + return newNode; + }, + trans("query.variables") + ), new NameConfig("triggerType", trans("query.triggerTypeExportDesc")), ]); diff --git a/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx b/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx index 07f4ef1e0..fa0f078e1 100644 --- a/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx +++ b/client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx @@ -171,6 +171,17 @@ export function QueryPropertyView(props: { comp: InstanceType ), }, + { + key: "variables", + title: trans("query.variablesTab"), + children: ( + + + {children.variables.getPropertyView()} + + + ), + }, ] as const } tabTitle={children.name.getView()} @@ -501,6 +512,29 @@ export const QueryGeneralPropertyView = (props: { ); }; +export const QueryVariablesPropertyView = (props: { + comp: InstanceType; + placement?: PageType; +}) => { + const { comp, placement = "editor" } = props; + + const children = comp.children; + let datasourceId = children.datasourceId.getView(); + + console.log(children.datasourceId); + return ( + + + {isCompWithPropertyView(children.comp) + ? children.comp.propertyView({ + datasourceId: datasourceId, + }) + : children.comp.getPropertyView()} + + + ); +}; + function findQueryInNestedStructure( structure: any, queryName: string, diff --git a/client/packages/lowcoder/src/comps/queries/queryComp/variablesComp.tsx b/client/packages/lowcoder/src/comps/queries/queryComp/variablesComp.tsx new file mode 100644 index 000000000..87c5bd432 --- /dev/null +++ b/client/packages/lowcoder/src/comps/queries/queryComp/variablesComp.tsx @@ -0,0 +1,16 @@ +import {MultiCompBuilder, withDefault} from "../../generators"; +import {keyValueListControl} from "lowcoder-sdk"; + +export const VariablesComp = new MultiCompBuilder( + { + variables: withDefault(keyValueListControl(), [{ key: "", value: "" }]), + }, + (props) => + props.variables + ) + .setPropertyViewFn((children) => ( + <> + {children.variables.propertyView({})} + + )) + .build(); diff --git a/client/packages/lowcoder/src/comps/queries/queryCompUtils.tsx b/client/packages/lowcoder/src/comps/queries/queryCompUtils.tsx index 1971e8ec5..1203e1cfd 100644 --- a/client/packages/lowcoder/src/comps/queries/queryCompUtils.tsx +++ b/client/packages/lowcoder/src/comps/queries/queryCompUtils.tsx @@ -25,18 +25,23 @@ export function toQueryView(params: FunctionProperty[]) { applicationId: string; applicationPath: string[]; args?: Record; + variables?: any; timeout: InstanceType; }): Promise => { const { applicationId, isViewMode } = getGlobalSettings(); + const mappedVariables = Object.keys(props.variables).map(key => ({key: `query1.variable.${key}`, value: props.variables[key]})); let request: QueryExecuteRequest = { path: props.applicationPath, params: [ - ...params.map(({ key, value }) => ({ key, value: value(props.args) })), + ...params.filter(param => { + return !mappedVariables.map(v => v.key).includes(param.key); + }).map(({ key, value }) => ({ key, value: value(props.args) })), ...Object.entries(props.timeout.getView()).map(([key, value]) => ({ key, value: value(props.args), })), + ...mappedVariables, ], viewMode: !!isViewMode, }; diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 9c8cdddfa..7623177c6 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -277,6 +277,7 @@ export const en = { "moduleEvent": "Module Event", "goToApp": "Go to an other App", "queryParams": "Query Parameters", + "queryVariables": "Query Variables", "hashParams": "Hash Parameters", "showNotification": "Show a Notification", "text": "Text", @@ -705,6 +706,7 @@ export const en = { "newDatasource": "New Data Source", "generalTab": "General", "notificationTab": "Notification", + "variablesTab": "Variables", "advancedTab": "Advanced", "showFailNotification": "Show Notification on Failure", "failCondition": "Failure Conditions", diff --git a/client/packages/lowcoder/src/util/appUtils.tsx b/client/packages/lowcoder/src/util/appUtils.tsx index 5aed643ae..be38dfc22 100644 --- a/client/packages/lowcoder/src/util/appUtils.tsx +++ b/client/packages/lowcoder/src/util/appUtils.tsx @@ -32,6 +32,7 @@ export function openApp(props: { hashParams?: string; newTab?: boolean; }) { + console.log(props.queryParams) const m = matchPath(window.location.pathname, APP_EDITOR_URL); if (!m || !props.applicationId) { return; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy