ui-soxo-bootstrap-core 2.6.1-dev.11 → 2.6.1-dev.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/components/landing-api/landing-api.js +66 -2
- package/core/components/landing-api/landing-api.scss +22 -0
- package/core/lib/models/forms/components/form-creator/form-creator.scss +1 -1
- package/core/models/core-scripts/core-scripts.js +134 -135
- package/core/models/menus/components/menu-lists/menu-lists.js +49 -46
- package/core/modules/reporting/components/reporting-dashboard/adavance-search/advance-search.js +49 -168
- package/core/modules/reporting/components/reporting-dashboard/adavance-search/advance-search.scss +76 -0
- package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.js +187 -185
- package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.scss +7 -0
- package/core/modules/steps/action-buttons.js +6 -0
- package/core/modules/steps/action-buttons.scss +9 -3
- package/core/modules/steps/steps.js +46 -5
- package/core/modules/steps/steps.scss +82 -13
- package/package.json +1 -1
package/core/modules/reporting/components/reporting-dashboard/adavance-search/advance-search.js
CHANGED
|
@@ -1,137 +1,20 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
3
|
-
// import React, { useState, useEffect, useRef } from "react";
|
|
4
|
-
// import { Select, Checkbox, Input, Spin } from "antd";
|
|
5
|
-
// import { CoreScripts } from "../../../../../models";
|
|
6
|
-
|
|
7
|
-
// const { Search } = Input;
|
|
8
|
-
|
|
9
|
-
// export default function AdvancedSearchSelect({ field, value = [], onChange }) {
|
|
10
|
-
// const [searchResults, setSearchResults] = useState([]); // only API results
|
|
11
|
-
// const [selectedItems, setSelectedItems] = useState(value); // persisted selections
|
|
12
|
-
// const [loading, setLoading] = useState(false);
|
|
13
|
-
// const debounceRef = useRef(null);
|
|
14
|
-
|
|
15
|
-
// // Sync selectedItems if parent value changes externally
|
|
16
|
-
// useEffect(() => {
|
|
17
|
-
// setSelectedItems(value);
|
|
18
|
-
// }, [value]);
|
|
19
|
-
|
|
20
|
-
// const loadOptions = async (searchText = "") => {
|
|
21
|
-
// try {
|
|
22
|
-
// setLoading(true);
|
|
23
|
-
|
|
24
|
-
// let query = field?.search_query || "";
|
|
25
|
-
// query = query.replace("@search_text;", searchText || "");
|
|
26
|
-
|
|
27
|
-
// const res = await CoreScripts.getQuery({ script: query });
|
|
28
|
-
// const data = Array.isArray(res) ? res[0] : [];
|
|
29
|
-
// const apiValues = data?.map((r) => r[field.field]) || [];
|
|
30
|
-
|
|
31
|
-
// setSearchResults(apiValues);
|
|
32
|
-
// } catch (error) {
|
|
33
|
-
// console.error("Search API error", error);
|
|
34
|
-
// } finally {
|
|
35
|
-
// setLoading(false);
|
|
36
|
-
// }
|
|
37
|
-
// };
|
|
38
|
-
|
|
39
|
-
// useEffect(() => {
|
|
40
|
-
// loadOptions("");
|
|
41
|
-
// }, [field]);
|
|
42
|
-
|
|
43
|
-
// const handleSearch = (text) => {
|
|
44
|
-
// if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
45
|
-
// debounceRef.current = setTimeout(() => loadOptions(text), 400);
|
|
46
|
-
// };
|
|
47
|
-
|
|
48
|
-
// const toggleValue = (checked, item) => {
|
|
49
|
-
// let newValues;
|
|
50
|
-
|
|
51
|
-
// if (checked) {
|
|
52
|
-
// newValues = [...selectedItems, item];
|
|
53
|
-
// } else {
|
|
54
|
-
// newValues = selectedItems.filter((v) => v !== item);
|
|
55
|
-
// }
|
|
56
|
-
|
|
57
|
-
// setSelectedItems(newValues); // update local persisted state immediately
|
|
58
|
-
// onChange(newValues);
|
|
59
|
-
// };
|
|
60
|
-
|
|
61
|
-
// // Merge: selected items always on top, then search results (excluding already selected)
|
|
62
|
-
// const displayOptions = [
|
|
63
|
-
// ...selectedItems,
|
|
64
|
-
// ...searchResults.filter((item) => !selectedItems.includes(item)),
|
|
65
|
-
// ];
|
|
66
|
-
|
|
67
|
-
// return (
|
|
68
|
-
// <Select
|
|
69
|
-
// mode="multiple"
|
|
70
|
-
// value={value}
|
|
71
|
-
// style={{ width: 250 }}
|
|
72
|
-
// placeholder={field.caption}
|
|
73
|
-
// allowClear
|
|
74
|
-
// maxTagCount={0}
|
|
75
|
-
// onChange={onChange}
|
|
76
|
-
// maxTagPlaceholder={() => (
|
|
77
|
-
// <span style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
|
78
|
-
// {field.caption}
|
|
79
|
-
// <span
|
|
80
|
-
// style={{
|
|
81
|
-
// background: "#e6f0ff",
|
|
82
|
-
// color: "#1677ff",
|
|
83
|
-
// borderRadius: "10px",
|
|
84
|
-
// padding: "0 8px",
|
|
85
|
-
// fontWeight: 600,
|
|
86
|
-
// fontSize: 12,
|
|
87
|
-
// }}
|
|
88
|
-
// >
|
|
89
|
-
// {value?.length || 0}
|
|
90
|
-
// </span>
|
|
91
|
-
// </span>
|
|
92
|
-
// )}
|
|
93
|
-
// dropdownRender={() => (
|
|
94
|
-
// <div style={{ padding: 10 }}>
|
|
95
|
-
// <Search
|
|
96
|
-
// placeholder={`Search ${field.caption}`}
|
|
97
|
-
// onChange={(e) => handleSearch(e.target.value)}
|
|
98
|
-
// />
|
|
99
|
-
|
|
100
|
-
// <div style={{ maxHeight: 200, overflowY: "auto", marginTop: 10 }}>
|
|
101
|
-
// {loading ? (
|
|
102
|
-
// <Spin />
|
|
103
|
-
// ) : (
|
|
104
|
-
// displayOptions.map((item) => (
|
|
105
|
-
// <div key={item} style={{ marginBottom: 6 }}>
|
|
106
|
-
// <Checkbox
|
|
107
|
-
// checked={selectedItems.includes(item)}
|
|
108
|
-
// onChange={(e) => toggleValue(e.target.checked, item)}
|
|
109
|
-
// >
|
|
110
|
-
// {item}
|
|
111
|
-
// </Checkbox>
|
|
112
|
-
// </div>
|
|
113
|
-
// ))
|
|
114
|
-
// )}
|
|
115
|
-
// </div>
|
|
116
|
-
// </div>
|
|
117
|
-
// )}
|
|
118
|
-
// />
|
|
119
|
-
// );
|
|
120
|
-
// }
|
|
121
|
-
|
|
122
2
|
import React, { useState, useEffect, useRef } from "react";
|
|
123
3
|
import { Select, Checkbox, Input, Spin } from "antd";
|
|
124
4
|
import { CoreScripts } from "../../../../../models";
|
|
5
|
+
import "./advance-search.scss";
|
|
125
6
|
|
|
126
7
|
const { Search } = Input;
|
|
127
8
|
|
|
128
|
-
export default function AdvancedSearchSelect({ field, value = [], onChange }) {
|
|
129
|
-
|
|
130
|
-
const
|
|
9
|
+
export default function AdvancedSearchSelect({ reportId, field, value = [], onChange ,onReset}) {
|
|
10
|
+
|
|
11
|
+
const isSearchQuery = !!field.search_query;
|
|
12
|
+
|
|
13
|
+
const [searchResults, setSearchResults] = useState([]);
|
|
14
|
+
const [selectedItems, setSelectedItems] = useState(value);
|
|
131
15
|
const [loading, setLoading] = useState(false);
|
|
132
16
|
const debounceRef = useRef(null);
|
|
133
17
|
|
|
134
|
-
// Sync selectedItems if parent value changes externally
|
|
135
18
|
useEffect(() => {
|
|
136
19
|
setSelectedItems(value);
|
|
137
20
|
}, [value]);
|
|
@@ -140,11 +23,14 @@ export default function AdvancedSearchSelect({ field, value = [], onChange }) {
|
|
|
140
23
|
try {
|
|
141
24
|
setLoading(true);
|
|
142
25
|
|
|
143
|
-
|
|
144
|
-
|
|
26
|
+
const formBody = {
|
|
27
|
+
script_id: reportId,
|
|
28
|
+
search_field: field.field,
|
|
29
|
+
search_condition: searchText,
|
|
30
|
+
};
|
|
145
31
|
|
|
146
|
-
const res = await CoreScripts.
|
|
147
|
-
const data = Array.isArray(res) ? res
|
|
32
|
+
const res = await CoreScripts.getQuerySeacch(formBody);
|
|
33
|
+
const data = Array.isArray(res.data) ? res.data : [];
|
|
148
34
|
const apiValues = data?.map((r) => r[field.field]) || [];
|
|
149
35
|
|
|
150
36
|
setSearchResults(apiValues);
|
|
@@ -156,7 +42,7 @@ export default function AdvancedSearchSelect({ field, value = [], onChange }) {
|
|
|
156
42
|
};
|
|
157
43
|
|
|
158
44
|
useEffect(() => {
|
|
159
|
-
loadOptions("");
|
|
45
|
+
if (isSearchQuery) loadOptions("");
|
|
160
46
|
}, [field]);
|
|
161
47
|
|
|
162
48
|
const handleSearch = (text) => {
|
|
@@ -167,11 +53,8 @@ export default function AdvancedSearchSelect({ field, value = [], onChange }) {
|
|
|
167
53
|
const toggleValue = (checked, item) => {
|
|
168
54
|
let newValues;
|
|
169
55
|
|
|
170
|
-
if (checked)
|
|
171
|
-
|
|
172
|
-
} else {
|
|
173
|
-
newValues = selectedItems.filter((v) => v !== item);
|
|
174
|
-
}
|
|
56
|
+
if (checked) newValues = [...selectedItems, item];
|
|
57
|
+
else newValues = selectedItems.filter((v) => v !== item);
|
|
175
58
|
|
|
176
59
|
setSelectedItems(newValues);
|
|
177
60
|
onChange(newValues);
|
|
@@ -180,53 +63,67 @@ export default function AdvancedSearchSelect({ field, value = [], onChange }) {
|
|
|
180
63
|
const handleReset = () => {
|
|
181
64
|
setSelectedItems([]);
|
|
182
65
|
onChange([]);
|
|
66
|
+
// if (onReset) {
|
|
67
|
+
onReset(); // 🔥 trigger dashboard refresh
|
|
68
|
+
// }
|
|
183
69
|
};
|
|
184
70
|
|
|
185
|
-
// Merge: selected items always on top, then search results
|
|
186
71
|
const displayOptions = [
|
|
187
72
|
...selectedItems,
|
|
188
73
|
...searchResults.filter((item) => !selectedItems.includes(item)),
|
|
189
74
|
];
|
|
190
75
|
|
|
76
|
+
const isActive = value && value.length > 0;
|
|
77
|
+
|
|
78
|
+
// -------- INPUT MODE --------
|
|
79
|
+
if (!isSearchQuery) {
|
|
80
|
+
return (
|
|
81
|
+
<Input
|
|
82
|
+
className={`advanced-search-input ${isActive ? "advanced-search-active" : ""}`}
|
|
83
|
+
placeholder={`Search ${field.caption}`}
|
|
84
|
+
// The parent provides an array for `value`.
|
|
85
|
+
// We take the first element for the input's display value.
|
|
86
|
+
value={value[0] || ""}
|
|
87
|
+
onChange={(e) => {
|
|
88
|
+
const text = e.target.value;
|
|
89
|
+
// Always pass an array back to the parent to be consistent with the Select mode.
|
|
90
|
+
onChange(text ? [text] : []);
|
|
91
|
+
}}
|
|
92
|
+
/>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// -------- SELECT MODE --------
|
|
191
97
|
return (
|
|
192
98
|
<Select
|
|
99
|
+
className={`advanced-search-select ${isActive ? "advanced-search-active" : ""}`}
|
|
193
100
|
mode="multiple"
|
|
194
101
|
value={value}
|
|
195
|
-
style={{ width: 250 }}
|
|
196
102
|
placeholder={field.caption}
|
|
197
103
|
allowClear
|
|
198
104
|
maxTagCount={0}
|
|
199
105
|
onChange={onChange}
|
|
200
106
|
maxTagPlaceholder={() => (
|
|
201
|
-
<span
|
|
107
|
+
<span className="tag-placeholder">
|
|
202
108
|
{field.caption}
|
|
203
|
-
<span
|
|
204
|
-
style={{
|
|
205
|
-
background: "#e6f0ff",
|
|
206
|
-
color: "#1677ff",
|
|
207
|
-
borderRadius: "10px",
|
|
208
|
-
padding: "0 8px",
|
|
209
|
-
fontWeight: 600,
|
|
210
|
-
fontSize: 12,
|
|
211
|
-
}}
|
|
212
|
-
>
|
|
109
|
+
<span className="tag-placeholder-count">
|
|
213
110
|
{value?.length || 0}
|
|
214
111
|
</span>
|
|
215
112
|
</span>
|
|
216
113
|
)}
|
|
217
114
|
dropdownRender={() => (
|
|
218
|
-
<div
|
|
115
|
+
<div className="dropdown-content">
|
|
219
116
|
<Search
|
|
220
117
|
placeholder={`Search ${field.caption}`}
|
|
221
118
|
onChange={(e) => handleSearch(e.target.value)}
|
|
222
119
|
/>
|
|
223
120
|
|
|
224
|
-
<div
|
|
121
|
+
<div className="dropdown-options-list">
|
|
225
122
|
{loading ? (
|
|
226
123
|
<Spin />
|
|
227
124
|
) : (
|
|
228
125
|
displayOptions.map((item) => (
|
|
229
|
-
<div key={item}
|
|
126
|
+
<div key={item} className="dropdown-option-item">
|
|
230
127
|
<Checkbox
|
|
231
128
|
checked={selectedItems.includes(item)}
|
|
232
129
|
onChange={(e) => toggleValue(e.target.checked, item)}
|
|
@@ -238,24 +135,8 @@ export default function AdvancedSearchSelect({ field, value = [], onChange }) {
|
|
|
238
135
|
)}
|
|
239
136
|
</div>
|
|
240
137
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
style={{
|
|
244
|
-
display: "flex",
|
|
245
|
-
justifyContent: "flex-end",
|
|
246
|
-
marginTop: 10,
|
|
247
|
-
borderTop: "1px solid #f0f0f0",
|
|
248
|
-
paddingTop: 8,
|
|
249
|
-
}}
|
|
250
|
-
>
|
|
251
|
-
<span
|
|
252
|
-
style={{
|
|
253
|
-
color: "#1677ff",
|
|
254
|
-
cursor: "pointer",
|
|
255
|
-
fontWeight: 500,
|
|
256
|
-
}}
|
|
257
|
-
onClick={handleReset}
|
|
258
|
-
>
|
|
138
|
+
<div className="dropdown-footer">
|
|
139
|
+
<span className="dropdown-reset-button" onClick={handleReset}>
|
|
259
140
|
Reset
|
|
260
141
|
</span>
|
|
261
142
|
</div>
|
package/core/modules/reporting/components/reporting-dashboard/adavance-search/advance-search.scss
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// .advanced-search-select,
|
|
2
|
+
/* Base select width */
|
|
3
|
+
.advanced-search-select {
|
|
4
|
+
width: 160px;
|
|
5
|
+
}
|
|
6
|
+
.advanced-search-input {
|
|
7
|
+
width: 160px;
|
|
8
|
+
}
|
|
9
|
+
/* Active state (when value selected) */
|
|
10
|
+
.advanced-search-select.advanced-search-active .ant-select-selector {
|
|
11
|
+
border-color: #1677ff !important;
|
|
12
|
+
box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.2) !important;
|
|
13
|
+
border-radius: 6px !important;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Input active state */
|
|
17
|
+
.advanced-search-input.advanced-search-active {
|
|
18
|
+
border-color: #1677ff !important;
|
|
19
|
+
box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.2);
|
|
20
|
+
border-radius: 6px;
|
|
21
|
+
}
|
|
22
|
+
// .advanced-search-input {
|
|
23
|
+
// width: 250px;
|
|
24
|
+
|
|
25
|
+
// &.advanced-search-active {
|
|
26
|
+
// // Antd Select and Input don't share the same border-radius property,
|
|
27
|
+
// // so we apply a wrapper style that works for both.
|
|
28
|
+
// // For more specific control, you might need to target internal antd classes.
|
|
29
|
+
// border: 1px solid #91caff !important;
|
|
30
|
+
// box-shadow: 0 0 0 1px #91caff;
|
|
31
|
+
// border-radius: 6px;
|
|
32
|
+
// }
|
|
33
|
+
// }
|
|
34
|
+
|
|
35
|
+
.tag-placeholder {
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
gap: 8px;
|
|
39
|
+
|
|
40
|
+
.tag-placeholder-count {
|
|
41
|
+
background: #e6f0ff;
|
|
42
|
+
color: #1677ff;
|
|
43
|
+
border-radius: 10px;
|
|
44
|
+
padding: 0 8px;
|
|
45
|
+
font-weight: 600;
|
|
46
|
+
font-size: 12px;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.dropdown-content {
|
|
51
|
+
padding: 10px;
|
|
52
|
+
|
|
53
|
+
.dropdown-options-list {
|
|
54
|
+
max-height: 200px;
|
|
55
|
+
overflow-y: auto;
|
|
56
|
+
margin-top: 10px;
|
|
57
|
+
|
|
58
|
+
.dropdown-option-item {
|
|
59
|
+
margin-bottom: 6px;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.dropdown-footer {
|
|
64
|
+
display: flex;
|
|
65
|
+
justify-content: flex-end;
|
|
66
|
+
margin-top: 10px;
|
|
67
|
+
border-top: 1px solid #f0f0f0;
|
|
68
|
+
padding-top: 8px;
|
|
69
|
+
|
|
70
|
+
.dropdown-reset-button {
|
|
71
|
+
color: #1677ff;
|
|
72
|
+
cursor: pointer;
|
|
73
|
+
font-weight: 500;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|