Skip to content

Commit 58114c7

Browse files
author
FalkWolsky
committed
Changing to Flow API
1 parent 36c5638 commit 58114c7

File tree

5 files changed

+199
-102
lines changed

5 files changed

+199
-102
lines changed

Diff for: client/packages/lowcoder/src/api/iconFlowApi.ts

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import Api from "api/api";
2+
import axios, { AxiosInstance, AxiosPromise, AxiosRequestConfig } from "axios";
3+
import { calculateFlowCode } from "./apiUtils";
4+
5+
export interface SearchParams {
6+
query: string;
7+
asset: string;
8+
per_page: number;
9+
page: 1;
10+
sort: string;
11+
formats?: string;
12+
price?: string;
13+
}
14+
15+
export type ResponseType = {
16+
response: any;
17+
};
18+
19+
const lcHeaders = {
20+
"Lowcoder-Token": calculateFlowCode(),
21+
"Content-Type": "application/json"
22+
};
23+
24+
let axiosIns: AxiosInstance | null = null;
25+
26+
const getAxiosInstance = (clientSecret?: string) => {
27+
if (axiosIns && !clientSecret) {
28+
return axiosIns;
29+
}
30+
31+
const headers: Record<string, string> = {
32+
"Content-Type": "application/json",
33+
};
34+
35+
const apiRequestConfig: AxiosRequestConfig = {
36+
baseURL: "https://api-service.lowcoder.cloud/api/flow",
37+
headers,
38+
};
39+
40+
axiosIns = axios.create(apiRequestConfig);
41+
return axiosIns;
42+
}
43+
44+
class IconFlowApi extends Api {
45+
46+
static async secureRequest(body: any, timeout: number = 6000): Promise<any> {
47+
let response;
48+
const axiosInstance = getAxiosInstance();
49+
50+
// Create a cancel token and set timeout for cancellation
51+
const source = axios.CancelToken.source();
52+
const timeoutId = setTimeout(() => {
53+
source.cancel("Request timed out.");
54+
}, timeout);
55+
56+
// Request configuration with cancel token
57+
const requestConfig: AxiosRequestConfig = {
58+
method: "POST",
59+
withCredentials: true,
60+
data: body,
61+
cancelToken: source.token, // Add cancel token
62+
};
63+
64+
try {
65+
response = await axiosInstance.request(requestConfig);
66+
} catch (error) {
67+
if (axios.isCancel(error)) {
68+
// Retry once after timeout cancellation
69+
try {
70+
// Reset the cancel token and retry
71+
const retrySource = axios.CancelToken.source();
72+
const retryTimeoutId = setTimeout(() => {
73+
retrySource.cancel("Retry request timed out.");
74+
}, 10000);
75+
76+
response = await axiosInstance.request({
77+
...requestConfig,
78+
cancelToken: retrySource.token,
79+
});
80+
81+
clearTimeout(retryTimeoutId);
82+
} catch (retryError) {
83+
console.warn("Error at Secure Flow Request. Retry failed:", retryError);
84+
throw retryError;
85+
}
86+
} else {
87+
console.warn("Error at Secure Flow Request:", error);
88+
throw error;
89+
}
90+
} finally {
91+
clearTimeout(timeoutId); // Clear the initial timeout
92+
}
93+
94+
return response;
95+
}
96+
97+
}
98+
99+
export const searchAssets = async (searchParameters : SearchParams) => {
100+
const apiBody = {
101+
path: "webhook/scout/search-asset",
102+
data: searchParameters,
103+
method: "post",
104+
headers: lcHeaders
105+
};
106+
try {
107+
const result = await IconFlowApi.secureRequest(apiBody);
108+
return result?.response?.items?.total > 0 ? result.response.items as any : null;
109+
} catch (error) {
110+
console.error("Error searching Design Assets:", error);
111+
throw error;
112+
}
113+
};
114+
115+
export const getAssetLinks = async (uuid: string, params: Record<string, string>) => {
116+
const apiBody = {
117+
path: "webhook/scout/get-asset-links",
118+
data: params,
119+
method: "post",
120+
headers: lcHeaders
121+
};
122+
try {
123+
const result = await IconFlowApi.secureRequest(apiBody);
124+
125+
return result?.response?.items?.total > 0 ? result.response.items as any : null;
126+
} catch (error) {
127+
console.error("Error searching Design Assets:", error);
128+
throw error;
129+
}
130+
};
131+
132+
133+
/*
134+
135+
static async search(params: SearchParams): Promise<any> {
136+
let response;
137+
try {
138+
response = await getAxiosInstance().request({
139+
url: '/v3/search',
140+
method: "GET",
141+
withCredentials: false,
142+
params: {
143+
...params,
144+
},
145+
});
146+
} catch (error) {
147+
console.error(error);
148+
}
149+
return response?.data.response.items;
150+
}
151+
152+
static async download(uuid: string, params: Record<string, string>): Promise<any> {
153+
const response = await getAxiosInstance(clientSecret).request({
154+
url: `/v3/items/${uuid}/api-download?format=${params.format}`,
155+
method: "POST",
156+
withCredentials: false,
157+
});
158+
return response?.data.response.download;
159+
}
160+
161+
*/
162+
163+
export default IconFlowApi;

