@nixxie-cms/core 2.0.0 → 2.2.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/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.cjs.js +7 -7
- package/admin-ui/components/dist/nixxie-cms-core-admin-ui-components.esm.js +7 -7
- package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.cjs.js +2 -2
- package/admin-ui/context/dist/nixxie-cms-core-admin-ui-context.esm.js +2 -2
- package/admin-ui/utils/dist/nixxie-cms-core-admin-ui-utils.cjs.js +5 -5
- package/admin-ui/utils/dist/nixxie-cms-core-admin-ui-utils.esm.js +3 -3
- package/dist/{CreateItemDialog-7008b050.esm.js → CreateItemDialog-66621fe8.esm.js} +3 -3
- package/dist/{CreateItemDialog-a0cab315.cjs.js → CreateItemDialog-96b044ce.cjs.js} +4 -4
- package/dist/{Field-47f85161.esm.js → Field-1820c4e6.esm.js} +1 -0
- package/dist/{Field-ed8d7627.cjs.js → Field-38d3cdf9.cjs.js} +1 -0
- package/dist/GraphQLErrorNotice-7594a9f8.esm.js +64 -0
- package/dist/GraphQLErrorNotice-c8890f80.cjs.js +66 -0
- package/dist/{PageContainer-5ae731cc.esm.js → PageContainer-355cfbfa.esm.js} +362 -156
- package/dist/{PageContainer-abd7159f.cjs.js → PageContainer-4095555a.cjs.js} +361 -155
- package/dist/{context-af9957ed.esm.js → context-2924eaaa.esm.js} +53 -58
- package/dist/{context-b5204629.cjs.js → context-2ce61d0b.cjs.js} +53 -58
- package/dist/declarations/src/admin-ui/components/GraphQLErrorNotice.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/components/Navigation.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/components/PageContainer.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/context.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/utils/useCreateItem.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/bigInt/views/index.d.ts +2 -1
- package/dist/declarations/src/fields/types/bigInt/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/bytes/views/index.d.ts +2 -1
- package/dist/declarations/src/fields/types/bytes/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/calendarDay/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/decimal/views/index.d.ts +2 -1
- package/dist/declarations/src/fields/types/decimal/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/float/views/index.d.ts +2 -1
- package/dist/declarations/src/fields/types/float/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/integer/views/index.d.ts +2 -1
- package/dist/declarations/src/fields/types/integer/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/json/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/multiselect/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/relationship/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/select/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/text/views/index.d.ts +2 -1
- package/dist/declarations/src/fields/types/text/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/timestamp/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/virtual/views/index.d.ts.map +1 -1
- package/dist/declarations/src/internal-unstable/admin-ui/pages/HomePage/index.d.ts.map +1 -1
- package/dist/declarations/src/internal-unstable/admin-ui/pages/ItemPage/index.d.ts.map +1 -1
- package/dist/pick-4c785a54.esm.js +34 -0
- package/dist/pick-906341bb.cjs.js +37 -0
- package/dist/{useCreateItem-1f94d252.esm.js → useCreateItem-36a75f1c.esm.js} +26 -26
- package/dist/{useCreateItem-1be4987e.cjs.js → useCreateItem-acf06f77.cjs.js} +37 -37
- package/dist/{useFilter-acc9d413.cjs.js → useFilter-c29f17a8.cjs.js} +1 -1
- package/dist/{useFilter-9b6db1f9.esm.js → useFilter-f79b2abb.esm.js} +1 -1
- package/dist/{Fields-956d9a14.esm.js → usePreventNavigation-093389dd.esm.js} +28 -2
- package/dist/{Fields-e2c28056.cjs.js → usePreventNavigation-d4f9f4fa.cjs.js} +27 -0
- package/fields/types/bigInt/views/dist/nixxie-cms-core-fields-types-bigInt-views.cjs.js +8 -0
- package/fields/types/bigInt/views/dist/nixxie-cms-core-fields-types-bigInt-views.esm.js +8 -1
- package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.cjs.js +14 -3
- package/fields/types/bytes/views/dist/nixxie-cms-core-fields-types-bytes-views.esm.js +15 -5
- package/fields/types/calendarDay/views/dist/nixxie-cms-core-fields-types-calendarDay-views.cjs.js +2 -1
- package/fields/types/calendarDay/views/dist/nixxie-cms-core-fields-types-calendarDay-views.esm.js +2 -1
- package/fields/types/decimal/views/dist/nixxie-cms-core-fields-types-decimal-views.cjs.js +10 -1
- package/fields/types/decimal/views/dist/nixxie-cms-core-fields-types-decimal-views.esm.js +10 -2
- package/fields/types/file/views/dist/nixxie-cms-core-fields-types-file-views.cjs.js +1 -1
- package/fields/types/file/views/dist/nixxie-cms-core-fields-types-file-views.esm.js +2 -2
- package/fields/types/float/views/dist/nixxie-cms-core-fields-types-float-views.cjs.js +10 -1
- package/fields/types/float/views/dist/nixxie-cms-core-fields-types-float-views.esm.js +10 -2
- package/fields/types/image/views/dist/nixxie-cms-core-fields-types-image-views.cjs.js +2 -1
- package/fields/types/image/views/dist/nixxie-cms-core-fields-types-image-views.esm.js +2 -1
- package/fields/types/integer/views/dist/nixxie-cms-core-fields-types-integer-views.cjs.js +8 -0
- package/fields/types/integer/views/dist/nixxie-cms-core-fields-types-integer-views.esm.js +8 -1
- package/fields/types/json/views/dist/nixxie-cms-core-fields-types-json-views.cjs.js +19 -4
- package/fields/types/json/views/dist/nixxie-cms-core-fields-types-json-views.esm.js +19 -4
- package/fields/types/multiselect/views/dist/nixxie-cms-core-fields-types-multiselect-views.cjs.js +18 -3
- package/fields/types/multiselect/views/dist/nixxie-cms-core-fields-types-multiselect-views.esm.js +18 -3
- package/fields/types/password/views/dist/nixxie-cms-core-fields-types-password-views.cjs.js +1 -1
- package/fields/types/password/views/dist/nixxie-cms-core-fields-types-password-views.esm.js +1 -1
- package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.cjs.js +9 -7
- package/fields/types/relationship/views/dist/nixxie-cms-core-fields-types-relationship-views.esm.js +9 -7
- package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.cjs.js +3 -2
- package/fields/types/select/views/dist/nixxie-cms-core-fields-types-select-views.esm.js +3 -2
- package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.cjs.js +14 -3
- package/fields/types/text/views/dist/nixxie-cms-core-fields-types-text-views.esm.js +15 -5
- package/fields/types/timestamp/views/dist/nixxie-cms-core-fields-types-timestamp-views.cjs.js +2 -1
- package/fields/types/timestamp/views/dist/nixxie-cms-core-fields-types-timestamp-views.esm.js +2 -1
- package/fields/types/virtual/views/dist/nixxie-cms-core-fields-types-virtual-views.cjs.js +13 -1
- package/fields/types/virtual/views/dist/nixxie-cms-core-fields-types-virtual-views.esm.js +14 -2
- package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.cjs.js +3 -3
- package/internal-unstable/admin-ui/pages/App/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-App.esm.js +3 -3
- package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.cjs.js +7 -7
- package/internal-unstable/admin-ui/pages/CreateItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-CreateItemPage.esm.js +6 -6
- package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.cjs.js +34 -33
- package/internal-unstable/admin-ui/pages/HomePage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-HomePage.esm.js +35 -34
- package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.cjs.js +53 -13
- package/internal-unstable/admin-ui/pages/ItemPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ItemPage.esm.js +52 -12
- package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.cjs.js +36 -25
- package/internal-unstable/admin-ui/pages/ListPage/dist/nixxie-cms-core-internal-unstable-admin-ui-pages-ListPage.esm.js +36 -25
- package/package.json +2 -2
- package/src/admin-ui/components/CommandPalette.tsx +134 -27
- package/src/admin-ui/components/CreateButtonLink.tsx +20 -46
- package/src/admin-ui/components/GraphQLErrorNotice.tsx +39 -33
- package/src/admin-ui/components/Logo.tsx +5 -5
- package/src/admin-ui/components/Navigation.tsx +41 -27
- package/src/admin-ui/components/PageContainer.tsx +171 -15
- package/src/admin-ui/components/WelcomeDialog.tsx +14 -14
- package/src/admin-ui/context.tsx +5 -2
- package/src/admin-ui/utils/useCreateItem.ts +21 -1
- package/src/fields/types/bigInt/views/index.tsx +10 -1
- package/src/fields/types/bytes/views/index.tsx +14 -1
- package/src/fields/types/calendarDay/views/index.tsx +2 -1
- package/src/fields/types/decimal/views/index.tsx +7 -1
- package/src/fields/types/file/views/Field.tsx +1 -1
- package/src/fields/types/float/views/index.tsx +7 -1
- package/src/fields/types/image/views/index.tsx +1 -1
- package/src/fields/types/integer/views/index.tsx +5 -0
- package/src/fields/types/json/views/index.tsx +20 -2
- package/src/fields/types/multiselect/views/index.tsx +7 -3
- package/src/fields/types/password/views/index.tsx +1 -1
- package/src/fields/types/relationship/views/index.tsx +1 -0
- package/src/fields/types/select/views/index.tsx +2 -1
- package/src/fields/types/text/views/index.tsx +14 -1
- package/src/fields/types/timestamp/views/__tests__/index.tsx +68 -68
- package/src/fields/types/timestamp/views/index.tsx +2 -1
- package/src/fields/types/virtual/views/index.tsx +17 -2
- package/src/internal-unstable/admin-ui/pages/HomePage/index.tsx +40 -31
- package/src/internal-unstable/admin-ui/pages/ItemPage/index.tsx +36 -3
- package/src/internal-unstable/admin-ui/pages/ListPage/PaginationControls.tsx +20 -33
- package/src/internal-unstable/admin-ui/pages/ListPage/index.tsx +24 -16
- package/tests/conditional-filters.test.ts +333 -326
- package/dist/GraphQLErrorNotice-cd74180d.cjs.js +0 -57
- package/dist/GraphQLErrorNotice-d9f0931b.esm.js +0 -55
- package/dist/pick-5fe45878.cjs.js +0 -71
- package/dist/pick-b7ef3115.esm.js +0 -68
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
useInvalidFields,
|
|
39
39
|
} from '../../../../admin-ui/utils'
|
|
40
40
|
import { pick } from '../../../../admin-ui/utils/pick'
|
|
41
|
+
import { usePreventNavigation } from '../../../../admin-ui/utils/usePreventNavigation'
|
|
41
42
|
import type {
|
|
42
43
|
ActionMeta,
|
|
43
44
|
BaseCollectionTypeInfo,
|
|
@@ -62,6 +63,22 @@ function useEventCallback<Func extends (...args: any[]) => unknown>(callback: Fu
|
|
|
62
63
|
return cb as any
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
// after forcing validation, move focus to the first invalid field so the user
|
|
67
|
+
// can see and fix it. runs on the next frame so the DOM reflects the new
|
|
68
|
+
// aria-invalid state, and is fully defensive so it can never throw.
|
|
69
|
+
function focusFirstInvalidField() {
|
|
70
|
+
requestAnimationFrame(() => {
|
|
71
|
+
try {
|
|
72
|
+
const el = document.querySelector<HTMLElement>('[aria-invalid="true"]')
|
|
73
|
+
if (!el) return
|
|
74
|
+
el.focus({ preventScroll: false })
|
|
75
|
+
el.scrollIntoView({ block: 'center', behavior: 'smooth' })
|
|
76
|
+
} catch {
|
|
77
|
+
// ignore — focusing is a best-effort enhancement
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
65
82
|
function DeleteButton({
|
|
66
83
|
list,
|
|
67
84
|
itemId,
|
|
@@ -155,7 +172,6 @@ function ResetButton(props: { onReset: () => void; hasChanges?: boolean }) {
|
|
|
155
172
|
title="Reset changes"
|
|
156
173
|
cancelLabel="Cancel"
|
|
157
174
|
primaryActionLabel="Yes, reset"
|
|
158
|
-
autoFocusButton="primary"
|
|
159
175
|
onPrimaryAction={props.onReset}
|
|
160
176
|
>
|
|
161
177
|
Are you sure? Any unsaved changes will be lost and cannot be recovered.
|
|
@@ -211,7 +227,11 @@ function ItemForm({
|
|
|
211
227
|
e.preventDefault()
|
|
212
228
|
const newForceValidation = invalidFields.size !== 0
|
|
213
229
|
setForceValidation(newForceValidation)
|
|
214
|
-
if (newForceValidation)
|
|
230
|
+
if (newForceValidation) {
|
|
231
|
+
toastQueue.critical('Please fix the highlighted field(s) before saving.')
|
|
232
|
+
focusFirstInvalidField()
|
|
233
|
+
return
|
|
234
|
+
}
|
|
215
235
|
|
|
216
236
|
const { error: _error } = await update({
|
|
217
237
|
variables: {
|
|
@@ -236,10 +256,18 @@ function ItemForm({
|
|
|
236
256
|
timeout: 5000,
|
|
237
257
|
})
|
|
238
258
|
|
|
259
|
+
// reset the navigation guard before refetch so saving and then navigating
|
|
260
|
+
// away doesn't prompt for unsaved changes
|
|
261
|
+
shouldPreventNavigationRef.current = false
|
|
239
262
|
onSaveSuccess()
|
|
240
263
|
})
|
|
241
264
|
|
|
242
265
|
const hasChangedFields = useHasChanges('update', list.fields, value, initialValue)
|
|
266
|
+
const shouldPreventNavigationRef = useRef(hasChangedFields)
|
|
267
|
+
useEffect(() => {
|
|
268
|
+
shouldPreventNavigationRef.current = hasChangedFields
|
|
269
|
+
}, [hasChangedFields])
|
|
270
|
+
usePreventNavigation(shouldPreventNavigationRef)
|
|
243
271
|
|
|
244
272
|
return (
|
|
245
273
|
<Fragment>
|
|
@@ -324,7 +352,12 @@ function ItemPage({ listKey }: ItemPageProps) {
|
|
|
324
352
|
const itemLabel_ = item?.[list.labelField] ?? item?.id
|
|
325
353
|
const itemLabel = typeof itemLabel_ === 'string' ? itemLabel_ : (itemId ?? '')
|
|
326
354
|
|
|
327
|
-
|
|
355
|
+
// Only show the full-page spinner on the INITIAL load (no data yet). On a
|
|
356
|
+
// post-save refetch Apollo keeps `data` populated while `loading` flips back
|
|
357
|
+
// to true; gating on `!data` keeps the form mounted (no scroll reset / flash)
|
|
358
|
+
// during background refetches while still showing the spinner before the
|
|
359
|
+
// first result arrives.
|
|
360
|
+
const pageLoading = (loading && !data) || itemId === undefined
|
|
328
361
|
const pageLabel = itemLabel || itemId
|
|
329
362
|
const pageTitle = list.isSingleton || typeof pageLabel !== 'string' ? list.label : pageLabel
|
|
330
363
|
const initialValue = useMemo(() => {
|
|
@@ -4,17 +4,11 @@ import { chevronLeftIcon } from '@keystar/ui/icon/icons/chevronLeftIcon'
|
|
|
4
4
|
import { chevronRightIcon } from '@keystar/ui/icon/icons/chevronRightIcon'
|
|
5
5
|
import { undo2Icon } from '@keystar/ui/icon/icons/undo2Icon'
|
|
6
6
|
import { HStack } from '@keystar/ui/layout'
|
|
7
|
-
import {
|
|
8
|
-
import { Item } from '@keystar/ui/
|
|
7
|
+
import { NumberField } from '@keystar/ui/number-field'
|
|
8
|
+
import { Item, Picker } from '@keystar/ui/picker'
|
|
9
9
|
import { Tooltip, TooltipTrigger } from '@keystar/ui/tooltip'
|
|
10
10
|
import { Text } from '@keystar/ui/typography'
|
|
11
11
|
import type { ReactNode } from 'react'
|
|
12
|
-
import { useMemo } from 'react'
|
|
13
|
-
|
|
14
|
-
type PageItem = {
|
|
15
|
-
label: string
|
|
16
|
-
id: number
|
|
17
|
-
}
|
|
18
12
|
|
|
19
13
|
export function PaginationControls(props: {
|
|
20
14
|
singular: string
|
|
@@ -34,16 +28,11 @@ export function PaginationControls(props: {
|
|
|
34
28
|
const prevPage = currentPage - 1
|
|
35
29
|
const lastPage = Math.max(Math.ceil(total / pageSize), 1)
|
|
36
30
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
label: String(page),
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
return result
|
|
46
|
-
}, [lastPage])
|
|
31
|
+
const goToPage = (value: number) => {
|
|
32
|
+
if (!Number.isFinite(value)) return
|
|
33
|
+
const page = Math.min(Math.max(Math.round(value), 1), lastPage)
|
|
34
|
+
if (page !== currentPage) props.onChangePage(page)
|
|
35
|
+
}
|
|
47
36
|
|
|
48
37
|
return (
|
|
49
38
|
<HStack
|
|
@@ -90,24 +79,22 @@ export function PaginationControls(props: {
|
|
|
90
79
|
|
|
91
80
|
{/*
|
|
92
81
|
right-side
|
|
93
|
-
mobile: next/prev
|
|
94
|
-
desktop^:
|
|
82
|
+
mobile: page jump, next/prev
|
|
83
|
+
desktop^: page jump, next/prev
|
|
95
84
|
*/}
|
|
96
85
|
<HStack gap="large" alignItems="center">
|
|
97
|
-
<HStack
|
|
98
|
-
<
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
86
|
+
<HStack gap="regular" alignItems="center">
|
|
87
|
+
<NumberField
|
|
88
|
+
aria-label="Go to page"
|
|
89
|
+
hideStepper
|
|
90
|
+
minValue={1}
|
|
91
|
+
maxValue={lastPage}
|
|
92
|
+
step={1}
|
|
93
|
+
value={currentPage}
|
|
94
|
+
onChange={goToPage}
|
|
106
95
|
width="scale.1000"
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
</Picker>
|
|
110
|
-
<Text>of {lastPage} pages</Text>
|
|
96
|
+
/>
|
|
97
|
+
<Text>of {lastPage}</Text>
|
|
111
98
|
</HStack>
|
|
112
99
|
<HStack gap="regular">
|
|
113
100
|
<ActionButton
|
|
@@ -897,21 +897,29 @@ function ActionItemsDialog({
|
|
|
897
897
|
id
|
|
898
898
|
}
|
|
899
899
|
}`
|
|
900
|
+
// The ids actually included in the mutation payload, in the exact order
|
|
901
|
+
// they are sent to the server. Server error paths reference indices into
|
|
902
|
+
// this array, so error/affected-record attribution must be done against it
|
|
903
|
+
// rather than the original (possibly larger) itemIds list.
|
|
904
|
+
const sentIds: string[] = []
|
|
905
|
+
const mutationData =
|
|
906
|
+
action.key === 'delete'
|
|
907
|
+
? itemIds.map(id => {
|
|
908
|
+
sentIds.push(id)
|
|
909
|
+
return { id }
|
|
910
|
+
})
|
|
911
|
+
: itemIds.flatMap(id => {
|
|
912
|
+
const row = items.find(item => String(item.id) === id)
|
|
913
|
+
if (!row) {
|
|
914
|
+
return []
|
|
915
|
+
}
|
|
916
|
+
const deserialized = deserializeItemToValue(list.fields, row)
|
|
917
|
+
const args = getActionArguments(list, action, deserialized)
|
|
918
|
+
sentIds.push(id)
|
|
919
|
+
return { where: { id }, ...args }
|
|
920
|
+
})
|
|
900
921
|
const [actionOnItems] = useMutation<{ results?: ({ id: string } | null)[] }>(actionMutation, {
|
|
901
|
-
variables:
|
|
902
|
-
action.key === 'delete'
|
|
903
|
-
? { where: itemIds.map(id => ({ id })) }
|
|
904
|
-
: {
|
|
905
|
-
data: itemIds.flatMap(id => {
|
|
906
|
-
const row = items.find(item => String(item.id) === id)
|
|
907
|
-
if (!row) {
|
|
908
|
-
return []
|
|
909
|
-
}
|
|
910
|
-
const deserialized = deserializeItemToValue(list.fields, row)
|
|
911
|
-
const args = getActionArguments(list, action, deserialized)
|
|
912
|
-
return { where: { id }, ...args }
|
|
913
|
-
}),
|
|
914
|
-
},
|
|
922
|
+
variables: action.key === 'delete' ? { where: mutationData } : { data: mutationData },
|
|
915
923
|
errorPolicy: 'all',
|
|
916
924
|
})
|
|
917
925
|
const { messages: m } = action
|
|
@@ -927,14 +935,14 @@ function ActionItemsDialog({
|
|
|
927
935
|
for (const err of error.errors ?? []) {
|
|
928
936
|
const i = err.path?.[1]
|
|
929
937
|
if (typeof i !== 'number') continue
|
|
930
|
-
const itemId =
|
|
938
|
+
const itemId = sentIds[i]
|
|
931
939
|
|
|
932
940
|
failed.add(itemId)
|
|
933
941
|
actionErrors[itemId] ??= []
|
|
934
942
|
actionErrors[itemId].push(err)
|
|
935
943
|
}
|
|
936
944
|
}
|
|
937
|
-
const countSuccess =
|
|
945
|
+
const countSuccess = sentIds.length - countFail
|
|
938
946
|
|
|
939
947
|
if (countSuccess) {
|
|
940
948
|
toastQueue.neutral(
|