@stoker-platform/web-app 0.5.193 → 0.5.195

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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # @stoker-platform/web-app
2
2
 
3
+ ## 0.5.195
4
+
5
+ ### Patch Changes
6
+
7
+ - fix: fix infinite scroll stale records issue
8
+
9
+ ## 0.5.194
10
+
11
+ ### Patch Changes
12
+
13
+ - feat: allow Dashboard elements to query the server in preload cache mode
14
+ - Updated dependencies
15
+ - @stoker-platform/web-client@0.5.79
16
+ - @stoker-platform/node-client@0.5.77
17
+ - @stoker-platform/utils@0.5.68
18
+
3
19
  ## 0.5.193
4
20
 
5
21
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stoker-platform/web-app",
3
- "version": "0.5.193",
3
+ "version": "0.5.195",
4
4
  "type": "module",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "scripts": {
@@ -51,9 +51,9 @@
51
51
  "@radix-ui/react-tooltip": "^1.2.8",
52
52
  "@react-google-maps/api": "^2.20.8",
53
53
  "@sentry/react": "^10.56.0",
54
- "@stoker-platform/node-client": "0.5.76",
55
- "@stoker-platform/utils": "0.5.67",
56
- "@stoker-platform/web-client": "0.5.78",
54
+ "@stoker-platform/node-client": "0.5.77",
55
+ "@stoker-platform/utils": "0.5.68",
56
+ "@stoker-platform/web-client": "0.5.79",
57
57
  "@tanstack/react-table": "^8.21.3",
58
58
  "@types/react": "18.3.13",
59
59
  "@types/react-dom": "18.3.1",
@@ -375,9 +375,6 @@ function Collection({
375
375
  }, [serverList])
376
376
 
377
377
  useEffect(() => {
378
- if (isAssigning !== undefined) {
379
- setBackToStartKey((prev) => prev + 1)
380
- }
381
378
  if (!relationList || !isInitialized) return
382
379
  setFilters((prev) => {
383
380
  let next = prev
@@ -397,7 +394,7 @@ function Collection({
397
394
  }
398
395
  return next
399
396
  })
400
- }, [isAssigning])
397
+ }, [isAssigning, isInitialized])
401
398
 
402
399
  // This is to ensure that the optimistic list is set in cases where cached documents exactly match the downloaded server documents
403
400
  // In this case, the cache-only snapshot listener does not fire a second time when the cache has loaded because there is no change to the list
