Skip to content

Commit 68d7c83

Browse files
authored
Merge pull request #1470 from lowcoder-org/feature-dataQuery
Added variables to data query
2 parents 8190bea + e43aba8 commit 68d7c83

File tree

11 files changed

+225
-69
lines changed

11 files changed

+225
-69
lines changed

client/packages/lowcoder-design/src/components/keyValueList.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,20 +76,25 @@ export const KeyValueList = (props: {
7676
list: ReactNode[];
7777
onAdd: () => void;
7878
onDelete: (item: ReactNode, index: number) => void;
79+
isStatic?: boolean;
7980
}) => (
8081
<>
8182
{props.list.map((item, index) => (
8283
<KeyValueListItem key={index /* FIXME: find a proper key instead of `index` */}>
8384
{item}
84-
<DelIcon
85-
onClick={() => props.list.length > 1 && props.onDelete(item, index)}
86-
$forbidden={props.list.length === 1}
87-
/>
85+
{!props.isStatic &&
86+
<DelIcon
87+
onClick={() => props.list.length > 1 && props.onDelete(item, index)}
88+
$forbidden={props.list.length === 1}
89+
/>
90+
}
8891
</KeyValueListItem>
8992
))}
93+
{!props.isStatic &&
9094
<AddBtn onClick={props.onAdd}>
9195
<AddIcon />
9296
{trans("addItem")}
9397
</AddBtn>
98+
}
9499
</>
95100
);

client/packages/lowcoder/src/comps/controls/actionSelector/executeQueryAction.tsx

Lines changed: 105 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,100 @@ import { BranchDiv, Dropdown } from "lowcoder-design";
77
import { BottomResTypeEnum } from "types/bottomRes";
88
import { getPromiseAfterDispatch } from "util/promiseUtils";
99
import { trans } from "i18n";
10+
import {keyValueListControl, keyValueListToSearchStr, withDefault} from "lowcoder-sdk";
11+
import {KeyValue} from "@lowcoder-ee/types/common";
12+
import { useCallback, useContext, useEffect, useMemo } from "react";
1013

