@stoker-platform/web-app 0.5.225 → 0.5.227
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/CHANGELOG.md +12 -0
- package/package.json +1 -1
- package/src/Collection.tsx +7 -2
- package/src/Filters.tsx +34 -12
- package/src/List.tsx +8 -8
- package/src/providers/FiltersProvider.tsx +18 -4
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
package/src/Collection.tsx
CHANGED
|
@@ -1541,9 +1541,14 @@ function Collection({
|
|
|
1541
1541
|
}
|
|
1542
1542
|
}
|
|
1543
1543
|
if (relationList) {
|
|
1544
|
+
const relationListField = getField(fields, relationList.field)
|
|
1545
|
+
const relationListUsesArrayContains = ["ManyToOne", "ManyToMany"].includes(relationListField.type)
|
|
1544
1546
|
filters.forEach((filter) => {
|
|
1545
1547
|
if (filter.type === "relation") {
|
|
1546
|
-
if (
|
|
1548
|
+
if (
|
|
1549
|
+
filter.field === relationList.field ||
|
|
1550
|
+
(!isPreloadCacheEnabled && relationListUsesArrayContains)
|
|
1551
|
+
) {
|
|
1547
1552
|
excluded.push(filter.field)
|
|
1548
1553
|
}
|
|
1549
1554
|
}
|
|
@@ -1553,7 +1558,7 @@ function Collection({
|
|
|
1553
1558
|
}
|
|
1554
1559
|
}
|
|
1555
1560
|
return excluded
|
|
1556
|
-
}, [isPreloadCacheEnabled, cardsConfig, statusField, tab, filters])
|
|
1561
|
+
}, [isPreloadCacheEnabled, cardsConfig, statusField, tab, filters, relationList, fields])
|
|
1557
1562
|
|
|
1558
1563
|
const filtersActive = useMemo(() => {
|
|
1559
1564
|
return (
|
package/src/Filters.tsx
CHANGED
|
@@ -103,9 +103,12 @@ export function Filters({
|
|
|
103
103
|
|
|
104
104
|
const preventChange = isRouteLoadingImmediate.has(location.pathname)
|
|
105
105
|
|
|
106
|
-
const
|
|
106
|
+
const isArrayContainsFilter = useCallback(
|
|
107
107
|
(filter: Filter): filter is SelectFilter | RelationFilter => {
|
|
108
|
-
if (filter.type === "relation")
|
|
108
|
+
if (filter.type === "relation") {
|
|
109
|
+
const fieldSchema = getField(fields, filter.field)
|
|
110
|
+
return ["ManyToOne", "ManyToMany"].includes(fieldSchema.type)
|
|
111
|
+
}
|
|
109
112
|
if (filter.type === "select") {
|
|
110
113
|
const fieldSchema = getField(fields, filter.field)
|
|
111
114
|
return fieldSchema.type === "Array"
|
|
@@ -116,11 +119,13 @@ export function Filters({
|
|
|
116
119
|
)
|
|
117
120
|
|
|
118
121
|
const isIncludeAssignedActive = useCallback(() => {
|
|
119
|
-
if (!isAssigning || !assignable?.includeAssignedInFilters?.length) return false
|
|
122
|
+
if (!isAssigning || !assignable?.includeAssignedInFilters?.length || !relationList) return false
|
|
123
|
+
const relationField = getField(fields, relationList.field)
|
|
124
|
+
if (["OneToOne", "OneToMany"].includes(relationField.type)) return false
|
|
120
125
|
return assignable.includeAssignedInFilters.some((field) =>
|
|
121
126
|
filters.some((filter) => filter.type === "select" && filter.field === field && filter.value),
|
|
122
127
|
)
|
|
123
|
-
}, [isAssigning, assignable, filters])
|
|
128
|
+
}, [isAssigning, assignable, filters, relationList, fields])
|
|
124
129
|
|
|
125
130
|
const isMobile = useIsMobile()
|
|
126
131
|
const someFilterOpen = Object.values(open).some(Boolean)
|
|
@@ -213,14 +218,14 @@ export function Filters({
|
|
|
213
218
|
}
|
|
214
219
|
}
|
|
215
220
|
|
|
216
|
-
const
|
|
217
|
-
(filter): filter is SelectFilter | RelationFilter => !!filter.value &&
|
|
221
|
+
const arrayContainsFilter = filters.find(
|
|
222
|
+
(filter): filter is SelectFilter | RelationFilter => !!filter.value && isArrayContainsFilter(filter),
|
|
218
223
|
)
|
|
219
|
-
if (
|
|
220
|
-
arrayOrRelationField =
|
|
224
|
+
if (arrayContainsFilter) {
|
|
225
|
+
arrayOrRelationField = arrayContainsFilter.field
|
|
221
226
|
}
|
|
222
227
|
setArrayContainsFilterSet(arrayOrRelationField)
|
|
223
|
-
}, [filters, isAssigning, assignable, isPreloadCacheEnabled, isIncludeAssignedActive,
|
|
228
|
+
}, [filters, isAssigning, assignable, isPreloadCacheEnabled, isIncludeAssignedActive, isArrayContainsFilter])
|
|
224
229
|
|
|
225
230
|
const handleChange = useCallback(
|
|
226
231
|
(filter: Filter, value: string, type: CollectionField["type"]) => {
|
|
@@ -454,19 +459,36 @@ export function Filters({
|
|
|
454
459
|
(filter: Filter) => {
|
|
455
460
|
if (filter.type === "range" || filter.type === "status") return false
|
|
456
461
|
const fieldSchema = getField(fields, filter.field)
|
|
462
|
+
const relationField = relationList ? getField(fields, relationList.field) : undefined
|
|
463
|
+
const includeAssignedUsesArrayContains =
|
|
464
|
+
isAssigning &&
|
|
465
|
+
!!assignable?.includeAssignedInFilters?.includes(filter.field) &&
|
|
466
|
+
!!relationField &&
|
|
467
|
+
["ManyToOne", "ManyToMany"].includes(relationField.type)
|
|
457
468
|
return !!(
|
|
458
469
|
(!isPreloadCacheEnabled &&
|
|
459
470
|
arrayContainsFilterSet &&
|
|
460
471
|
arrayContainsFilterSet !== filter.field &&
|
|
461
|
-
(filter.type === "relation" ||
|
|
472
|
+
((filter.type === "relation" && ["ManyToOne", "ManyToMany"].includes(fieldSchema.type)) ||
|
|
462
473
|
fieldSchema.type === "Array" ||
|
|
463
|
-
|
|
474
|
+
includeAssignedUsesArrayContains)) ||
|
|
464
475
|
(isRelationField(fieldSchema) &&
|
|
465
476
|
connectionStatus === "offline" &&
|
|
466
477
|
!preloadCacheEnabled(schema.collections[fieldSchema.collection]))
|
|
467
478
|
)
|
|
468
479
|
},
|
|
469
|
-
[
|
|
480
|
+
[
|
|
481
|
+
isPreloadCacheEnabled,
|
|
482
|
+
arrayContainsFilterSet,
|
|
483
|
+
isRouteLoading,
|
|
484
|
+
location.pathname,
|
|
485
|
+
fields,
|
|
486
|
+
relationList,
|
|
487
|
+
isAssigning,
|
|
488
|
+
assignable,
|
|
489
|
+
connectionStatus,
|
|
490
|
+
schema,
|
|
491
|
+
],
|
|
470
492
|
)
|
|
471
493
|
|
|
472
494
|
return (
|
package/src/List.tsx
CHANGED
|
@@ -1345,9 +1345,9 @@ export function List({
|
|
|
1345
1345
|
if (permissions?.Role && (!metric.roles || metric.roles.includes(permissions?.Role))) {
|
|
1346
1346
|
if (metric.type === "custom" && metric.formula) {
|
|
1347
1347
|
// eslint-disable-next-line security/detect-object-injection
|
|
1348
|
-
values[index] = metric.formula(
|
|
1348
|
+
values[index] = metric.formula(searchList).toString() || ""
|
|
1349
1349
|
} else if (metric.type === "count") {
|
|
1350
|
-
let value = (
|
|
1350
|
+
let value = (searchList.length || 0).toString()
|
|
1351
1351
|
if (metric.prefix) {
|
|
1352
1352
|
value = `${metric.prefix}${value}`
|
|
1353
1353
|
}
|
|
@@ -1361,7 +1361,7 @@ export function List({
|
|
|
1361
1361
|
let value: string
|
|
1362
1362
|
const field = getField(fields, metric.field)
|
|
1363
1363
|
const fieldCustomization = getFieldCustomization(field, customization)
|
|
1364
|
-
|
|
1364
|
+
searchList.forEach((record: StokerRecord) => {
|
|
1365
1365
|
if (!metric.field) return
|
|
1366
1366
|
const value = record[metric.field]
|
|
1367
1367
|
if (field.type === "Number" && typeof value === "number") {
|
|
@@ -1395,7 +1395,7 @@ export function List({
|
|
|
1395
1395
|
let value: string
|
|
1396
1396
|
const field = getField(fields, metric.field)
|
|
1397
1397
|
const fieldCustomization = getFieldCustomization(field, customization)
|
|
1398
|
-
|
|
1398
|
+
searchList.forEach((record: StokerRecord) => {
|
|
1399
1399
|
if (!metric.field) return
|
|
1400
1400
|
const value = record[metric.field]
|
|
1401
1401
|
if (field.type === "Number" && typeof value === "number") {
|
|
@@ -1406,7 +1406,7 @@ export function List({
|
|
|
1406
1406
|
total = newTotal
|
|
1407
1407
|
}
|
|
1408
1408
|
})
|
|
1409
|
-
const average = total /
|
|
1409
|
+
const average = total / searchList.length || 0
|
|
1410
1410
|
const currency = tryFunction(fieldCustomization?.admin?.currency)
|
|
1411
1411
|
if (currency) {
|
|
1412
1412
|
value = `${currency}${average.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
|
|
@@ -1424,7 +1424,7 @@ export function List({
|
|
|
1424
1424
|
} else if (metric.type === "area") {
|
|
1425
1425
|
if (metric.metricField1) {
|
|
1426
1426
|
const chartData: MetricValue = []
|
|
1427
|
-
|
|
1427
|
+
searchList.forEach((record: StokerRecord) => {
|
|
1428
1428
|
if (!record[metric.dateField] || !metric.metricField1) return
|
|
1429
1429
|
const date = DateTime.fromJSDate((record[metric.dateField] as Timestamp).toDate(), {
|
|
1430
1430
|
zone: timezone,
|
|
@@ -1460,7 +1460,7 @@ export function List({
|
|
|
1460
1460
|
const chartData: MetricValue = []
|
|
1461
1461
|
const dateMap = new Map<string, number>()
|
|
1462
1462
|
|
|
1463
|
-
|
|
1463
|
+
searchList.forEach((record: StokerRecord) => {
|
|
1464
1464
|
if (!record[metric.dateField]) return
|
|
1465
1465
|
const date = DateTime.fromJSDate((record[metric.dateField] as Timestamp).toDate(), {
|
|
1466
1466
|
zone: timezone,
|
|
@@ -1489,7 +1489,7 @@ export function List({
|
|
|
1489
1489
|
}
|
|
1490
1490
|
})
|
|
1491
1491
|
return values
|
|
1492
|
-
}, [list])
|
|
1492
|
+
}, [list, searchList])
|
|
1493
1493
|
|
|
1494
1494
|
const [timeRange, setTimeRange] = useState<Record<string, string>>({})
|
|
1495
1495
|
|
|
@@ -152,11 +152,17 @@ export const FiltersProvider: React.FC<FiltersProviderProps> = ({
|
|
|
152
152
|
if (includeValueInFilters) {
|
|
153
153
|
filterValues.push(includeValueInFilters.includeValue as string | number)
|
|
154
154
|
}
|
|
155
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
156
|
+
const relationField = getField(fields, relationList!.field)
|
|
157
|
+
const assignedConstraint = ["OneToOne", "OneToMany"].includes(relationField.type)
|
|
158
|
+
? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
159
|
+
where(`${relationList!.field}_Single.id`, "==", relationParent!.id)
|
|
160
|
+
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
161
|
+
where(`${relationList!.field}_Array`, "array-contains", relationParent!.id)
|
|
155
162
|
constraints.push(
|
|
156
163
|
or(
|
|
157
164
|
where(filter.field, "in", filterValues),
|
|
158
|
-
|
|
159
|
-
where(`${relationList!.field}_Array`, "array-contains", relationParent!.id),
|
|
165
|
+
assignedConstraint,
|
|
160
166
|
) as unknown as QueryConstraint,
|
|
161
167
|
)
|
|
162
168
|
} else if (isAssigning && includeValueInFilters) {
|
|
@@ -169,7 +175,11 @@ export const FiltersProvider: React.FC<FiltersProviderProps> = ({
|
|
|
169
175
|
}
|
|
170
176
|
if (filter.type === "relation") {
|
|
171
177
|
const field = getField(fields, filter.field)
|
|
172
|
-
|
|
178
|
+
if (["OneToOne", "OneToMany"].includes(field.type)) {
|
|
179
|
+
constraints.push(where(`${field.name}_Single.id`, "==", filter.value))
|
|
180
|
+
} else {
|
|
181
|
+
constraints.push(where(`${field.name}_Array`, "array-contains", filter.value))
|
|
182
|
+
}
|
|
173
183
|
}
|
|
174
184
|
})
|
|
175
185
|
if (!isPreloadCacheEnabled) {
|
|
@@ -240,7 +250,11 @@ export const FiltersProvider: React.FC<FiltersProviderProps> = ({
|
|
|
240
250
|
}
|
|
241
251
|
if (filter.type === "relation") {
|
|
242
252
|
const field = getField(fields, filter.field)
|
|
243
|
-
|
|
253
|
+
if (["OneToOne", "OneToMany"].includes(field.type)) {
|
|
254
|
+
constraints.push([`${field.name}_Single.id`, "==", filter.value])
|
|
255
|
+
} else {
|
|
256
|
+
constraints.push([`${field.name}_Array`, "array-contains", filter.value])
|
|
257
|
+
}
|
|
244
258
|
}
|
|
245
259
|
})
|
|
246
260
|
if (!isPreloadCacheEnabled) {
|