strapi-plugin-magic-mark 3.3.2 → 3.4.0
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/dist/_chunks/{App-DFDDcq8K.js → App-DNyxeldt.js} +2 -62
- package/dist/_chunks/{App-CozIqdTt.mjs → App-D_Vllkur.mjs} +1 -61
- package/dist/_chunks/{UpgradePage-9godO_5E.mjs → UpgradePage-DuyIskve.mjs} +1 -1
- package/dist/_chunks/{UpgradePage-CwYDN8bT.js → UpgradePage-SzlmS6po.js} +1 -1
- package/dist/_chunks/{index-DCsuhvUc.js → index-CBwb0AEf.js} +1081 -161
- package/dist/_chunks/{index-DNoxLWi0.mjs → index-QkINaIgJ.mjs} +1083 -163
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/package.json +3 -3
|
@@ -160,7 +160,7 @@ const FilterChip = styled__default.default.div`
|
|
|
160
160
|
gap: 4px;
|
|
161
161
|
color: ${(props) => props.theme.colors.neutral800};
|
|
162
162
|
`;
|
|
163
|
-
const LogicBadge = styled__default.default.span`
|
|
163
|
+
const LogicBadge$1 = styled__default.default.span`
|
|
164
164
|
font-weight: bold;
|
|
165
165
|
color: ${(props) => props.logic === "OR" ? props.theme.colors.warning700 : props.theme.colors.primary700};
|
|
166
166
|
font-size: 10px;
|
|
@@ -197,7 +197,7 @@ const FilterPreview = ({ query }) => {
|
|
|
197
197
|
parsed.filters.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { marginBottom: 2, children: [
|
|
198
198
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: "Filters:" }),
|
|
199
199
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { wrap: "wrap", gap: 1, children: parsed.filters.map((filter, idx) => /* @__PURE__ */ jsxRuntime.jsxs(FilterChip, { logic: filter.logic, children: [
|
|
200
|
-
filter.logic && /* @__PURE__ */ jsxRuntime.jsx(LogicBadge, { logic: filter.logic, children: filter.logic }),
|
|
200
|
+
filter.logic && /* @__PURE__ */ jsxRuntime.jsx(LogicBadge$1, { logic: filter.logic, children: filter.logic }),
|
|
201
201
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
202
202
|
filter.field,
|
|
203
203
|
" ",
|
|
@@ -360,7 +360,7 @@ const ModalBody = styled__default.default.div`
|
|
|
360
360
|
overflow-y: auto;
|
|
361
361
|
flex: 1;
|
|
362
362
|
`;
|
|
363
|
-
const ModalFooter = styled__default.default.div`
|
|
363
|
+
const ModalFooter$1 = styled__default.default.div`
|
|
364
364
|
padding: 16px 28px;
|
|
365
365
|
background: ${(p) => p.theme.colors.neutral100};
|
|
366
366
|
border-top: 1px solid rgba(128, 128, 128, 0.25);
|
|
@@ -1012,7 +1012,7 @@ const CreateEditModal = ({
|
|
|
1012
1012
|
)
|
|
1013
1013
|
] })
|
|
1014
1014
|
] }),
|
|
1015
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ModalFooter, { children: [
|
|
1015
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ModalFooter$1, { children: [
|
|
1016
1016
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({ id: `${pluginId2}.button.cancel`, defaultMessage: "Cancel" }) }),
|
|
1017
1017
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleSubmit, loading: isSubmitting, children: isEditing ? formatMessage({ id: `${pluginId2}.button.update`, defaultMessage: "Update" }) : formatMessage({ id: `${pluginId2}.button.save`, defaultMessage: "Save Bookmark" }) })
|
|
1018
1018
|
] })
|
|
@@ -1459,7 +1459,8 @@ const SelectContainer = styled__default.default.div`
|
|
|
1459
1459
|
`;
|
|
1460
1460
|
const SelectButton = styled__default.default.button`
|
|
1461
1461
|
width: 100%;
|
|
1462
|
-
|
|
1462
|
+
height: 32px;
|
|
1463
|
+
padding: 0 36px 0 12px;
|
|
1463
1464
|
border: 1px solid ${(props) => props.$isOpen ? "#4945ff" : "rgba(128, 128, 128, 0.25)"};
|
|
1464
1465
|
border-radius: 4px;
|
|
1465
1466
|
background: ${(p) => p.theme.colors.neutral0};
|
|
@@ -1482,12 +1483,13 @@ const SelectButton = styled__default.default.button`
|
|
|
1482
1483
|
}
|
|
1483
1484
|
|
|
1484
1485
|
@media (max-width: 768px) {
|
|
1485
|
-
|
|
1486
|
+
height: 32px;
|
|
1487
|
+
padding: 0 32px 0 10px;
|
|
1486
1488
|
font-size: 13px;
|
|
1487
1489
|
}
|
|
1488
1490
|
`;
|
|
1489
1491
|
const SelectText = styled__default.default.span`
|
|
1490
|
-
color: ${(props) => props.$isPlaceholder ?
|
|
1492
|
+
color: ${(props) => props.$isPlaceholder ? props.theme.colors.neutral500 : props.theme.colors.neutral800};
|
|
1491
1493
|
overflow: hidden;
|
|
1492
1494
|
text-overflow: ellipsis;
|
|
1493
1495
|
white-space: nowrap;
|
|
@@ -1508,7 +1510,7 @@ const DropdownList = styled__default.default.div`
|
|
|
1508
1510
|
top: ${(props) => props.top}px;
|
|
1509
1511
|
left: ${(props) => props.left}px;
|
|
1510
1512
|
width: ${(props) => props.width}px;
|
|
1511
|
-
max-height:
|
|
1513
|
+
max-height: 400px;
|
|
1512
1514
|
overflow-y: auto;
|
|
1513
1515
|
background: ${(p) => p.theme.colors.neutral0};
|
|
1514
1516
|
border: 1px solid rgba(128, 128, 128, 0.25);
|
|
@@ -1518,14 +1520,14 @@ const DropdownList = styled__default.default.div`
|
|
|
1518
1520
|
display: ${(props) => props.$isOpen ? "block" : "none"};
|
|
1519
1521
|
|
|
1520
1522
|
@media (max-width: 768px) {
|
|
1521
|
-
max-height:
|
|
1523
|
+
max-height: 320px;
|
|
1522
1524
|
}
|
|
1523
1525
|
`;
|
|
1524
1526
|
const DropdownItem = styled__default.default.button`
|
|
1525
1527
|
width: 100%;
|
|
1526
1528
|
padding: 10px 12px;
|
|
1527
1529
|
border: none;
|
|
1528
|
-
background: ${(props) => props.$isSelected ? "
|
|
1530
|
+
background: ${(props) => props.$isSelected ? "rgba(73, 69, 255, 0.06)" : props.theme.colors.neutral0};
|
|
1529
1531
|
text-align: left;
|
|
1530
1532
|
cursor: pointer;
|
|
1531
1533
|
font-size: 14px;
|
|
@@ -1552,6 +1554,8 @@ const SearchInput = styled__default.default.input`
|
|
|
1552
1554
|
border: none;
|
|
1553
1555
|
border-bottom: 1px solid rgba(128, 128, 128, 0.25);
|
|
1554
1556
|
font-size: 14px;
|
|
1557
|
+
background: ${(p) => p.theme.colors.neutral0};
|
|
1558
|
+
color: ${(p) => p.theme.colors.neutral800};
|
|
1555
1559
|
|
|
1556
1560
|
&:focus {
|
|
1557
1561
|
outline: none;
|
|
@@ -1763,18 +1767,110 @@ const useRelationSchema = () => {
|
|
|
1763
1767
|
errors
|
|
1764
1768
|
};
|
|
1765
1769
|
};
|
|
1766
|
-
const
|
|
1770
|
+
const BASE_FILTERS = [
|
|
1771
|
+
{ value: "eq", label: "is" },
|
|
1772
|
+
{ value: "ne", label: "is not" },
|
|
1773
|
+
{ value: "null", label: "is null" },
|
|
1774
|
+
{ value: "notNull", label: "is not null" }
|
|
1775
|
+
];
|
|
1776
|
+
const NUMERIC_FILTERS = [
|
|
1777
|
+
{ value: "gt", label: "is greater than" },
|
|
1778
|
+
{ value: "gte", label: "is greater than or equal to" },
|
|
1779
|
+
{ value: "lt", label: "is less than" },
|
|
1780
|
+
{ value: "lte", label: "is less than or equal to" }
|
|
1781
|
+
];
|
|
1782
|
+
const CONTAINS_FILTERS = [
|
|
1783
|
+
{ value: "contains", label: "contains" },
|
|
1784
|
+
{ value: "containsi", label: "contains (case insensitive)" },
|
|
1785
|
+
{ value: "notContains", label: "not contains" },
|
|
1786
|
+
{ value: "notContainsi", label: "not contains (case insensitive)" }
|
|
1787
|
+
];
|
|
1788
|
+
const STRING_PARSE_FILTERS = [
|
|
1789
|
+
{ value: "startsWith", label: "starts with" },
|
|
1790
|
+
{ value: "startsWithi", label: "starts with (case insensitive)" },
|
|
1791
|
+
{ value: "endsWith", label: "ends with" },
|
|
1792
|
+
{ value: "endsWithi", label: "ends with (case insensitive)" }
|
|
1793
|
+
];
|
|
1794
|
+
const IS_SENSITIVE_FILTERS = [
|
|
1795
|
+
{ value: "eqi", label: "is (case insensitive)" },
|
|
1796
|
+
{ value: "nei", label: "is not (case insensitive)" }
|
|
1797
|
+
];
|
|
1798
|
+
const ARRAY_FILTERS = [
|
|
1799
|
+
{ value: "in", label: "is in" },
|
|
1800
|
+
{ value: "notIn", label: "is not in" }
|
|
1801
|
+
];
|
|
1802
|
+
const RANGE_FILTERS = [
|
|
1803
|
+
{ value: "between", label: "is between" }
|
|
1804
|
+
];
|
|
1805
|
+
function getOperatorsForType(fieldType) {
|
|
1806
|
+
const t = (fieldType || "string").toLowerCase();
|
|
1807
|
+
if (["string", "text", "email", "uid", "richtext"].includes(t)) {
|
|
1808
|
+
return [
|
|
1809
|
+
...BASE_FILTERS,
|
|
1810
|
+
...IS_SENSITIVE_FILTERS,
|
|
1811
|
+
...CONTAINS_FILTERS,
|
|
1812
|
+
...STRING_PARSE_FILTERS,
|
|
1813
|
+
...ARRAY_FILTERS
|
|
1814
|
+
];
|
|
1815
|
+
}
|
|
1816
|
+
if (["integer", "float", "decimal", "biginteger"].includes(t)) {
|
|
1817
|
+
return [
|
|
1818
|
+
...BASE_FILTERS,
|
|
1819
|
+
...NUMERIC_FILTERS,
|
|
1820
|
+
...ARRAY_FILTERS,
|
|
1821
|
+
...RANGE_FILTERS
|
|
1822
|
+
];
|
|
1823
|
+
}
|
|
1824
|
+
if (["datetime"].includes(t)) {
|
|
1825
|
+
return [
|
|
1826
|
+
...BASE_FILTERS,
|
|
1827
|
+
...NUMERIC_FILTERS,
|
|
1828
|
+
...RANGE_FILTERS
|
|
1829
|
+
];
|
|
1830
|
+
}
|
|
1831
|
+
if (["date", "time"].includes(t)) {
|
|
1832
|
+
return [
|
|
1833
|
+
...BASE_FILTERS,
|
|
1834
|
+
...NUMERIC_FILTERS,
|
|
1835
|
+
...CONTAINS_FILTERS,
|
|
1836
|
+
...RANGE_FILTERS
|
|
1837
|
+
];
|
|
1838
|
+
}
|
|
1839
|
+
if (["boolean"].includes(t)) {
|
|
1840
|
+
return BASE_FILTERS;
|
|
1841
|
+
}
|
|
1842
|
+
if (["enumeration"].includes(t)) {
|
|
1843
|
+
return [...BASE_FILTERS, ...ARRAY_FILTERS];
|
|
1844
|
+
}
|
|
1845
|
+
return [...BASE_FILTERS, ...IS_SENSITIVE_FILTERS];
|
|
1846
|
+
}
|
|
1847
|
+
const buildFilterFromPath = (fieldPath, operator, value, valueTo, negate) => {
|
|
1767
1848
|
const parts = fieldPath.split(".").filter(Boolean);
|
|
1768
1849
|
if (parts.length === 0) return {};
|
|
1769
1850
|
const opKey = operator.startsWith("$") ? operator : `$${operator}`;
|
|
1770
|
-
|
|
1851
|
+
let filterValue;
|
|
1852
|
+
if (["null", "notNull"].includes(operator)) {
|
|
1853
|
+
filterValue = true;
|
|
1854
|
+
} else if (["in", "notIn"].includes(operator)) {
|
|
1855
|
+
filterValue = value.split(",").map((v) => v.trim()).filter(Boolean);
|
|
1856
|
+
} else if (operator === "between" && valueTo) {
|
|
1857
|
+
filterValue = [value, valueTo];
|
|
1858
|
+
} else {
|
|
1859
|
+
filterValue = value;
|
|
1860
|
+
}
|
|
1861
|
+
let result;
|
|
1771
1862
|
if (parts.length === 1) {
|
|
1772
|
-
|
|
1863
|
+
result = { [parts[0]]: { [opKey]: filterValue } };
|
|
1864
|
+
} else {
|
|
1865
|
+
const [first, ...rest] = parts;
|
|
1866
|
+
result = {
|
|
1867
|
+
[first]: buildFilterFromPath(rest.join("."), operator, value, valueTo, false)
|
|
1868
|
+
};
|
|
1773
1869
|
}
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1870
|
+
if (negate) {
|
|
1871
|
+
return { $not: result };
|
|
1872
|
+
}
|
|
1873
|
+
return result;
|
|
1778
1874
|
};
|
|
1779
1875
|
const extractRelationFromField = (field) => {
|
|
1780
1876
|
if (!field || !field.includes(".")) return null;
|
|
@@ -1788,12 +1884,12 @@ const rowsToFilterStructure = (rows, connectors) => {
|
|
|
1788
1884
|
});
|
|
1789
1885
|
if (validRows.length === 0) return void 0;
|
|
1790
1886
|
if (validRows.length === 1) {
|
|
1791
|
-
return buildFilterFromPath(validRows[0].field, validRows[0].operator, validRows[0].value);
|
|
1887
|
+
return buildFilterFromPath(validRows[0].field, validRows[0].operator, validRows[0].value, validRows[0].valueTo, validRows[0].negate);
|
|
1792
1888
|
}
|
|
1793
1889
|
const groups = [];
|
|
1794
1890
|
let currentAndGroup = [];
|
|
1795
1891
|
validRows.forEach((row, i) => {
|
|
1796
|
-
const filter = buildFilterFromPath(row.field, row.operator, row.value);
|
|
1892
|
+
const filter = buildFilterFromPath(row.field, row.operator, row.value, row.valueTo, row.negate);
|
|
1797
1893
|
currentAndGroup.push(filter);
|
|
1798
1894
|
const nextConnector = connectors[i];
|
|
1799
1895
|
if (nextConnector?.logic === "OR" || !nextConnector) {
|
|
@@ -1835,6 +1931,58 @@ const generateFromRows = (rows, connectors) => {
|
|
|
1835
1931
|
}
|
|
1836
1932
|
return qs__default.default.stringify(queryObject, { encodeValuesOnly: true });
|
|
1837
1933
|
};
|
|
1934
|
+
const buildFilterFromGroup = (group) => {
|
|
1935
|
+
const validItems = group.items.filter((item) => {
|
|
1936
|
+
if ("isGroup" in item && item.isGroup) return true;
|
|
1937
|
+
const row = item;
|
|
1938
|
+
if (!row.field) return false;
|
|
1939
|
+
if (["null", "notNull"].includes(row.operator)) return true;
|
|
1940
|
+
if (row.operator === "between") return row.value?.trim() && row.valueTo?.trim();
|
|
1941
|
+
return row.value?.trim();
|
|
1942
|
+
});
|
|
1943
|
+
if (validItems.length === 0) return void 0;
|
|
1944
|
+
const conditions = validItems.map((item) => {
|
|
1945
|
+
if ("isGroup" in item && item.isGroup) {
|
|
1946
|
+
return buildFilterFromGroup(item);
|
|
1947
|
+
}
|
|
1948
|
+
const row = item;
|
|
1949
|
+
return buildFilterFromPath(row.field, row.operator, row.value, row.valueTo, row.negate);
|
|
1950
|
+
}).filter(Boolean);
|
|
1951
|
+
if (conditions.length === 0) return void 0;
|
|
1952
|
+
if (conditions.length === 1) return conditions[0];
|
|
1953
|
+
const logicKey = group.logic === "AND" ? "$and" : "$or";
|
|
1954
|
+
return { [logicKey]: conditions };
|
|
1955
|
+
};
|
|
1956
|
+
const extractRelationsFromGroup = (group) => {
|
|
1957
|
+
const relations = /* @__PURE__ */ new Set();
|
|
1958
|
+
group.items.forEach((item) => {
|
|
1959
|
+
if ("isGroup" in item && item.isGroup) {
|
|
1960
|
+
const nested = extractRelationsFromGroup(item);
|
|
1961
|
+
nested.forEach((r) => relations.add(r));
|
|
1962
|
+
} else {
|
|
1963
|
+
const row = item;
|
|
1964
|
+
const rel = extractRelationFromField(row.field);
|
|
1965
|
+
if (rel) relations.add(rel);
|
|
1966
|
+
}
|
|
1967
|
+
});
|
|
1968
|
+
return relations;
|
|
1969
|
+
};
|
|
1970
|
+
const generateFromGroup = (group) => {
|
|
1971
|
+
const queryObject = {};
|
|
1972
|
+
const filterStructure = buildFilterFromGroup(group);
|
|
1973
|
+
if (filterStructure) {
|
|
1974
|
+
queryObject.filters = filterStructure;
|
|
1975
|
+
}
|
|
1976
|
+
const relations = extractRelationsFromGroup(group);
|
|
1977
|
+
if (relations.size > 0) {
|
|
1978
|
+
const populate = {};
|
|
1979
|
+
relations.forEach((rel) => {
|
|
1980
|
+
populate[rel] = true;
|
|
1981
|
+
});
|
|
1982
|
+
queryObject.populate = populate;
|
|
1983
|
+
}
|
|
1984
|
+
return qs__default.default.stringify(queryObject, { encodeValuesOnly: true });
|
|
1985
|
+
};
|
|
1838
1986
|
const extractFieldPathAndOperator = (parts) => {
|
|
1839
1987
|
let operatorIndex = -1;
|
|
1840
1988
|
for (let i = parts.length - 1; i >= 0; i--) {
|
|
@@ -2009,7 +2157,7 @@ const ModalOverlay = styled__default.default.div`
|
|
|
2009
2157
|
display: flex;
|
|
2010
2158
|
align-items: center;
|
|
2011
2159
|
justify-content: center;
|
|
2012
|
-
z-index:
|
|
2160
|
+
z-index: 400;
|
|
2013
2161
|
padding: 20px;
|
|
2014
2162
|
@media (max-width: 768px) {
|
|
2015
2163
|
padding: 10px;
|
|
@@ -2019,61 +2167,328 @@ const ModalContent = styled__default.default(designSystem.Box)`
|
|
|
2019
2167
|
background: ${(p) => p.theme.colors.neutral0};
|
|
2020
2168
|
border-radius: 8px;
|
|
2021
2169
|
max-height: 90vh;
|
|
2022
|
-
|
|
2023
|
-
max-width: 560px;
|
|
2170
|
+
max-width: 720px;
|
|
2024
2171
|
width: 100%;
|
|
2172
|
+
min-height: 400px;
|
|
2025
2173
|
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
|
|
2174
|
+
display: flex;
|
|
2175
|
+
flex-direction: column;
|
|
2176
|
+
overflow: hidden;
|
|
2026
2177
|
@media (max-width: 768px) {
|
|
2027
2178
|
max-width: 100%;
|
|
2028
|
-
max-height:
|
|
2179
|
+
max-height: 92vh;
|
|
2029
2180
|
}
|
|
2030
2181
|
`;
|
|
2182
|
+
const ModalScrollArea = styled__default.default.div`
|
|
2183
|
+
flex: 1;
|
|
2184
|
+
overflow-y: auto;
|
|
2185
|
+
overflow-x: hidden;
|
|
2186
|
+
`;
|
|
2031
2187
|
const RowWrapper = styled__default.default.div`
|
|
2032
2188
|
display: flex;
|
|
2033
2189
|
flex-direction: column;
|
|
2034
2190
|
gap: 8px;
|
|
2035
2191
|
margin-bottom: 8px;
|
|
2036
2192
|
`;
|
|
2037
|
-
const
|
|
2193
|
+
const FilterRowCard = styled__default.default.div`
|
|
2194
|
+
display: flex;
|
|
2195
|
+
flex-direction: column;
|
|
2196
|
+
gap: 10px;
|
|
2197
|
+
padding: 12px;
|
|
2198
|
+
background: ${(p) => p.theme.colors.neutral100};
|
|
2199
|
+
border-radius: 6px;
|
|
2200
|
+
border: 1px solid ${(p) => p.theme.colors.neutral200};
|
|
2201
|
+
`;
|
|
2202
|
+
const FilterRowTop = styled__default.default.div`
|
|
2038
2203
|
display: flex;
|
|
2039
2204
|
align-items: center;
|
|
2040
2205
|
gap: 8px;
|
|
2041
2206
|
flex-wrap: wrap;
|
|
2042
2207
|
`;
|
|
2043
|
-
const
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2208
|
+
const NegateCheckbox = styled__default.default.label`
|
|
2209
|
+
display: flex;
|
|
2210
|
+
align-items: center;
|
|
2211
|
+
gap: 6px;
|
|
2212
|
+
font-size: 12px;
|
|
2213
|
+
color: ${(p) => p.theme.colors.neutral700};
|
|
2214
|
+
cursor: pointer;
|
|
2215
|
+
user-select: none;
|
|
2216
|
+
input {
|
|
2217
|
+
cursor: pointer;
|
|
2218
|
+
}
|
|
2219
|
+
`;
|
|
2220
|
+
const FilterRowValue = styled__default.default.div`
|
|
2221
|
+
width: 100%;
|
|
2222
|
+
padding-top: 14px;
|
|
2223
|
+
padding-bottom: 4px;
|
|
2224
|
+
border-top: 1px solid ${(p) => p.theme.colors.neutral200};
|
|
2225
|
+
`;
|
|
2226
|
+
const ValueLabel = styled__default.default.span`
|
|
2227
|
+
display: block;
|
|
2228
|
+
font-size: 12px;
|
|
2229
|
+
font-weight: 500;
|
|
2230
|
+
color: ${(p) => p.theme.colors.neutral600};
|
|
2231
|
+
margin-bottom: 8px;
|
|
2232
|
+
`;
|
|
2233
|
+
styled__default.default.span`
|
|
2234
|
+
font-size: 10px;
|
|
2235
|
+
font-weight: 500;
|
|
2236
|
+
padding: 2px 6px;
|
|
2237
|
+
border-radius: 4px;
|
|
2238
|
+
background: ${(p) => p.theme.colors.neutral200};
|
|
2239
|
+
color: ${(p) => p.theme.colors.neutral700};
|
|
2240
|
+
text-transform: uppercase;
|
|
2241
|
+
`;
|
|
2242
|
+
const MultiValueWrapper = styled__default.default.div`
|
|
2243
|
+
display: flex;
|
|
2244
|
+
flex-wrap: wrap;
|
|
2245
|
+
gap: 6px;
|
|
2246
|
+
min-height: 32px;
|
|
2247
|
+
padding: 6px 8px;
|
|
2248
|
+
border: 1px solid ${(p) => p.theme.colors.neutral200};
|
|
2048
2249
|
border-radius: 4px;
|
|
2250
|
+
background: ${(p) => p.theme.colors.neutral0};
|
|
2251
|
+
&:focus-within {
|
|
2252
|
+
border-color: #4945ff;
|
|
2253
|
+
box-shadow: 0 0 0 2px rgba(73, 69, 255, 0.1);
|
|
2254
|
+
}
|
|
2255
|
+
`;
|
|
2256
|
+
const MultiValueInput = styled__default.default.input`
|
|
2257
|
+
flex: 1;
|
|
2258
|
+
min-width: 80px;
|
|
2259
|
+
border: none;
|
|
2260
|
+
background: transparent;
|
|
2049
2261
|
font-size: 14px;
|
|
2262
|
+
color: ${(p) => p.theme.colors.neutral800};
|
|
2050
2263
|
&:focus {
|
|
2051
2264
|
outline: none;
|
|
2052
|
-
border-color: #4945ff;
|
|
2053
|
-
box-shadow: 0 0 0 2px rgba(73, 69, 255, 0.1);
|
|
2054
2265
|
}
|
|
2266
|
+
&::placeholder {
|
|
2267
|
+
color: ${(p) => p.theme.colors.neutral500};
|
|
2268
|
+
}
|
|
2269
|
+
`;
|
|
2270
|
+
const BetweenWrapper = styled__default.default.div`
|
|
2271
|
+
display: flex;
|
|
2272
|
+
align-items: center;
|
|
2273
|
+
gap: 8px;
|
|
2274
|
+
width: 100%;
|
|
2055
2275
|
`;
|
|
2056
|
-
const
|
|
2276
|
+
const BetweenSeparator = styled__default.default.span`
|
|
2277
|
+
font-size: 13px;
|
|
2278
|
+
font-weight: 500;
|
|
2279
|
+
color: ${(p) => p.theme.colors.neutral600};
|
|
2280
|
+
`;
|
|
2281
|
+
function SmartValueInput({
|
|
2282
|
+
fieldType,
|
|
2283
|
+
operator,
|
|
2284
|
+
value,
|
|
2285
|
+
valueTo,
|
|
2286
|
+
onChange,
|
|
2287
|
+
onValueToChange,
|
|
2288
|
+
placeholder = "Value"
|
|
2289
|
+
}) {
|
|
2290
|
+
const t = (fieldType || "string").toLowerCase();
|
|
2291
|
+
const [inputValue, setInputValue] = React__default.default.useState("");
|
|
2292
|
+
if (["in", "notIn"].includes(operator)) {
|
|
2293
|
+
const values = value ? value.split(",").map((v) => v.trim()).filter(Boolean) : [];
|
|
2294
|
+
const handleAddValue = (e) => {
|
|
2295
|
+
if (e.key === "Enter" || e.key === ",") {
|
|
2296
|
+
e.preventDefault();
|
|
2297
|
+
const newVal = inputValue.trim();
|
|
2298
|
+
if (newVal && !values.includes(newVal)) {
|
|
2299
|
+
const updated = [...values, newVal].join(",");
|
|
2300
|
+
onChange(updated);
|
|
2301
|
+
setInputValue("");
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
};
|
|
2305
|
+
const handleRemoveValue = (val) => {
|
|
2306
|
+
const updated = values.filter((v) => v !== val).join(",");
|
|
2307
|
+
onChange(updated);
|
|
2308
|
+
};
|
|
2309
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsxs(MultiValueWrapper, { children: [
|
|
2310
|
+
values.map((val) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2311
|
+
designSystem.Tag,
|
|
2312
|
+
{
|
|
2313
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {}),
|
|
2314
|
+
onClick: () => handleRemoveValue(val),
|
|
2315
|
+
children: val
|
|
2316
|
+
},
|
|
2317
|
+
val
|
|
2318
|
+
)),
|
|
2319
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2320
|
+
MultiValueInput,
|
|
2321
|
+
{
|
|
2322
|
+
value: inputValue,
|
|
2323
|
+
onChange: (e) => setInputValue(e.target.value),
|
|
2324
|
+
onKeyDown: handleAddValue,
|
|
2325
|
+
placeholder: values.length === 0 ? "Type and press Enter" : ""
|
|
2326
|
+
}
|
|
2327
|
+
)
|
|
2328
|
+
] }) });
|
|
2329
|
+
}
|
|
2330
|
+
if (operator === "between") {
|
|
2331
|
+
if (["date"].includes(t)) {
|
|
2332
|
+
const dateVal1 = value ? (() => {
|
|
2333
|
+
try {
|
|
2334
|
+
const d = new Date(value);
|
|
2335
|
+
return isNaN(d.getTime()) ? void 0 : d;
|
|
2336
|
+
} catch {
|
|
2337
|
+
return void 0;
|
|
2338
|
+
}
|
|
2339
|
+
})() : void 0;
|
|
2340
|
+
const dateVal2 = valueTo ? (() => {
|
|
2341
|
+
try {
|
|
2342
|
+
const d = new Date(valueTo);
|
|
2343
|
+
return isNaN(d.getTime()) ? void 0 : d;
|
|
2344
|
+
} catch {
|
|
2345
|
+
return void 0;
|
|
2346
|
+
}
|
|
2347
|
+
})() : void 0;
|
|
2348
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(BetweenWrapper, { children: [
|
|
2349
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.DatePicker, { value: dateVal1, onChange: (d) => onChange(d ? d.toISOString().slice(0, 10) : ""), clearLabel: "Clear", size: "S" }) }),
|
|
2350
|
+
/* @__PURE__ */ jsxRuntime.jsx(BetweenSeparator, { children: "and" }),
|
|
2351
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.DatePicker, { value: dateVal2, onChange: (d) => onValueToChange?.(d ? d.toISOString().slice(0, 10) : ""), clearLabel: "Clear", size: "S" }) })
|
|
2352
|
+
] });
|
|
2353
|
+
}
|
|
2354
|
+
if (["integer", "float", "decimal", "biginteger"].includes(t)) {
|
|
2355
|
+
const num1 = value === "" ? void 0 : (() => {
|
|
2356
|
+
const n = parseFloat(value);
|
|
2357
|
+
return isNaN(n) ? void 0 : n;
|
|
2358
|
+
})();
|
|
2359
|
+
const num2 = valueTo === "" || !valueTo ? void 0 : (() => {
|
|
2360
|
+
const n = parseFloat(valueTo);
|
|
2361
|
+
return isNaN(n) ? void 0 : n;
|
|
2362
|
+
})();
|
|
2363
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(BetweenWrapper, { children: [
|
|
2364
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.NumberInput, { value: num1, onValueChange: (v) => onChange(v !== void 0 ? String(v) : ""), size: "S" }) }),
|
|
2365
|
+
/* @__PURE__ */ jsxRuntime.jsx(BetweenSeparator, { children: "and" }),
|
|
2366
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.NumberInput, { value: num2, onValueChange: (v) => onValueToChange?.(v !== void 0 ? String(v) : ""), size: "S" }) })
|
|
2367
|
+
] });
|
|
2368
|
+
}
|
|
2369
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(BetweenWrapper, { children: [
|
|
2370
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.TextInput, { value, onChange: (e) => onChange(e.target.value), placeholder: "From", size: "S" }) }),
|
|
2371
|
+
/* @__PURE__ */ jsxRuntime.jsx(BetweenSeparator, { children: "and" }),
|
|
2372
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.TextInput, { value: valueTo || "", onChange: (e) => onValueToChange?.(e.target.value), placeholder: "To", size: "S" }) })
|
|
2373
|
+
] });
|
|
2374
|
+
}
|
|
2375
|
+
if (["date"].includes(t)) {
|
|
2376
|
+
const dateVal = value ? (() => {
|
|
2377
|
+
try {
|
|
2378
|
+
const d = new Date(value);
|
|
2379
|
+
return isNaN(d.getTime()) ? void 0 : d;
|
|
2380
|
+
} catch {
|
|
2381
|
+
return void 0;
|
|
2382
|
+
}
|
|
2383
|
+
})() : void 0;
|
|
2384
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "100%", minWidth: 140 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2385
|
+
designSystem.DatePicker,
|
|
2386
|
+
{
|
|
2387
|
+
value: dateVal,
|
|
2388
|
+
onChange: (d) => onChange(d ? d.toISOString().slice(0, 10) : ""),
|
|
2389
|
+
clearLabel: "Clear",
|
|
2390
|
+
size: "S"
|
|
2391
|
+
}
|
|
2392
|
+
) });
|
|
2393
|
+
}
|
|
2394
|
+
if (["datetime"].includes(t)) {
|
|
2395
|
+
const dateVal = value ? (() => {
|
|
2396
|
+
try {
|
|
2397
|
+
const d = new Date(value);
|
|
2398
|
+
return isNaN(d.getTime()) ? void 0 : d;
|
|
2399
|
+
} catch {
|
|
2400
|
+
return void 0;
|
|
2401
|
+
}
|
|
2402
|
+
})() : void 0;
|
|
2403
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "100%", minWidth: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2404
|
+
designSystem.DateTimePicker,
|
|
2405
|
+
{
|
|
2406
|
+
value: dateVal ?? void 0,
|
|
2407
|
+
onChange: (d) => onChange(d ? d.toISOString() : ""),
|
|
2408
|
+
clearLabel: "Clear",
|
|
2409
|
+
size: "S"
|
|
2410
|
+
}
|
|
2411
|
+
) });
|
|
2412
|
+
}
|
|
2413
|
+
if (["time"].includes(t)) {
|
|
2414
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "100%", minWidth: 120 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2415
|
+
designSystem.TimePicker,
|
|
2416
|
+
{
|
|
2417
|
+
value: value || void 0,
|
|
2418
|
+
onChange: (v) => onChange(v ?? ""),
|
|
2419
|
+
size: "S"
|
|
2420
|
+
}
|
|
2421
|
+
) });
|
|
2422
|
+
}
|
|
2423
|
+
if (["integer", "float", "decimal", "biginteger"].includes(t)) {
|
|
2424
|
+
const numVal = value === "" ? void 0 : (() => {
|
|
2425
|
+
const n = parseFloat(value);
|
|
2426
|
+
return isNaN(n) ? void 0 : n;
|
|
2427
|
+
})();
|
|
2428
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "100%", minWidth: 120 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2429
|
+
designSystem.NumberInput,
|
|
2430
|
+
{
|
|
2431
|
+
value: numVal,
|
|
2432
|
+
onValueChange: (v) => onChange(v !== void 0 ? String(v) : ""),
|
|
2433
|
+
size: "S"
|
|
2434
|
+
}
|
|
2435
|
+
) });
|
|
2436
|
+
}
|
|
2437
|
+
if (["boolean"].includes(t)) {
|
|
2438
|
+
const selVal = value === "true" ? "true" : value === "false" ? "false" : "";
|
|
2439
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "100%", minWidth: 120 }, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2440
|
+
designSystem.SingleSelect,
|
|
2441
|
+
{
|
|
2442
|
+
value: selVal || void 0,
|
|
2443
|
+
onChange: (v) => onChange(v != null ? String(v) : ""),
|
|
2444
|
+
placeholder,
|
|
2445
|
+
size: "S",
|
|
2446
|
+
children: [
|
|
2447
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "true", children: "true" }),
|
|
2448
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "false", children: "false" })
|
|
2449
|
+
]
|
|
2450
|
+
}
|
|
2451
|
+
) });
|
|
2452
|
+
}
|
|
2453
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "100%", minWidth: 120 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2454
|
+
designSystem.TextInput,
|
|
2455
|
+
{
|
|
2456
|
+
value,
|
|
2457
|
+
onChange: (e) => onChange(e.target.value),
|
|
2458
|
+
placeholder,
|
|
2459
|
+
size: "S"
|
|
2460
|
+
}
|
|
2461
|
+
) });
|
|
2462
|
+
}
|
|
2463
|
+
const ConnectorPill = styled__default.default.div`
|
|
2057
2464
|
display: flex;
|
|
2058
2465
|
align-items: center;
|
|
2059
2466
|
justify-content: center;
|
|
2060
|
-
padding:
|
|
2467
|
+
padding: 6px 0;
|
|
2061
2468
|
`;
|
|
2062
2469
|
const ConnectorButton = styled__default.default.button`
|
|
2063
|
-
padding:
|
|
2470
|
+
padding: 6px 14px;
|
|
2064
2471
|
font-size: 12px;
|
|
2065
2472
|
font-weight: 500;
|
|
2066
|
-
border: 1px solid ${(
|
|
2067
|
-
border-radius:
|
|
2068
|
-
background: ${(
|
|
2069
|
-
color: ${(
|
|
2473
|
+
border: 1px solid ${(p) => p.$active ? "#4945ff" : p.theme.colors.neutral300};
|
|
2474
|
+
border-radius: 999px;
|
|
2475
|
+
background: ${(p) => p.$active ? "#EEF0FF" : "transparent"};
|
|
2476
|
+
color: ${(p) => p.$active ? "#4945ff" : p.theme.colors.neutral700};
|
|
2070
2477
|
cursor: pointer;
|
|
2071
2478
|
transition: all 0.15s ease;
|
|
2072
2479
|
&:hover {
|
|
2073
2480
|
border-color: #4945ff;
|
|
2074
|
-
background: ${(p) => p.theme.colors.neutral100};
|
|
2075
2481
|
}
|
|
2076
2482
|
`;
|
|
2483
|
+
const ActiveBadge = styled__default.default.span`
|
|
2484
|
+
font-size: 12px;
|
|
2485
|
+
font-weight: 500;
|
|
2486
|
+
padding: 2px 8px;
|
|
2487
|
+
border-radius: 999px;
|
|
2488
|
+
background: rgba(73, 69, 255, 0.12);
|
|
2489
|
+
color: #4945ff;
|
|
2490
|
+
margin-left: 8px;
|
|
2491
|
+
`;
|
|
2077
2492
|
const DeleteButton = styled__default.default.button`
|
|
2078
2493
|
display: flex;
|
|
2079
2494
|
align-items: center;
|
|
@@ -2118,34 +2533,101 @@ const InfoText = styled__default.default.div`
|
|
|
2118
2533
|
margin-top: 8px;
|
|
2119
2534
|
font-style: italic;
|
|
2120
2535
|
`;
|
|
2121
|
-
const
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
{
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
{
|
|
2132
|
-
|
|
2536
|
+
const ModalFooter = styled__default.default.div`
|
|
2537
|
+
flex-shrink: 0;
|
|
2538
|
+
padding-top: 16px;
|
|
2539
|
+
border-top: 1px solid ${(p) => p.theme.colors.neutral200};
|
|
2540
|
+
margin-top: 8px;
|
|
2541
|
+
`;
|
|
2542
|
+
const GroupContainer = styled__default.default.div`
|
|
2543
|
+
border: 2px solid ${(p) => p.$logic === "AND" ? "#0EA5E9" : "#F97316"};
|
|
2544
|
+
border-radius: 8px;
|
|
2545
|
+
padding: 16px;
|
|
2546
|
+
margin: ${(p) => p.$level > 0 ? "12px 0 12px 20px" : "0"};
|
|
2547
|
+
background: ${(p) => p.$logic === "AND" ? "rgba(14, 165, 233, 0.03)" : "rgba(249, 115, 22, 0.03)"};
|
|
2548
|
+
position: relative;
|
|
2549
|
+
${(p) => p.$level > 0 && `border-style: dashed;`}
|
|
2550
|
+
`;
|
|
2551
|
+
const GroupHeader = styled__default.default.div`
|
|
2552
|
+
display: flex;
|
|
2553
|
+
align-items: center;
|
|
2554
|
+
justify-content: space-between;
|
|
2555
|
+
margin-bottom: 12px;
|
|
2556
|
+
padding-bottom: 10px;
|
|
2557
|
+
border-bottom: 1px solid ${(p) => p.theme.colors.neutral200};
|
|
2558
|
+
`;
|
|
2559
|
+
const LogicBadge = styled__default.default.div`
|
|
2560
|
+
display: inline-flex;
|
|
2561
|
+
align-items: center;
|
|
2562
|
+
gap: 8px;
|
|
2563
|
+
font-size: 12px;
|
|
2564
|
+
font-weight: 600;
|
|
2565
|
+
color: ${(p) => p.$logic === "AND" ? "#0284C7" : "#EA580C"};
|
|
2566
|
+
`;
|
|
2567
|
+
const LogicToggleButton = styled__default.default.button`
|
|
2568
|
+
padding: 4px 12px;
|
|
2569
|
+
border-radius: 999px;
|
|
2570
|
+
border: 1px solid ${(p) => p.$logic === "AND" ? "#0EA5E9" : "#F97316"};
|
|
2571
|
+
background: ${(p) => p.$active ? p.$logic === "AND" ? "#0EA5E9" : "#F97316" : "transparent"};
|
|
2572
|
+
color: ${(p) => p.$active ? "white" : p.$logic === "AND" ? "#0284C7" : "#EA580C"};
|
|
2573
|
+
font-size: 11px;
|
|
2574
|
+
font-weight: 600;
|
|
2575
|
+
cursor: pointer;
|
|
2576
|
+
transition: all 0.15s ease;
|
|
2577
|
+
&:hover {
|
|
2578
|
+
transform: scale(1.05);
|
|
2579
|
+
}
|
|
2580
|
+
`;
|
|
2581
|
+
const GroupActions = styled__default.default.div`
|
|
2582
|
+
display: flex;
|
|
2583
|
+
gap: 6px;
|
|
2584
|
+
align-items: center;
|
|
2585
|
+
`;
|
|
2586
|
+
const SmallButton = styled__default.default.button`
|
|
2587
|
+
padding: 4px 10px;
|
|
2588
|
+
font-size: 11px;
|
|
2589
|
+
font-weight: 500;
|
|
2590
|
+
border: 1px solid ${(p) => p.theme.colors.neutral300};
|
|
2591
|
+
border-radius: 4px;
|
|
2592
|
+
background: ${(p) => p.theme.colors.neutral0};
|
|
2593
|
+
color: ${(p) => p.theme.colors.neutral700};
|
|
2594
|
+
cursor: pointer;
|
|
2595
|
+
&:hover {
|
|
2596
|
+
border-color: #4945ff;
|
|
2597
|
+
background: rgba(73, 69, 255, 0.06);
|
|
2598
|
+
}
|
|
2599
|
+
&:disabled {
|
|
2600
|
+
opacity: 0.5;
|
|
2601
|
+
cursor: not-allowed;
|
|
2602
|
+
}
|
|
2603
|
+
`;
|
|
2604
|
+
const RemoveGroupButton = styled__default.default(SmallButton)`
|
|
2605
|
+
color: #dc2626;
|
|
2606
|
+
border-color: rgba(239, 68, 68, 0.3);
|
|
2607
|
+
&:hover {
|
|
2608
|
+
border-color: #dc2626;
|
|
2609
|
+
background: rgba(239, 68, 68, 0.06);
|
|
2610
|
+
}
|
|
2611
|
+
`;
|
|
2133
2612
|
const StrapiStyleFilterModal = ({
|
|
2134
2613
|
onClose,
|
|
2135
2614
|
onApply,
|
|
2136
2615
|
availableFields,
|
|
2137
2616
|
availableRelations = [],
|
|
2138
|
-
currentQuery = ""
|
|
2617
|
+
currentQuery = "",
|
|
2618
|
+
enableNestedGroups = false
|
|
2139
2619
|
}) => {
|
|
2140
2620
|
const { getRelationFields } = useRelationSchema();
|
|
2141
2621
|
const [fieldOptions, setFieldOptions] = React.useState([]);
|
|
2142
2622
|
const [rows, setRows] = React.useState([]);
|
|
2143
2623
|
const [connectors, setConnectors] = React.useState([]);
|
|
2624
|
+
const [rootGroup, setRootGroup] = React.useState(null);
|
|
2144
2625
|
const buildFieldOptions = React.useCallback(async () => {
|
|
2145
2626
|
const direct = availableFields.map((f) => ({
|
|
2146
2627
|
value: f.name,
|
|
2147
2628
|
label: f.name,
|
|
2148
|
-
group: "Fields"
|
|
2629
|
+
group: "Fields",
|
|
2630
|
+
type: f.type
|
|
2149
2631
|
}));
|
|
2150
2632
|
const relationOptions = [];
|
|
2151
2633
|
for (const rel of availableRelations) {
|
|
@@ -2157,7 +2639,8 @@ const StrapiStyleFilterModal = ({
|
|
|
2157
2639
|
relationOptions.push({
|
|
2158
2640
|
value: `${rel.name}.${f.name}`,
|
|
2159
2641
|
label: `${rel.name} > ${f.name}`,
|
|
2160
|
-
group: "Relations"
|
|
2642
|
+
group: "Relations",
|
|
2643
|
+
type: f.type
|
|
2161
2644
|
});
|
|
2162
2645
|
});
|
|
2163
2646
|
}
|
|
@@ -2171,27 +2654,94 @@ const StrapiStyleFilterModal = ({
|
|
|
2171
2654
|
buildFieldOptions();
|
|
2172
2655
|
}, [buildFieldOptions]);
|
|
2173
2656
|
React.useEffect(() => {
|
|
2174
|
-
if (
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2657
|
+
if (enableNestedGroups) {
|
|
2658
|
+
setRootGroup({
|
|
2659
|
+
id: "root",
|
|
2660
|
+
logic: "AND",
|
|
2661
|
+
items: [{
|
|
2662
|
+
id: `row_${Date.now()}`,
|
|
2663
|
+
field: "",
|
|
2664
|
+
operator: "eq",
|
|
2665
|
+
value: ""
|
|
2666
|
+
}],
|
|
2667
|
+
isGroup: true
|
|
2668
|
+
});
|
|
2669
|
+
} else {
|
|
2670
|
+
if (currentQuery) {
|
|
2671
|
+
const { rows: parsedRows, connectors: parsedConnectors } = parseQueryToRows(currentQuery);
|
|
2672
|
+
if (parsedRows.length > 0) {
|
|
2673
|
+
setRows(parsedRows);
|
|
2674
|
+
setConnectors(parsedConnectors);
|
|
2675
|
+
return;
|
|
2676
|
+
}
|
|
2180
2677
|
}
|
|
2678
|
+
setRows([{
|
|
2679
|
+
id: `row_${Date.now()}`,
|
|
2680
|
+
field: "",
|
|
2681
|
+
operator: "eq",
|
|
2682
|
+
value: ""
|
|
2683
|
+
}]);
|
|
2684
|
+
setConnectors([]);
|
|
2181
2685
|
}
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2686
|
+
}, [currentQuery, enableNestedGroups]);
|
|
2687
|
+
React.useEffect(() => {
|
|
2688
|
+
if (fieldOptions.length === 0) return;
|
|
2689
|
+
if (!enableNestedGroups) {
|
|
2690
|
+
setRows((prev) => prev.map((r) => {
|
|
2691
|
+
if (!r.field || r.fieldType) return r;
|
|
2692
|
+
const opt = fieldOptions.find((f) => f.value === r.field);
|
|
2693
|
+
return opt?.type ? { ...r, fieldType: opt.type } : r;
|
|
2694
|
+
}));
|
|
2695
|
+
} else if (rootGroup) {
|
|
2696
|
+
const enrichGroup = (group) => ({
|
|
2697
|
+
...group,
|
|
2698
|
+
items: group.items.map((item) => {
|
|
2699
|
+
if ("isGroup" in item && item.isGroup) {
|
|
2700
|
+
return enrichGroup(item);
|
|
2701
|
+
}
|
|
2702
|
+
const row = item;
|
|
2703
|
+
if (!row.field || row.fieldType) return row;
|
|
2704
|
+
const opt = fieldOptions.find((f) => f.value === row.field);
|
|
2705
|
+
return opt?.type ? { ...row, fieldType: opt.type } : row;
|
|
2706
|
+
})
|
|
2707
|
+
});
|
|
2708
|
+
setRootGroup((prev) => prev ? enrichGroup(prev) : prev);
|
|
2709
|
+
}
|
|
2710
|
+
}, [fieldOptions, enableNestedGroups]);
|
|
2711
|
+
const relationsInUse = enableNestedGroups && rootGroup ? (() => {
|
|
2712
|
+
const relations = /* @__PURE__ */ new Set();
|
|
2713
|
+
const extract = (group) => {
|
|
2714
|
+
group.items.forEach((item) => {
|
|
2715
|
+
if ("isGroup" in item && item.isGroup) {
|
|
2716
|
+
extract(item);
|
|
2717
|
+
} else {
|
|
2718
|
+
const row = item;
|
|
2719
|
+
if (row.field?.includes(".")) {
|
|
2720
|
+
relations.add(row.field.split(".")[0]);
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
});
|
|
2724
|
+
};
|
|
2725
|
+
extract(rootGroup);
|
|
2726
|
+
return relations;
|
|
2727
|
+
})() : new Set(
|
|
2191
2728
|
rows.map((r) => r.field.includes(".") ? r.field.split(".")[0] : null).filter(Boolean)
|
|
2192
2729
|
);
|
|
2193
2730
|
const updateRow = (index2, updates) => {
|
|
2194
|
-
setRows((prev) => prev.map((r, i) =>
|
|
2731
|
+
setRows((prev) => prev.map((r, i) => {
|
|
2732
|
+
if (i !== index2) return r;
|
|
2733
|
+
const merged = { ...r, ...updates };
|
|
2734
|
+
if ("field" in updates && updates.field !== void 0) {
|
|
2735
|
+
const opt = fieldOptions.find((f) => f.value === updates.field);
|
|
2736
|
+
merged.fieldType = opt?.type;
|
|
2737
|
+
const ops = getOperatorsForType(opt?.type || "string");
|
|
2738
|
+
const firstOp = ops[0]?.value ?? "eq";
|
|
2739
|
+
if (!ops.some((o) => o.value === merged.operator)) {
|
|
2740
|
+
merged.operator = firstOp;
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
return merged;
|
|
2744
|
+
}));
|
|
2195
2745
|
};
|
|
2196
2746
|
const updateConnector = (index2, logic) => {
|
|
2197
2747
|
setConnectors((prev) => {
|
|
@@ -2217,8 +2767,153 @@ const StrapiStyleFilterModal = ({
|
|
|
2217
2767
|
return prev.filter((_, i) => i !== connectorIndex);
|
|
2218
2768
|
});
|
|
2219
2769
|
};
|
|
2770
|
+
const updateGroupLogic = (groupId, logic) => {
|
|
2771
|
+
if (!rootGroup) return;
|
|
2772
|
+
const update = (group) => {
|
|
2773
|
+
if (group.id === groupId) {
|
|
2774
|
+
return { ...group, logic };
|
|
2775
|
+
}
|
|
2776
|
+
return {
|
|
2777
|
+
...group,
|
|
2778
|
+
items: group.items.map(
|
|
2779
|
+
(item) => "isGroup" in item && item.isGroup ? update(item) : item
|
|
2780
|
+
)
|
|
2781
|
+
};
|
|
2782
|
+
};
|
|
2783
|
+
setRootGroup(update(rootGroup));
|
|
2784
|
+
};
|
|
2785
|
+
const updateRowInGroup = (groupId, rowId, updates) => {
|
|
2786
|
+
if (!rootGroup) return;
|
|
2787
|
+
const update = (group) => {
|
|
2788
|
+
if (group.id === groupId) {
|
|
2789
|
+
return {
|
|
2790
|
+
...group,
|
|
2791
|
+
items: group.items.map((item) => {
|
|
2792
|
+
if (!("isGroup" in item) || !item.isGroup) {
|
|
2793
|
+
const row = item;
|
|
2794
|
+
if (row.id === rowId) {
|
|
2795
|
+
const merged = { ...row, ...updates };
|
|
2796
|
+
if ("field" in updates && updates.field !== void 0) {
|
|
2797
|
+
const opt = fieldOptions.find((f) => f.value === updates.field);
|
|
2798
|
+
merged.fieldType = opt?.type;
|
|
2799
|
+
const ops = getOperatorsForType(opt?.type || "string");
|
|
2800
|
+
const firstOp = ops[0]?.value ?? "eq";
|
|
2801
|
+
if (!ops.some((o) => o.value === merged.operator)) {
|
|
2802
|
+
merged.operator = firstOp;
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
return merged;
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
return item;
|
|
2809
|
+
})
|
|
2810
|
+
};
|
|
2811
|
+
}
|
|
2812
|
+
return {
|
|
2813
|
+
...group,
|
|
2814
|
+
items: group.items.map(
|
|
2815
|
+
(item) => "isGroup" in item && item.isGroup ? update(item) : item
|
|
2816
|
+
)
|
|
2817
|
+
};
|
|
2818
|
+
};
|
|
2819
|
+
setRootGroup(update(rootGroup));
|
|
2820
|
+
};
|
|
2821
|
+
const addRowToGroup = (groupId) => {
|
|
2822
|
+
if (!rootGroup) return;
|
|
2823
|
+
const newRow = {
|
|
2824
|
+
id: `row_${Date.now()}`,
|
|
2825
|
+
field: "",
|
|
2826
|
+
operator: "eq",
|
|
2827
|
+
value: ""
|
|
2828
|
+
};
|
|
2829
|
+
const update = (group) => {
|
|
2830
|
+
if (group.id === groupId) {
|
|
2831
|
+
return { ...group, items: [...group.items, newRow] };
|
|
2832
|
+
}
|
|
2833
|
+
return {
|
|
2834
|
+
...group,
|
|
2835
|
+
items: group.items.map(
|
|
2836
|
+
(item) => "isGroup" in item && item.isGroup ? update(item) : item
|
|
2837
|
+
)
|
|
2838
|
+
};
|
|
2839
|
+
};
|
|
2840
|
+
setRootGroup(update(rootGroup));
|
|
2841
|
+
};
|
|
2842
|
+
const removeRowFromGroup = (groupId, rowId) => {
|
|
2843
|
+
if (!rootGroup) return;
|
|
2844
|
+
const update = (group) => {
|
|
2845
|
+
if (group.id === groupId) {
|
|
2846
|
+
return {
|
|
2847
|
+
...group,
|
|
2848
|
+
items: group.items.filter((item) => {
|
|
2849
|
+
if ("isGroup" in item && item.isGroup) return true;
|
|
2850
|
+
return item.id !== rowId;
|
|
2851
|
+
})
|
|
2852
|
+
};
|
|
2853
|
+
}
|
|
2854
|
+
return {
|
|
2855
|
+
...group,
|
|
2856
|
+
items: group.items.map(
|
|
2857
|
+
(item) => "isGroup" in item && item.isGroup ? update(item) : item
|
|
2858
|
+
)
|
|
2859
|
+
};
|
|
2860
|
+
};
|
|
2861
|
+
setRootGroup(update(rootGroup));
|
|
2862
|
+
};
|
|
2863
|
+
const addNestedGroup = (parentGroupId) => {
|
|
2864
|
+
if (!rootGroup) return;
|
|
2865
|
+
const newGroup = {
|
|
2866
|
+
id: `group_${Date.now()}`,
|
|
2867
|
+
logic: "AND",
|
|
2868
|
+
items: [{
|
|
2869
|
+
id: `row_${Date.now()}`,
|
|
2870
|
+
field: "",
|
|
2871
|
+
operator: "eq",
|
|
2872
|
+
value: ""
|
|
2873
|
+
}],
|
|
2874
|
+
isGroup: true
|
|
2875
|
+
};
|
|
2876
|
+
const update = (group) => {
|
|
2877
|
+
if (group.id === parentGroupId) {
|
|
2878
|
+
return { ...group, items: [...group.items, newGroup] };
|
|
2879
|
+
}
|
|
2880
|
+
return {
|
|
2881
|
+
...group,
|
|
2882
|
+
items: group.items.map(
|
|
2883
|
+
(item) => "isGroup" in item && item.isGroup ? update(item) : item
|
|
2884
|
+
)
|
|
2885
|
+
};
|
|
2886
|
+
};
|
|
2887
|
+
setRootGroup(update(rootGroup));
|
|
2888
|
+
};
|
|
2889
|
+
const removeGroup = (groupId) => {
|
|
2890
|
+
if (!rootGroup || groupId === "root") return;
|
|
2891
|
+
const update = (group) => ({
|
|
2892
|
+
...group,
|
|
2893
|
+
items: group.items.filter((item) => {
|
|
2894
|
+
if ("isGroup" in item && item.isGroup) {
|
|
2895
|
+
return item.id !== groupId;
|
|
2896
|
+
}
|
|
2897
|
+
return true;
|
|
2898
|
+
}).map(
|
|
2899
|
+
(item) => "isGroup" in item && item.isGroup ? update(item) : item
|
|
2900
|
+
)
|
|
2901
|
+
});
|
|
2902
|
+
setRootGroup(update(rootGroup));
|
|
2903
|
+
};
|
|
2220
2904
|
const handleApply = () => {
|
|
2221
|
-
|
|
2905
|
+
if (enableNestedGroups && rootGroup) {
|
|
2906
|
+
const queryString2 = generateFromGroup(rootGroup);
|
|
2907
|
+
onApply(queryString2);
|
|
2908
|
+
onClose();
|
|
2909
|
+
return;
|
|
2910
|
+
}
|
|
2911
|
+
const validRows = rows.filter((r) => {
|
|
2912
|
+
if (!r.field) return false;
|
|
2913
|
+
if (["null", "notNull"].includes(r.operator)) return true;
|
|
2914
|
+
if (r.operator === "between") return r.value.trim() && r.valueTo?.trim();
|
|
2915
|
+
return r.value.trim();
|
|
2916
|
+
});
|
|
2222
2917
|
if (validRows.length === 0) {
|
|
2223
2918
|
onApply("");
|
|
2224
2919
|
onClose();
|
|
@@ -2229,100 +2924,322 @@ const StrapiStyleFilterModal = ({
|
|
|
2229
2924
|
onClose();
|
|
2230
2925
|
};
|
|
2231
2926
|
const handleClearAll = () => {
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2927
|
+
if (enableNestedGroups) {
|
|
2928
|
+
setRootGroup({
|
|
2929
|
+
id: "root",
|
|
2930
|
+
logic: "AND",
|
|
2931
|
+
items: [{
|
|
2932
|
+
id: `row_${Date.now()}`,
|
|
2933
|
+
field: "",
|
|
2934
|
+
operator: "eq",
|
|
2935
|
+
value: ""
|
|
2936
|
+
}],
|
|
2937
|
+
isGroup: true
|
|
2938
|
+
});
|
|
2939
|
+
} else {
|
|
2940
|
+
setRows([{
|
|
2941
|
+
id: `row_${Date.now()}`,
|
|
2942
|
+
field: "",
|
|
2943
|
+
operator: "eq",
|
|
2944
|
+
value: ""
|
|
2945
|
+
}]);
|
|
2946
|
+
setConnectors([]);
|
|
2947
|
+
}
|
|
2948
|
+
};
|
|
2949
|
+
const countActiveFilters = (group) => {
|
|
2950
|
+
let count = 0;
|
|
2951
|
+
group.items.forEach((item) => {
|
|
2952
|
+
if ("isGroup" in item && item.isGroup) {
|
|
2953
|
+
count += countActiveFilters(item);
|
|
2954
|
+
} else {
|
|
2955
|
+
const row = item;
|
|
2956
|
+
if (row.field && (["null", "notNull"].includes(row.operator) || row.value && row.value.trim())) {
|
|
2957
|
+
count++;
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
});
|
|
2961
|
+
return count;
|
|
2962
|
+
};
|
|
2963
|
+
const activeCount = enableNestedGroups && rootGroup ? countActiveFilters(rootGroup) : rows.filter((r) => r.field && (["null", "notNull"].includes(r.operator) || r.value && r.value.trim())).length;
|
|
2964
|
+
const renderGroup = (group, level = 0) => {
|
|
2965
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(GroupContainer, { $logic: group.logic, $level: level, children: [
|
|
2966
|
+
/* @__PURE__ */ jsxRuntime.jsxs(GroupHeader, { children: [
|
|
2967
|
+
/* @__PURE__ */ jsxRuntime.jsxs(LogicBadge, { $logic: group.logic, children: [
|
|
2968
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2969
|
+
LogicToggleButton,
|
|
2970
|
+
{
|
|
2971
|
+
$active: group.logic === "AND",
|
|
2972
|
+
$logic: "AND",
|
|
2973
|
+
onClick: () => updateGroupLogic(group.id, "AND"),
|
|
2974
|
+
type: "button",
|
|
2975
|
+
children: "AND"
|
|
2976
|
+
}
|
|
2977
|
+
),
|
|
2978
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2979
|
+
LogicToggleButton,
|
|
2980
|
+
{
|
|
2981
|
+
$active: group.logic === "OR",
|
|
2982
|
+
$logic: "OR",
|
|
2983
|
+
onClick: () => updateGroupLogic(group.id, "OR"),
|
|
2984
|
+
type: "button",
|
|
2985
|
+
children: "OR"
|
|
2986
|
+
}
|
|
2987
|
+
)
|
|
2988
|
+
] }),
|
|
2989
|
+
/* @__PURE__ */ jsxRuntime.jsxs(GroupActions, { children: [
|
|
2990
|
+
/* @__PURE__ */ jsxRuntime.jsx(SmallButton, { onClick: () => addRowToGroup(group.id), type: "button", children: "+ Row" }),
|
|
2991
|
+
/* @__PURE__ */ jsxRuntime.jsx(SmallButton, { onClick: () => addNestedGroup(group.id), type: "button", children: "+ Group" }),
|
|
2992
|
+
group.id !== "root" && /* @__PURE__ */ jsxRuntime.jsx(RemoveGroupButton, { onClick: () => removeGroup(group.id), type: "button", children: "Remove" })
|
|
2993
|
+
] })
|
|
2994
|
+
] }),
|
|
2995
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: group.items.map((item) => {
|
|
2996
|
+
if ("isGroup" in item && item.isGroup) {
|
|
2997
|
+
return renderGroup(item, level + 1);
|
|
2998
|
+
}
|
|
2999
|
+
const row = item;
|
|
3000
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(FilterRowCard, { children: [
|
|
3001
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FilterRowTop, { children: [
|
|
3002
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: "1 1 200px", minWidth: "140px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3003
|
+
CustomSelect,
|
|
3004
|
+
{
|
|
3005
|
+
value: row.field,
|
|
3006
|
+
onChange: (v) => updateRowInGroup(group.id, row.id, { field: v }),
|
|
3007
|
+
options: [
|
|
3008
|
+
{ value: "", label: "Select field..." },
|
|
3009
|
+
...fieldOptions
|
|
3010
|
+
],
|
|
3011
|
+
placeholder: "Select field",
|
|
3012
|
+
searchable: true
|
|
3013
|
+
}
|
|
3014
|
+
) }),
|
|
3015
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: "1 1 140px", minWidth: "120px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3016
|
+
CustomSelect,
|
|
3017
|
+
{
|
|
3018
|
+
value: row.operator,
|
|
3019
|
+
onChange: (v) => updateRowInGroup(group.id, row.id, { operator: v }),
|
|
3020
|
+
options: getOperatorsForType(row.fieldType).map((o) => ({ value: o.value, label: o.label })),
|
|
3021
|
+
placeholder: "Operator",
|
|
3022
|
+
searchable: false
|
|
3023
|
+
}
|
|
3024
|
+
) }),
|
|
3025
|
+
/* @__PURE__ */ jsxRuntime.jsxs(NegateCheckbox, { title: "Negate this condition (NOT)", children: [
|
|
3026
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3027
|
+
"input",
|
|
3028
|
+
{
|
|
3029
|
+
type: "checkbox",
|
|
3030
|
+
checked: row.negate || false,
|
|
3031
|
+
onChange: (e) => updateRowInGroup(group.id, row.id, { negate: e.target.checked })
|
|
3032
|
+
}
|
|
3033
|
+
),
|
|
3034
|
+
"NOT"
|
|
3035
|
+
] }),
|
|
3036
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3037
|
+
DeleteButton,
|
|
3038
|
+
{
|
|
3039
|
+
type: "button",
|
|
3040
|
+
onClick: () => removeRowFromGroup(group.id, row.id),
|
|
3041
|
+
title: "Remove filter",
|
|
3042
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {})
|
|
3043
|
+
}
|
|
3044
|
+
)
|
|
3045
|
+
] }),
|
|
3046
|
+
!["null", "notNull"].includes(row.operator) && /* @__PURE__ */ jsxRuntime.jsxs(FilterRowValue, { children: [
|
|
3047
|
+
/* @__PURE__ */ jsxRuntime.jsx(ValueLabel, { children: ["in", "notIn"].includes(row.operator) ? "Enter values (press Enter after each)" : ["between"].includes(row.operator) ? "Enter range" : "Enter value" }),
|
|
3048
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3049
|
+
SmartValueInput,
|
|
3050
|
+
{
|
|
3051
|
+
fieldType: row.fieldType,
|
|
3052
|
+
operator: row.operator,
|
|
3053
|
+
value: row.value,
|
|
3054
|
+
valueTo: row.valueTo,
|
|
3055
|
+
onChange: (v) => updateRowInGroup(group.id, row.id, { value: v }),
|
|
3056
|
+
onValueToChange: (v) => updateRowInGroup(group.id, row.id, { valueTo: v }),
|
|
3057
|
+
placeholder: "Value"
|
|
3058
|
+
}
|
|
3059
|
+
)
|
|
3060
|
+
] })
|
|
3061
|
+
] }, row.id);
|
|
3062
|
+
}) })
|
|
3063
|
+
] }, group.id);
|
|
2239
3064
|
};
|
|
2240
|
-
const operatorOptions = OPERATORS.map((o) => ({ value: o.value, label: o.label }));
|
|
2241
3065
|
return /* @__PURE__ */ jsxRuntime.jsx(ModalOverlay, { onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { padding: 6, onClick: (e) => e.stopPropagation(), children: [
|
|
2242
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 4, children: [
|
|
2243
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3066
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 4, style: { flexShrink: 0 }, children: [
|
|
3067
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", children: [
|
|
3068
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "h2", variant: "beta", children: "Advanced Filter" }),
|
|
3069
|
+
activeCount > 0 && /* @__PURE__ */ jsxRuntime.jsx(ActiveBadge, { children: activeCount })
|
|
3070
|
+
] }),
|
|
2244
3071
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "ghost", type: "button", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {}) })
|
|
2245
3072
|
] }),
|
|
2246
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
children: "and"
|
|
2255
|
-
}
|
|
2256
|
-
),
|
|
2257
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { margin: "0 8px", color: "var(--colors-neutral500, #8e8ea9)" }, children: "|" }),
|
|
2258
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2259
|
-
ConnectorButton,
|
|
2260
|
-
{
|
|
2261
|
-
type: "button",
|
|
2262
|
-
$active: connectors[i - 1]?.logic === "OR",
|
|
2263
|
-
onClick: () => updateConnector(i - 1, "OR"),
|
|
2264
|
-
children: "or"
|
|
2265
|
-
}
|
|
2266
|
-
)
|
|
2267
|
-
] }),
|
|
2268
|
-
/* @__PURE__ */ jsxRuntime.jsxs(FilterRowContainer, { children: [
|
|
2269
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: "1 1 140px", minWidth: "120px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2270
|
-
CustomSelect,
|
|
2271
|
-
{
|
|
2272
|
-
value: row.field,
|
|
2273
|
-
onChange: (v) => updateRow(i, { field: v }),
|
|
2274
|
-
options: [
|
|
2275
|
-
{ value: "", label: "Select field..." },
|
|
2276
|
-
...fieldOptions
|
|
2277
|
-
],
|
|
2278
|
-
placeholder: "Select field",
|
|
2279
|
-
searchable: true
|
|
2280
|
-
}
|
|
2281
|
-
) }),
|
|
2282
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: "1 1 130px", minWidth: "100px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2283
|
-
CustomSelect,
|
|
2284
|
-
{
|
|
2285
|
-
value: row.operator,
|
|
2286
|
-
onChange: (v) => updateRow(i, { operator: v }),
|
|
2287
|
-
options: [
|
|
2288
|
-
{ value: "eq", label: "is" },
|
|
2289
|
-
...operatorOptions.filter((o) => o.value !== "eq")
|
|
2290
|
-
],
|
|
2291
|
-
placeholder: "Operator",
|
|
2292
|
-
searchable: false
|
|
2293
|
-
}
|
|
2294
|
-
) }),
|
|
2295
|
-
!["null", "notNull"].includes(row.operator) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2296
|
-
ValueInput,
|
|
2297
|
-
{
|
|
2298
|
-
type: "text",
|
|
2299
|
-
value: row.value,
|
|
2300
|
-
onChange: (e) => updateRow(i, { value: e.target.value }),
|
|
2301
|
-
placeholder: "Value"
|
|
2302
|
-
}
|
|
2303
|
-
),
|
|
2304
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2305
|
-
DeleteButton,
|
|
2306
|
-
{
|
|
2307
|
-
type: "button",
|
|
2308
|
-
onClick: () => removeRow(i),
|
|
2309
|
-
title: "Remove filter",
|
|
2310
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {})
|
|
2311
|
-
}
|
|
2312
|
-
)
|
|
3073
|
+
/* @__PURE__ */ jsxRuntime.jsx(ModalScrollArea, { children: enableNestedGroups && rootGroup ? (
|
|
3074
|
+
// Nested Groups Mode
|
|
3075
|
+
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3076
|
+
renderGroup(rootGroup, 0),
|
|
3077
|
+
relationsInUse.size > 0 && /* @__PURE__ */ jsxRuntime.jsxs(InfoText, { children: [
|
|
3078
|
+
Array.from(relationsInUse).join(", "),
|
|
3079
|
+
" will be loaded automatically"
|
|
3080
|
+
] })
|
|
2313
3081
|
] })
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
3082
|
+
) : (
|
|
3083
|
+
// Flat Mode
|
|
3084
|
+
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3085
|
+
/* @__PURE__ */ jsxRuntime.jsx(RowWrapper, { children: rows.map((row, i) => /* @__PURE__ */ jsxRuntime.jsxs(React__default.default.Fragment, { children: [
|
|
3086
|
+
i > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ConnectorPill, { children: [
|
|
3087
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3088
|
+
ConnectorButton,
|
|
3089
|
+
{
|
|
3090
|
+
type: "button",
|
|
3091
|
+
$active: connectors[i - 1]?.logic === "AND",
|
|
3092
|
+
onClick: () => updateConnector(i - 1, "AND"),
|
|
3093
|
+
children: "and"
|
|
3094
|
+
}
|
|
3095
|
+
),
|
|
3096
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { margin: "0 8px", color: "var(--colors-neutral500, #8e8ea9)" }, children: "|" }),
|
|
3097
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3098
|
+
ConnectorButton,
|
|
3099
|
+
{
|
|
3100
|
+
type: "button",
|
|
3101
|
+
$active: connectors[i - 1]?.logic === "OR",
|
|
3102
|
+
onClick: () => updateConnector(i - 1, "OR"),
|
|
3103
|
+
children: "or"
|
|
3104
|
+
}
|
|
3105
|
+
)
|
|
3106
|
+
] }),
|
|
3107
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FilterRowCard, { children: [
|
|
3108
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FilterRowTop, { children: [
|
|
3109
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: "1 1 200px", minWidth: "140px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3110
|
+
CustomSelect,
|
|
3111
|
+
{
|
|
3112
|
+
value: row.field,
|
|
3113
|
+
onChange: (v) => updateRow(i, { field: v }),
|
|
3114
|
+
options: [
|
|
3115
|
+
{ value: "", label: "Select field..." },
|
|
3116
|
+
...fieldOptions
|
|
3117
|
+
],
|
|
3118
|
+
placeholder: "Select field",
|
|
3119
|
+
searchable: true
|
|
3120
|
+
}
|
|
3121
|
+
) }),
|
|
3122
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: "1 1 140px", minWidth: "120px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3123
|
+
CustomSelect,
|
|
3124
|
+
{
|
|
3125
|
+
value: row.operator,
|
|
3126
|
+
onChange: (v) => updateRow(i, { operator: v }),
|
|
3127
|
+
options: getOperatorsForType(row.fieldType).map((o) => ({ value: o.value, label: o.label })),
|
|
3128
|
+
placeholder: "Operator",
|
|
3129
|
+
searchable: false
|
|
3130
|
+
}
|
|
3131
|
+
) }),
|
|
3132
|
+
/* @__PURE__ */ jsxRuntime.jsxs(NegateCheckbox, { title: "Negate this condition (NOT)", children: [
|
|
3133
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3134
|
+
"input",
|
|
3135
|
+
{
|
|
3136
|
+
type: "checkbox",
|
|
3137
|
+
checked: row.negate || false,
|
|
3138
|
+
onChange: (e) => updateRow(i, { negate: e.target.checked })
|
|
3139
|
+
}
|
|
3140
|
+
),
|
|
3141
|
+
"NOT"
|
|
3142
|
+
] }),
|
|
3143
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3144
|
+
DeleteButton,
|
|
3145
|
+
{
|
|
3146
|
+
type: "button",
|
|
3147
|
+
onClick: () => removeRow(i),
|
|
3148
|
+
title: "Remove filter",
|
|
3149
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {})
|
|
3150
|
+
}
|
|
3151
|
+
)
|
|
3152
|
+
] }),
|
|
3153
|
+
!["null", "notNull"].includes(row.operator) && /* @__PURE__ */ jsxRuntime.jsxs(FilterRowValue, { children: [
|
|
3154
|
+
/* @__PURE__ */ jsxRuntime.jsx(ValueLabel, { children: ["in", "notIn"].includes(row.operator) ? "Enter values (press Enter after each)" : ["between"].includes(row.operator) ? "Enter range" : "Enter value" }),
|
|
3155
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3156
|
+
SmartValueInput,
|
|
3157
|
+
{
|
|
3158
|
+
fieldType: row.fieldType,
|
|
3159
|
+
operator: row.operator,
|
|
3160
|
+
value: row.value,
|
|
3161
|
+
valueTo: row.valueTo,
|
|
3162
|
+
onChange: (v) => updateRow(i, { value: v }),
|
|
3163
|
+
onValueToChange: (v) => updateRow(i, { valueTo: v }),
|
|
3164
|
+
placeholder: "Value"
|
|
3165
|
+
}
|
|
3166
|
+
)
|
|
3167
|
+
] })
|
|
3168
|
+
] })
|
|
3169
|
+
] }, row.id)) }),
|
|
3170
|
+
relationsInUse.size > 0 && /* @__PURE__ */ jsxRuntime.jsxs(InfoText, { children: [
|
|
3171
|
+
Array.from(relationsInUse).join(", "),
|
|
3172
|
+
" will be loaded automatically"
|
|
3173
|
+
] })
|
|
3174
|
+
] })
|
|
3175
|
+
) }),
|
|
3176
|
+
/* @__PURE__ */ jsxRuntime.jsx(ModalFooter, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", gap: 2, children: [
|
|
2321
3177
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClearAll, variant: "tertiary", children: "Clear All" }),
|
|
2322
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2323
|
-
|
|
3178
|
+
!enableNestedGroups && /* @__PURE__ */ jsxRuntime.jsx(AddButton, { type: "button", onClick: addRow, children: "+ Add Filter" }),
|
|
3179
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleApply, variant: "default", children: "Apply" })
|
|
3180
|
+
] }) })
|
|
2324
3181
|
] }) });
|
|
2325
3182
|
};
|
|
3183
|
+
const FEATURES = {
|
|
3184
|
+
// Free tier features
|
|
3185
|
+
basicBookmarks: { tier: "free", limit: 10 },
|
|
3186
|
+
basicFilters: { tier: "free" },
|
|
3187
|
+
// Premium tier features
|
|
3188
|
+
extendedBookmarks: { tier: "premium", limit: 50 },
|
|
3189
|
+
queryHistory: { tier: "premium" },
|
|
3190
|
+
exportBookmarks: { tier: "premium" },
|
|
3191
|
+
sharedBookmarks: { tier: "premium" },
|
|
3192
|
+
// Advanced tier features
|
|
3193
|
+
unlimitedBookmarks: { tier: "advanced", limit: -1 },
|
|
3194
|
+
advancedFilters: { tier: "advanced" },
|
|
3195
|
+
subGroups: { tier: "advanced" },
|
|
3196
|
+
bulkOperations: { tier: "advanced" },
|
|
3197
|
+
analytics: { tier: "advanced" },
|
|
3198
|
+
customIntegrations: { tier: "advanced" }
|
|
3199
|
+
};
|
|
3200
|
+
const useLicenseInfo = () => {
|
|
3201
|
+
const { get } = admin.useFetchClient();
|
|
3202
|
+
const [limits, setLimits] = React.useState(null);
|
|
3203
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
3204
|
+
React.useEffect(() => {
|
|
3205
|
+
const fetchLimits = async () => {
|
|
3206
|
+
try {
|
|
3207
|
+
console.log("[useLicenseInfo] Fetching license limits...");
|
|
3208
|
+
const response = await get("/magic-mark/license/limits");
|
|
3209
|
+
console.log("[useLicenseInfo] Raw API response:", response);
|
|
3210
|
+
console.log("[useLicenseInfo] Response data:", response.data);
|
|
3211
|
+
if (response.data?.success) {
|
|
3212
|
+
console.log("[useLicenseInfo] Setting limits:", response.data.data);
|
|
3213
|
+
setLimits(response.data.data);
|
|
3214
|
+
} else {
|
|
3215
|
+
console.warn("[useLicenseInfo] API returned success=false or missing data");
|
|
3216
|
+
}
|
|
3217
|
+
} catch (error) {
|
|
3218
|
+
console.error("[useLicenseInfo] Error fetching license limits:", error);
|
|
3219
|
+
} finally {
|
|
3220
|
+
setIsLoading(false);
|
|
3221
|
+
}
|
|
3222
|
+
};
|
|
3223
|
+
fetchLimits();
|
|
3224
|
+
}, []);
|
|
3225
|
+
const tier = limits?.tier || "free";
|
|
3226
|
+
const isPremium = tier === "premium" || tier === "advanced";
|
|
3227
|
+
const isAdvanced = tier === "advanced";
|
|
3228
|
+
console.log("[useLicenseInfo] Computed values:", { tier, isPremium, isAdvanced, limits });
|
|
3229
|
+
return {
|
|
3230
|
+
isLoading,
|
|
3231
|
+
limits,
|
|
3232
|
+
tier,
|
|
3233
|
+
isFree: tier === "free",
|
|
3234
|
+
isPremium,
|
|
3235
|
+
isAdvanced,
|
|
3236
|
+
canUseFeature: (feature) => {
|
|
3237
|
+
const featureConfig = FEATURES[feature];
|
|
3238
|
+
const tierOrder = { free: 0, premium: 1, advanced: 2 };
|
|
3239
|
+
return tierOrder[tier] >= tierOrder[featureConfig.tier];
|
|
3240
|
+
}
|
|
3241
|
+
};
|
|
3242
|
+
};
|
|
2326
3243
|
const FilterButtonGroup = styled__default.default.div`
|
|
2327
3244
|
display: flex;
|
|
2328
3245
|
align-items: center;
|
|
@@ -2400,6 +3317,7 @@ const AdvancedFilterButton = () => {
|
|
|
2400
3317
|
const navigate = reactRouterDom.useNavigate();
|
|
2401
3318
|
const location = reactRouterDom.useLocation();
|
|
2402
3319
|
const { get } = admin.useFetchClient();
|
|
3320
|
+
const { isPremium, isAdvanced } = useLicenseInfo();
|
|
2403
3321
|
const [availableFields, setAvailableFields] = React.useState([]);
|
|
2404
3322
|
const [availableRelations, setAvailableRelations] = React.useState([]);
|
|
2405
3323
|
const [hasActiveFilters, setHasActiveFilters] = React.useState(false);
|
|
@@ -2544,7 +3462,7 @@ const AdvancedFilterButton = () => {
|
|
|
2544
3462
|
title: "Open advanced filter builder",
|
|
2545
3463
|
children: [
|
|
2546
3464
|
/* @__PURE__ */ jsxRuntime.jsx(icons.Filter, {}),
|
|
2547
|
-
"
|
|
3465
|
+
"Advanced Filter",
|
|
2548
3466
|
hasActiveFilters && /* @__PURE__ */ jsxRuntime.jsx(ActiveDot, {})
|
|
2549
3467
|
]
|
|
2550
3468
|
}
|
|
@@ -2564,7 +3482,8 @@ const AdvancedFilterButton = () => {
|
|
|
2564
3482
|
onApply: handleApplyFilters,
|
|
2565
3483
|
availableFields,
|
|
2566
3484
|
availableRelations,
|
|
2567
|
-
currentQuery: getCurrentFilters()
|
|
3485
|
+
currentQuery: getCurrentFilters(),
|
|
3486
|
+
enableNestedGroups: isPremium || isAdvanced
|
|
2568
3487
|
}
|
|
2569
3488
|
)
|
|
2570
3489
|
] });
|
|
@@ -2587,7 +3506,7 @@ const index = {
|
|
|
2587
3506
|
id: `${pluginId}.Admin.MainMenu.PluginName`,
|
|
2588
3507
|
defaultMessage: name
|
|
2589
3508
|
},
|
|
2590
|
-
Component: () => Promise.resolve().then(() => require("./App-
|
|
3509
|
+
Component: () => Promise.resolve().then(() => require("./App-DNyxeldt.js")),
|
|
2591
3510
|
permissions: []
|
|
2592
3511
|
});
|
|
2593
3512
|
app.createSettingSection(
|
|
@@ -2608,7 +3527,7 @@ const index = {
|
|
|
2608
3527
|
to: `${pluginId}/upgrade`,
|
|
2609
3528
|
Component: () => Promise.resolve().then(() => require(
|
|
2610
3529
|
/* webpackChunkName: "magic-mark-upgrade" */
|
|
2611
|
-
"./UpgradePage-
|
|
3530
|
+
"./UpgradePage-SzlmS6po.js"
|
|
2612
3531
|
)),
|
|
2613
3532
|
permissions: []
|
|
2614
3533
|
},
|
|
@@ -2696,3 +3615,4 @@ exports.CreateEditModal = CreateEditModal;
|
|
|
2696
3615
|
exports.getIconById = getIconById;
|
|
2697
3616
|
exports.index = index;
|
|
2698
3617
|
exports.pluginId = pluginId;
|
|
3618
|
+
exports.useLicenseInfo = useLicenseInfo;
|