14+
const ExecuteQueryPropertyView = ({
15+
comp,
16+
placement,
17+
}: {
18+
comp: any,
19+
placement?: "query" | "table"
20+
}) => {
21+
const getQueryOptions = useCallback((editorState?: EditorState) => {
22+
const options: { label: string; value: string; variable?: Record<string, string> }[] =
23+
editorState
24+
?.queryCompInfoList()
25+
.map((info) => {
26+
return {
27+
label: info.name,
28+
value: info.name,
29+
variable: info.data.variable,
30+
}
31+
})
32+
.filter(
33+
// Filter out the current query under query
34+
(option) => {
35+
if (
36+
placement === "query" &&
37+
editorState.selectedBottomResType === BottomResTypeEnum.Query
38+
) {
39+
return option.value !== editorState.selectedBottomResName;
40+
}
41+
return true;
42+
}
43+
) || [];
44+
45+
// input queries
46+
editorState
47+
?.getModuleLayoutComp()
48+
?.getInputs()
49+
.forEach((i) => {
50+
const { name, type } = i.getView();
51+
if (type === InputTypeEnum.Query) {
52+
options.push({ label: name, value: name });
53+
}
54+
});
55+
return options;
56+
}, [placement]);
57+
58+
const getVariableOptions = useCallback((editorState?: EditorState) => {
59+
return comp.children.queryVariables.propertyView({
60+
label: trans("eventHandler.queryVariables"),
61+
layout: "vertical",
62+
isStatic: true,
63+
keyFixed: true,
64+
});
65+
}, [comp.children.queryVariables.getView()])
66+
67+
return (
68+
<>
69+
<BranchDiv $type={"inline"}>
70+
<EditorContext.Consumer>
71+
{(editorState) => (
72+
<>
73+
<Dropdown
74+
showSearch={true}
75+
value={comp.children.queryName.getView()}
76+
options={getQueryOptions(editorState)}
77+
label={trans("eventHandler.selectQuery")}
78+
onChange={(value) => {
79+
const options = getQueryOptions(editorState);
80+
const selectedQuery = options.find(option => option.value === value);
81+
const variables = selectedQuery ? Object.keys(selectedQuery.variable || {}) : [];
82+
comp.dispatchChangeValueAction({
83+
queryName: value,
84+
queryVariables: variables.map((variable) => ({key: variable, value: ''})),
85+
});
86+
}}
87+
/>
88+
</>
89+
)}
90+
</EditorContext.Consumer>
91+
</BranchDiv>
92+
<BranchDiv>
93+
<EditorContext.Consumer>
94+
{(editorState) => getVariableOptions(editorState)}
95+
</EditorContext.Consumer>
96+
</BranchDiv>
97+
</>
98+
);
99+
}
11100
const ExecuteQueryTmpAction = (function () {
12101
const childrenMap = {
13102
queryName: SimpleNameComp,
103+
queryVariables: withDefault(keyValueListControl(false, [], "string"), [])
14104
};
15105
return new MultiCompBuilder(childrenMap, () => {
16106
return () => Promise.resolve(undefined as unknown);
@@ -22,6 +112,15 @@ const ExecuteQueryTmpAction = (function () {
22112
export class ExecuteQueryAction extends ExecuteQueryTmpAction {
23113
override getView() {
24114
const queryName = this.children.queryName.getView();
115+
// const queryParams = keyValueListToSearchStr(Array.isArray(this?.children?.query) ? (this.children.query as unknown as any[]).map((i: any) => i.getView() as KeyValue) : []);
116+
const result = Object.values(this.children.queryVariables.children as Record<string, {
117+
children: {
118+
key: { unevaledValue: string },
119+
value: { unevaledValue: string }
120+
}}>)
121+
.filter(item => item.children.key.unevaledValue !== "" && item.children.value.unevaledValue !== "")
122+
.map(item => ({[item.children.key.unevaledValue]: item.children.value.unevaledValue}))
123+
.reduce((acc, curr) => Object.assign(acc, curr), {});
25124
if (!queryName) {
26125
return () => Promise.resolve();
27126
}
@@ -30,9 +129,7 @@ export class ExecuteQueryAction extends ExecuteQueryTmpAction {
30129
this.dispatch,
31130
routeByNameAction(
32131
queryName,
33-
executeQueryAction({
34-
// can add context in the future
35-
})
132+
executeQueryAction({args: result})
36133
),
37134
{ notHandledError: trans("eventHandler.notHandledError") }
38135
);
@@ -46,55 +143,11 @@ export class ExecuteQueryAction extends ExecuteQueryTmpAction {
46143
}
47144

48145
propertyView({ placement }: { placement?: "query" | "table" }) {
49-
const getQueryOptions = (editorState?: EditorState) => {
50-
const options: { label: string; value: string }[] =
51-
editorState
52-
?.queryCompInfoList()
53-
.map((info) => ({
54-
label: info.name,
55-
value: info.name,
56-
}))
57-
.filter(
58-
// Filter out the current query under query
59-
(option) => {
60-
if (
61-
placement === "query" &&
62-
editorState.selectedBottomResType === BottomResTypeEnum.Query
63-
) {
64-
return option.value !== editorState.selectedBottomResName;
65-
}
66-
return true;
67-
}
68-
) || [];
69-
70-
// input queries
71-
editorState
72-
?.getModuleLayoutComp()
73-
?.getInputs()
74-
.forEach((i) => {
75-
const { name, type } = i.getView();
76-
if (type === InputTypeEnum.Query) {
77-
options.push({ label: name, value: name });
78-
}
79-
});
80-
return options;
81-
};
82146
return (
83-
<BranchDiv $type={"inline"}>
84-
<EditorContext.Consumer>
85-
{(editorState) => (
86-
<>
87-
<Dropdown
88-
showSearch={true}
89-
value={this.children.queryName.getView()}
90-
options={getQueryOptions(editorState)}
91-
label={trans("eventHandler.selectQuery")}
92-
onChange={(value) => this.dispatchChangeValueAction({ queryName: value })}
93-
/>
94-
</>
95-
)}
96-
</EditorContext.Consumer>
97-
</BranchDiv>
98-
);
147+
<ExecuteQueryPropertyView
148+
comp={this}
149+
placement={placement}
150+
/>
151+
)
99152
}
100153
}

client/packages/lowcoder/src/comps/controls/actionSelector/goToURLAction.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const childrenMap = {
2020
};
2121

2222
export const GoToURLAction = new MultiCompBuilder(childrenMap, (props) => {
23-
return () => {
23+
return () => {
2424
const queryParams = keyValueListToSearchStr(
2525
props.query.map((i) => i.getView() as KeyValue)
2626
);

client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,18 @@ const EventHandlerControlPropertyView = (props: {
167167
if (eventConfigs.length === 0) {
168168
return;
169169
}
170+
171+
const queryVariables = editorState
172+
?.selectedOrFirstQueryComp()
173+
?.children.variables.children.variables.toJsonValue();
174+
170175
const queryExecHandler = {
171176
compType: "executeQuery",
172177
comp: {
173178
queryName: editorState
174179
?.selectedOrFirstQueryComp()
175180
?.children.name.getView(),
181+
queryVariables: queryVariables?.map((variable) => ({...variable, value: ''})),
176182
},
177183
};
178184
const messageHandler = {

client/packages/lowcoder/src/comps/controls/keyValueControl.tsx

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ export type KeyValueControlParams = ControlParams & {
4747
typeTooltip?: ReactNode;
4848
keyFlexBasics?: number;
4949
valueFlexBasics?: number;
50+
isStatic?: boolean;
51+
keyFixed?: boolean;
5052
};
5153

5254
/**
@@ -82,16 +84,20 @@ function keyValueControl<T extends OptionsType>(
8284
return (
8385
<KeyValueWrapper>
8486
<KeyWrapper $flexBasics={params.keyFlexBasics}>
85-
{this.children.key.propertyView({ placeholder: "key", indentWithTab: false })}
86-
{hasType && params.showType && (
87-
<TypeWrapper>
88-
{this.children.type.propertyView({
89-
placeholder: "key",
90-
indentWithTab: false,
91-
tooltip: params.typeTooltip,
92-
})}
93-
</TypeWrapper>
94-
)}
87+
{params.keyFixed?
88+
<>{this.children.key.getView()}</>
89+
:<>
90+
{this.children.key.propertyView({ placeholder: "key", indentWithTab: false })}
91+
{hasType && params.showType && (
92+
<TypeWrapper>
93+
{this.children.type.propertyView({
94+
placeholder: "key",
95+
indentWithTab: false,
96+
tooltip: params.typeTooltip,
97+
})}
98+
</TypeWrapper>
99+
)}
100+
</>}
95101
</KeyWrapper>
96102
<ValueWrapper $flexBasics={params.valueFlexBasics}>
97103
{this.children.value.propertyView({
@@ -136,6 +142,7 @@ export function keyValueListControl<T extends OptionsType>(
136142
list={this.getView().map((child) => child.propertyView(params))}
137143
onAdd={() => this.dispatch(this.pushAction({}))}
138144
onDelete={(item, index) => this.dispatch(this.deleteAction(index))}
145+
isStatic={params.isStatic}
139146
/>
140147
</ControlPropertyViewWrapper>
141148
);

client/packages/lowcoder/src/comps/queries/queryComp.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,15 @@ import { JSONObject, JSONValue } from "../../util/jsonTypes";
6767
import { BoolPureControl } from "../controls/boolControl";
6868
import { millisecondsControl } from "../controls/millisecondControl";
6969
import { paramsMillisecondsControl } from "../controls/paramsControl";
70-
import { NameConfig, withExposingConfigs } from "../generators/withExposing";
70+
import { DepsConfig, NameConfig, withExposingConfigs } from "../generators/withExposing";
7171
import { HttpQuery } from "./httpQuery/httpQuery";
7272
import { StreamQuery } from "./httpQuery/streamQuery";
7373
import { QueryConfirmationModal } from "./queryComp/queryConfirmationModal";
7474
import { QueryNotificationControl } from "./queryComp/queryNotificationControl";
7575
import { QueryPropertyView } from "./queryComp/queryPropertyView";
7676
import { getTriggerType, onlyManualTrigger } from "./queryCompUtils";
7777
import { messageInstance } from "lowcoder-design/src/components/GlobalInstances";
78+
import {VariablesComp} from "@lowcoder-ee/comps/queries/queryComp/variablesComp";
7879

7980
const latestExecution: Record<string, string> = {};
8081

@@ -153,6 +154,7 @@ const childrenMap = {
153154
defaultValue: 10 * 1000,
154155
}),
155156
confirmationModal: QueryConfirmationModal,
157+
variables: VariablesComp,
156158
periodic: BoolPureControl,
157159
periodicTime: millisecondsControl({
158160
defaultValue: Number.NaN,
@@ -361,6 +363,8 @@ QueryCompTmp = class extends QueryCompTmp {
361363
}
362364
if (action.type === CompActionTypes.EXECUTE_QUERY) {
363365
if (getReduceContext().disableUpdateState) return this;
366+
if(!action.args) action.args = this.children.variables.children.variables.toJsonValue().reduce((acc, curr) => Object.assign(acc, {[curr.key as string]:curr.value}), {});
367+
364368
return this.executeQuery(action);
365369
}
366370
if (action.type === CompActionTypes.CHANGE_VALUE) {
@@ -404,16 +408,21 @@ QueryCompTmp = class extends QueryCompTmp {
404408
return this;
405409
}
406410

411+
412+
413+
407414
/**
408415
* Process the execution result
409416
*/
410417
private processResult(result: QueryResult, action: ExecuteQueryAction, startTime: number) {
411418
const lastQueryStartTime = this.children.lastQueryStartTime.getView();
419+
412420
if (lastQueryStartTime > startTime) {
413421
// There are more new requests, ignore this result
414422
// FIXME: cancel this request in advance in the future
415423
return;
416424
}
425+
417426
const changeAction = multiChangeAction({
418427
code: this.children.code.changeValueAction(result.code ?? QUERY_EXECUTION_OK),
419428
success: this.children.success.changeValueAction(result.success ?? true),
@@ -470,6 +479,7 @@ QueryCompTmp = class extends QueryCompTmp {
470479
applicationId: applicationId,
471480
applicationPath: parentApplicationPath,
472481
args: action.args,
482+
variables: action.args,
473483
timeout: this.children.timeout,
474484
callback: (result) => this.processResult(result, action, startTime)
475485
});
@@ -653,6 +663,23 @@ export const QueryComp = withExposingConfigs(QueryCompTmp, [
653663
new NameConfig("isFetching", trans("query.isFetchingExportDesc")),
654664
new NameConfig("runTime", trans("query.runTimeExportDesc")),
655665
new NameConfig("latestEndTime", trans("query.latestEndTimeExportDesc")),
666+
new DepsConfig(
667+
"variable",
668+
(children: any) => {
669+
return {data: children.variables.children.variables.node()};
670+
},
671+
(input) => {
672+
if (!input.data) {
673+
return undefined;
674+
}
675+
const newNode = Object.values(input.data)
676+
.filter((kvNode: any) => kvNode.key.text.value)
677+
.map((kvNode: any) => ({[kvNode.key.text.value]: kvNode.value.text.value}))
678+
.reduce((prev, obj) => ({...prev, ...obj}), {});
679+
return newNode;
680+
},
681+
trans("query.variables")
682+
),
656683
new NameConfig("triggerType", trans("query.triggerTypeExportDesc")),
657684
]);
658685

0 commit comments

Comments
 (0)
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