Diff for: client/packages/lowcoder/src/api/iconscoutApi.ts

+3-72
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,15 @@
11
import Api from "api/api";
2-
import axios, { AxiosInstance, AxiosPromise, AxiosRequestConfig } from "axios";
3-
import { GenericApiResponse } from "./apiResponses";
4-
5-
export interface SearchParams {
6-
query: string;
7-
product_type: string;
8-
asset: string;
9-
per_page: number;
10-
page: 1;
11-
sort: string;
12-
formats?: string;
13-
price?: string;
14-
}
2+
import axios from "axios";
153

164
export type ResponseType = {
175
response: any;
186
};
197

20-
const apiUrl = "https://api.iconscout.com";
21-
const clientID = "";
22-
const clientSecret = "";
23-
const currentPage = 1;
24-
const currentQuery = '';
25-
const currentData = [];
26-
27-
let axiosIns: AxiosInstance | null = null;
28-
29-
const getAxiosInstance = (clientSecret?: string) => {
30-
if (axiosIns && !clientSecret) {
31-
return axiosIns;
32-
}
33-
34-
const headers: Record<string, string> = {
35-
"Content-Type": "application/json",
36-
"Client-ID": clientID,
37-
}
38-
if (clientSecret) {
39-
headers['Client-Secret'] = clientSecret;
40-
}
41-
const apiRequestConfig: AxiosRequestConfig = {
42-
baseURL: `${apiUrl}`,
43-
headers,
44-
withCredentials: true,
45-
};
46-
47-
axiosIns = axios.create(apiRequestConfig);
48-
return axiosIns;
49-
}
50-
51-
class IconscoutApi extends Api {
52-
static async search(params: SearchParams): Promise<any> {
53-
let response;
54-
try {
55-
response = await getAxiosInstance().request({
56-
url: '/v3/search',
57-
method: "GET",
58-
withCredentials: false,
59-
params: {
60-
...params,
61-
},
62-
});
63-
} catch (error) {
64-
console.error(error);
65-
}
66-
return response?.data.response.items;
67-
}
68-
69-
static async download(uuid: string, params: Record<string, string>): Promise<any> {
70-
const response = await getAxiosInstance(clientSecret).request({
71-
url: `/v3/items/${uuid}/api-download?format=${params.format}`,
72-
method: "POST",
73-
withCredentials: false,
74-
});
75-
return response?.data.response.download;
76-
}
77-
8+
class IconScoutApi extends Api {
789
static async downloadAsset(url: string): Promise<any> {
7910
const response = await axios.get(url, {responseType: 'blob'})
8011
return response?.data;
8112
}
8213
}
8314

84-
export default IconscoutApi;
15+
export default IconScoutApi;

Diff for: client/packages/lowcoder/src/api/subscriptionApi.ts

-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import Api from "api/api";
22
import axios, { AxiosInstance, AxiosRequestConfig, CancelToken } from "axios";
3-
import { useDispatch, useSelector } from "react-redux";
4-
import { useEffect, useState} from "react";
53
import { calculateFlowCode } from "./apiUtils";
6-
import { fetchGroupsAction, fetchOrgUsersAction } from "redux/reduxActions/orgActions";
7-
import { getOrgUsers } from "redux/selectors/orgSelectors";
8-
import { AppState } from "@lowcoder-ee/redux/reducers";
94
import type {
105
LowcoderNewCustomer,
116
LowcoderSearchCustomer,

Diff for: client/packages/lowcoder/src/comps/controls/iconscoutControl.tsx

+18-10
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ import styled from "styled-components";
1717
import Popover from "antd/es/popover";
1818
import { CloseIcon, SearchIcon } from "icons";
1919
import Draggable from "react-draggable";
20-
import IconscoutApi, { SearchParams } from "api/iconscoutApi";
20+
import IconScoutApi from "@lowcoder-ee/api/iconScoutApi";
21+
import { searchAssets, getAssetLinks, SearchParams } from "@lowcoder-ee/api/iconFlowApi";
2122
import List, { ListRowProps } from "react-virtualized/dist/es/List";
2223
import { debounce } from "lodash";
2324
import Spin from "antd/es/spin";
@@ -204,7 +205,6 @@ export type IconScoutAsset = {
204205

205206
const IconScoutSearchParams: SearchParams = {
206207
query: '',
207-
product_type: 'item',
208208
asset: 'icon',
209209
per_page: 25,
210210
page: 1,
@@ -240,13 +240,13 @@ export const IconPicker = (props: {
240240

241241
const fetchResults = async (query: string) => {
242242
setLoading(true);
243-
const freeResult = await IconscoutApi.search({
243+
const freeResult = await searchAssets({
244244
...IconScoutSearchParams,
245245
asset: props.assetType,
246246
price: 'free',
247247
query,
248248
});
249-
const premiumResult = await IconscoutApi.search({
249+
const premiumResult = await searchAssets({
250250
...IconScoutSearchParams,
251251
asset: props.assetType,
252252
price: 'premium',
@@ -263,7 +263,7 @@ export const IconPicker = (props: {
263263
) => {
264264
try {
265265
if (uuid && downloadUrl) {
266-
const json = await IconscoutApi.downloadAsset(downloadUrl);
266+
const json = await IconScoutApi.downloadAsset(downloadUrl);
267267
getBase64(json, (url: string) => {
268268
callback(url);
269269
});
@@ -277,7 +277,7 @@ export const IconPicker = (props: {
277277
const fetchDownloadUrl = async (uuid: string, preview: string) => {
278278
try {
279279
setDownloading(true);
280-
const result = await IconscoutApi.download(uuid, {
280+
const result = await getAssetLinks(uuid, {
281281
format: props.assetType === AssetType.LOTTIE ? 'lottie' : 'svg',
282282
});
283283

@@ -291,10 +291,18 @@ export const IconPicker = (props: {
291291
}
292292
}
293293

294-
const handleChange = debounce((e) => {
295-
fetchResults(e.target.value);
296-
setSearchText(e.target.value);
297-
}, 500);
294+
const handleChange = (e: { target: { value: any; }; }) => {
295+
const query = e.target.value;
296+
setSearchText(query); // Update search text immediately
297+
298+
if (query.length > 2) {
299+
debouncedFetchResults(query); // Trigger search only for >2 characters
300+
} else {
301+
setSearchResults([]); // Clear results if input is too short
302+
}
303+
};
304+
305+
const debouncedFetchResults = useMemo(() => debounce(fetchResults, 700), []);
298306

299307
const rowRenderer = useCallback(
300308
(p: ListRowProps) => (

0 commit comments

Comments
 (0)