@@ -61,7 +61,7 @@ export const DashboardMetric = ({ metric, title, collection }: DashboardMetricPr
61
61
 
62
62
  useEffect(() => {
63
63
  debouncedSetIsLoading(true)
64
- getData(collectionSchema, constraints, debouncedSetIsLoading, setResults, setUnsubscribe)
64
+ getData(collectionSchema, constraints, debouncedSetIsLoading, setResults, setUnsubscribe, metric.forceServer)
65
65
  return () => {
66
66
  unsubscribe?.forEach((unsubscribe) => unsubscribe())
67
67
  if (loadingTimeoutRef.current) {
@@ -17,7 +17,6 @@ import { Card, CardContent } from "./components/ui/card"
17
17
  import { useConnection } from "./providers/ConnectionProvider"
18
18
  import { getField, getFieldCustomization, isRelationField, tryFunction } from "@stoker-platform/utils"
19
19
  import { getFormattedFieldValue } from "./utils/getFormattedFieldValue"
20
- import { getSortingValue } from "./utils/getSortingValue"
21
20
 
22
21
  interface DashboardReminderProps {
23
22
  reminder: Reminder
@@ -49,6 +48,10 @@ export const DashboardReminder = ({ reminder, title, collection }: DashboardRemi
49
48
  const [rowHighlight, setRowHighlight] = useState<RowHighlight[] | undefined>(undefined)
50
49
  const pages = 5
51
50
 
51
+ const setResultsCallback = useCallback((results: StokerRecord[]) => {
52
+ setResults(reminder.filter ? results.filter((result) => reminder.filter?.(result)) : results)
53
+ }, [])
54
+
52
55
  const loadingTimeoutRef = useRef<NodeJS.Timeout | null>(null)
53
56
  const debouncedSetIsLoading = useCallback((loading: boolean) => {
54
57
  if (loading) {
@@ -96,7 +99,14 @@ export const DashboardReminder = ({ reminder, title, collection }: DashboardRemi
96
99
  }
97
100
  initialize()
98
101
  debouncedSetIsLoading(true)
99
- getData(collectionSchema, constraints, debouncedSetIsLoading, setResults, setUnsubscribe)
102
+ getData(
103
+ collectionSchema,
104
+ constraints,
105
+ debouncedSetIsLoading,
106
+ setResultsCallback,
107
+ setUnsubscribe,
108
+ reminder.forceServer,
109
+ )
100
110
  return () => {
101
111
  unsubscribe?.forEach((unsubscribe) => unsubscribe())
102
112
  if (loadingTimeoutRef.current) {
@@ -199,60 +209,26 @@ export const DashboardReminder = ({ reminder, title, collection }: DashboardRemi
199
209
  </TableRow>
200
210
  ) : (
201
211
  results
212
+ .slice(page * pages, (page + 1) * pages)
202
213
  .sort((a, b) => {
203
214
  if (!sorting) return 0
204
215
  const sortingField = getField(fields, sorting.field)
205
- const valueA = getSortingValue(
206
- collectionSchema,
216
+ const fieldCustomization = getFieldCustomization(
217
+ sortingField,
207
218
  customization,
208
- sorting.field,
209
- a,
210
219
  )
211
- const valueB = getSortingValue(
212
- collectionSchema,
213
- customization,
214
- sorting.field,
215
- b,
216
- )
217
- let result: number
218
- if (sortingField.type === "String") {
219
- const rawA = valueA?.toString().toLowerCase() ?? ""
220
- const rawB = valueB?.toString().toLowerCase() ?? ""
221
- result = rawA > rawB ? 1 : rawA < rawB ? -1 : 0
222
- } else if (isRelationField(sortingField)) {
223
- const titleField = sortingField.titleField
224
- let rawA: string
225
- let rawB: string
226
- if (titleField) {
227
- const recordA = Object.values(a[sortingField.name] ?? {})[0] as
228
- | StokerRecord
229
- | undefined
230
- const recordB = Object.values(b[sortingField.name] ?? {})[0] as
231
- | StokerRecord
232
- | undefined
233
- // eslint-disable-next-line security/detect-object-injection
234
- rawA = recordA?.[titleField]?.toString().toLowerCase() ?? ""
235
- // eslint-disable-next-line security/detect-object-injection
236
- rawB = recordB?.[titleField]?.toString().toLowerCase() ?? ""
237
- } else {
238
- rawA = (
239
- Object.keys(a[sortingField.name] ?? {})[0] ?? ""
240
- ).toLowerCase()
241
- rawB = (
242
- Object.keys(b[sortingField.name] ?? {})[0] ?? ""
243
- ).toLowerCase()
244
- }
245
- result = rawA > rawB ? 1 : rawA < rawB ? -1 : 0
246
- } else if (sortingField.type === "Timestamp") {
247
- const rawA = Number(valueA?.valueOf() || 0)
248
- const rawB = Number(valueB?.valueOf() || 0)
249
- result = rawA > rawB ? 1 : rawA < rawB ? -1 : 0
220
+ let sortA = a[sorting.field]
221
+ let sortB = b[sorting.field]
222
+ if (fieldCustomization.admin?.sort) {
223
+ sortA = tryFunction(fieldCustomization.admin?.sort, [a])
224
+ sortB = tryFunction(fieldCustomization.admin?.sort, [b])
225
+ }
226
+ if (sorting.direction === "asc") {
227
+ return sortA - sortB
250
228
  } else {
251
- result = valueA > valueB ? 1 : valueA < valueB ? -1 : 0
229
+ return sortB - sortA
252
230
  }
253
- return sorting.direction === "asc" ? result : -result
254
231
  })
255
- .slice(page * pages, (page + 1) * pages)
256
232
  .map((result: StokerRecord) => (
257
233
  <TableRow
258
234
  key={result.id}
package/src/Images.tsx CHANGED
@@ -370,6 +370,8 @@ export const Images = memo(
370
370
  const [orderByField, setOrderByField] = useState<string | undefined>(undefined)
371
371
  const [orderByDirection, setOrderByDirection] = useState<"asc" | "desc" | undefined>(undefined)
372
372
 
373
+ const infiniteLoaderRef = useRef<InfiniteLoader>(null)
374
+
373
375
  const backToStart = useCallback(
374
376
  (
375
377
  latestConstraints?: QueryConstraint[],
@@ -377,6 +379,7 @@ export const Images = memo(
377
379
  latestOrderByDirection?: "asc" | "desc",
378
380
  ) => {
379
381
  return new Promise<void>((resolve) => {
382
+ infiniteLoaderRef.current?.resetloadMoreItemsCache()
380
383
  setServerList({})
381
384
  setList({})
382
385
  const newQuery = {
@@ -659,6 +662,7 @@ export const Images = memo(
659
662
 
660
663
  useEffect(() => {
661
664
  setIsFirstLoad(true)
665
+ setPrevIds(new Set())
662
666
  }, [filters, orderByField, orderByDirection])
663
667
 
664
668
  useEffect(() => {
@@ -838,6 +842,7 @@ export const Images = memo(
838
842
  >
839
843
  {!formList && (meta?.title || collectionTitle) && <Meta />}
840
844
  <InfiniteLoader
845
+ ref={infiniteLoaderRef}
841
846
  isItemLoaded={(index) => index < itemCount}
842
847
  itemCount={100000}
843
848
  loadMoreItems={loadMoreItems}
@@ -11,6 +11,7 @@ export const getData = async (
11
11
  setLoading: (loading: boolean) => void,
12
12
  setResults: (results: StokerRecord[]) => void,
13
13
  setUnsubscribe: (value: React.SetStateAction<Unsubscribe[] | undefined>) => void,
14
+ forceServer?: boolean,
14
15
  ) => {
15
16
  const { labels } = collection
16
17
  const isPreloadCacheEnabled = preloadCacheEnabled(collection)
@@ -65,7 +66,10 @@ export const getData = async (
65
66
  }
66
67
  resolve()
67
68
  },
68
- { constraints: currentQuery.constraints as QueryConstraint[] },
69
+ {
70
+ constraints: currentQuery.constraints as QueryConstraint[],
71
+ only: forceServer ? "default" : undefined,
72
+ },
69
73
  )
70
74
  const { unsubscribe: newUnsubscribe } = result
71
75
  promiseLoaded = true