@aglyn/plugins-marketing 1.0.0-beta.198 → 1.0.0-beta.200
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/package.json +15 -15
- package/src/lib/components/campaign-detail-card.js +106 -36
- package/src/lib/components/campaign-detail-card.js.map +1 -1
- package/src/lib/components/campaign-queries.d.ts +11 -0
- package/src/lib/components/campaign-queries.js +13 -0
- package/src/lib/components/campaign-queries.js.map +1 -1
- package/src/lib/components/campaigns-card.d.ts +8 -6
- package/src/lib/components/campaigns-card.js +283 -125
- package/src/lib/components/campaigns-card.js.map +1 -1
- package/src/lib/components/emails-list-card.d.ts +11 -15
- package/src/lib/components/emails-list-card.js +139 -142
- package/src/lib/components/emails-list-card.js.map +1 -1
- package/src/lib/components/host-experiments-card.component.js +107 -78
- package/src/lib/components/host-experiments-card.component.js.map +1 -1
- package/src/lib/components/org-experiments-card.js +7 -3
- package/src/lib/components/org-experiments-card.js.map +1 -1
- package/src/lib/model/campaign-list-query.d.ts +99 -0
- package/src/lib/model/campaign-list-query.js +373 -0
- package/src/lib/model/campaign-list-query.js.map +1 -0
- package/src/lib/model/experiment-list-query.d.ts +22 -0
- package/src/lib/model/experiment-list-query.js +85 -0
- package/src/lib/model/experiment-list-query.js.map +1 -0
- package/src/lib/server/campaign-manage.d.ts +1 -1
- package/src/lib/server/campaign-manage.js +30 -18
- package/src/lib/server/campaign-manage.js.map +1 -1
- package/src/lib/server/campaign-send.d.ts +7 -0
- package/src/lib/server/campaign-send.js +17 -5
- package/src/lib/server/campaign-send.js.map +1 -1
- package/src/lib/server/email-events.js +3 -1
- package/src/lib/server/email-events.js.map +1 -1
- package/src/lib/components/email-send-filter.d.ts +0 -32
- package/src/lib/components/email-send-filter.js +0 -55
- package/src/lib/components/email-send-filter.js.map +0 -1
|
@@ -20,34 +20,32 @@ import { pluginDocsHelp } from "@aglyn/aglyn";
|
|
|
20
20
|
import { mdiBullhornOutline, mdiContentCopy, mdiDeleteOutline, mdiEyeOutline, mdiPaletteOutline } from "@aglyn/shared-data-mdi";
|
|
21
21
|
import { AppLink, CardDisplay, MdiIcon, useConfirmationContext } from "@aglyn/shared-ui-jsx";
|
|
22
22
|
import ListFilterChips from "@aglyn/shared-ui-jsx/components/list-filter-chips.component";
|
|
23
|
+
import { ListPagination } from "@aglyn/shared-ui-jsx/components/list-pagination.component";
|
|
24
|
+
import ListQueryNotices, { listQueryRefusals } from "@aglyn/shared-ui-jsx/components/list-query-notices.component";
|
|
23
25
|
import { ListRowActions, ListTable, listActionsColumn } from "@aglyn/shared-ui-jsx/components/list-table.component";
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
+
import { hiddenFilterVisibility } from "@aglyn/shared-ui-jsx/const/list-filter";
|
|
27
|
+
import { listFilterGridColumns } from "@aglyn/shared-ui-jsx/const/list-grid-filter";
|
|
28
|
+
import { useListGridFilter } from "@aglyn/shared-ui-jsx/hooks/use-list-grid-filter";
|
|
26
29
|
import { TABLE_ROW_HEIGHT } from "@aglyn/shared-ui-jsx/const/table-pagination";
|
|
27
30
|
import { CreateArtifactDrawer } from "@aglyn/shared-ui-jsx-forms";
|
|
28
31
|
import { useSnackbar } from "@aglyn/shared-ui-snackstack";
|
|
29
|
-
import {
|
|
32
|
+
import { collectionCeiling } from "@aglyn/tenant-feature-instance/hooks/host-collection-queries";
|
|
33
|
+
import { useListQuery } from "@aglyn/tenant-feature-instance/hooks/use-list-query";
|
|
30
34
|
import { DUPLICATE_MENU_LABEL, useDuplicateResource, useFirestore, useFirestoreCollection } from "@aglyn/tenant-feature-instance";
|
|
31
|
-
import {
|
|
35
|
+
import { Button, Chip, Stack, Typography } from "@mui/material";
|
|
32
36
|
import { useRouter } from "next/navigation";
|
|
33
37
|
import { useCallback, useMemo, useState } from "react";
|
|
34
38
|
import { campaignPlacedOnHost, campaignSendDisplay, CAMPAIGN_SEND_CONTAINER_FIELD } from "@aglyn/shared-ui-email-campaigns/model/campaign-container";
|
|
35
39
|
import { emailListTimeMs, emailSendTimeMs } from "@aglyn/shared-ui-email-campaigns/model/email-record";
|
|
36
40
|
import { useCampaignManageApi, useCampaignSendApi } from "./use-campaign-send-api.js";
|
|
37
|
-
import {
|
|
41
|
+
import { CAMPAIGN_SEND_STATUS_OPTIONS, SINGLE_SEND_FILTER_VALUE, campaignEmailsListQuery, campaignSendsScope, emailCampaignQueryClauses } from "../model/campaign-list-query.js";
|
|
38
42
|
import { useMarketingHubPath } from "./use-marketing-hub-path.js";
|
|
39
|
-
import { campaignContainersQuery,
|
|
43
|
+
import { campaignContainersQuery, campaignSendsCollection } from "./campaign-queries.js";
|
|
40
44
|
import { orgSiteHubPath, orgSiteName, orgSiteOptions, useMarketingOrgId, useMarketingOrgMount } from "./marketing-org-mount.js";
|
|
41
|
-
/** How many messages one read of this list covers. */ const EMAIL_CEILING = 30;
|
|
42
45
|
/**
|
|
43
46
|
* How many campaigns the Campaign filter and the create drawer offer — the
|
|
44
|
-
* same read serves both.
|
|
47
|
+
* same read serves both. A picker's options, not a list.
|
|
45
48
|
*/ const CONTAINER_CEILING = 50;
|
|
46
|
-
/**
|
|
47
|
-
* The Campaign filter's value for an email filed under no campaign. An empty
|
|
48
|
-
* value reads as "no value" to the filter, so a clause on it would never
|
|
49
|
-
* apply; a sentinel is a value like any campaign id.
|
|
50
|
-
*/ const SINGLE_SEND_FILTER_VALUE = '__single__';
|
|
51
49
|
/**
|
|
52
50
|
* Why discard is refused, keyed by the state that refuses it.
|
|
53
51
|
*
|
|
@@ -78,28 +76,17 @@ import { orgSiteHubPath, orgSiteName, orgSiteOptions, useMarketingOrgId, useMark
|
|
|
78
76
|
stopped: 'warning'
|
|
79
77
|
};
|
|
80
78
|
/*
|
|
81
|
-
* What the messages grid's Filters panel offers
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*/ const
|
|
86
|
-
EMAIL_SUBJECT_FILTER_FIELD,
|
|
87
|
-
EMAIL_STATE_FILTER_FIELD,
|
|
88
|
-
// Matched on a derived key, so the row's own container field stays what
|
|
89
|
-
// was stored for the row menu that reads it.
|
|
90
|
-
inMemoryListField('emailCampaignId', 'select', 'campaignFilterKey'),
|
|
91
|
-
inMemoryListField('site', 'text', 'siteName')
|
|
92
|
-
];
|
|
93
|
-
const EMAIL_FILTER_HEADERS = {
|
|
79
|
+
* What the messages grid's Filters panel offers, each clause and the search
|
|
80
|
+
* on the list's Firestore query (AGL-3321, `campaignEmailsListQuery`). The
|
|
81
|
+
* State column is what the email is DOING (`campaignSendDisplay`), which no
|
|
82
|
+
* query can ask, so the panel offers the Status it STORES instead.
|
|
83
|
+
*/ const EMAIL_FILTER_HEADERS = {
|
|
94
84
|
subject: 'Subject',
|
|
95
|
-
|
|
85
|
+
status: 'Status',
|
|
96
86
|
emailCampaignId: 'Campaign',
|
|
97
|
-
site: 'Site'
|
|
87
|
+
site: 'Site',
|
|
88
|
+
createdAtMs: 'Created'
|
|
98
89
|
};
|
|
99
|
-
/** What the quick search reads on a message row. */ const EMAIL_SEARCH_FIELDS = [
|
|
100
|
-
'subjectText',
|
|
101
|
-
'siteName'
|
|
102
|
-
];
|
|
103
90
|
const emailsDocsHelp = pluginDocsHelp('emailCampaigns', {
|
|
104
91
|
anchor: '#opens--clicks',
|
|
105
92
|
excerpt: 'Every message this site has sent or has scheduled, each with its own ' + 'report: what was delivered, who opened it, and which links they followed.'
|
|
@@ -112,23 +99,19 @@ const emailsDocsHelp = pluginDocsHelp('emailCampaigns', {
|
|
|
112
99
|
* 14th, and to whom" — and they were previously the same list because a
|
|
113
100
|
* campaign document WAS a single send.
|
|
114
101
|
*
|
|
115
|
-
* ##
|
|
116
|
-
*
|
|
117
|
-
* No SEND date is on every message: a sent one carries `sentAt` and a
|
|
118
|
-
* scheduled one carries `sendAtMs`, written by two different branches of the
|
|
119
|
-
* send path, and a draft carries neither — so `orderBy` on either would not
|
|
120
|
-
* mis-sort this list, it would DROP half of it. `collectionCeiling` reads a
|
|
121
|
-
* bounded window in document-id order and probes one past the ceiling, so the
|
|
122
|
-
* rows are sorted here and the reader is told when there are more.
|
|
102
|
+
* ## Asked of Firestore, a page at a time
|
|
123
103
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
104
|
+
* No SEND date is on every message — a sent one carries `sentAt`, a
|
|
105
|
+
* scheduled one `sendAtMs`, a draft neither — so the list is ordered on
|
|
106
|
+
* `createdAtMs`, the one date every writer stamps when it mints a record
|
|
107
|
+
* (and `backfill-campaign-list-fields.mjs` stamped on the ones before).
|
|
108
|
+
* Newest first, paged by the query itself.
|
|
128
109
|
*
|
|
129
|
-
* The
|
|
130
|
-
*
|
|
131
|
-
*
|
|
110
|
+
* The Filters panel and the search box are the grid's; every clause and the
|
|
111
|
+
* search word go onto that ONE query (AGL-3321, `campaignEmailsListQuery`),
|
|
112
|
+
* so each page is a page of matches — an email that matches on page four is
|
|
113
|
+
* found — and a combination one query cannot hold is refused by name above
|
|
114
|
+
* the table, never answered over the rows that happen to be loaded.
|
|
132
115
|
*
|
|
133
116
|
* ## Under a site, and over the organization
|
|
134
117
|
*
|
|
@@ -147,32 +130,34 @@ const emailsDocsHelp = pluginDocsHelp('emailCampaigns', {
|
|
|
147
130
|
const siteMarketingHub = useMarketingHubPath();
|
|
148
131
|
const marketingHub = orgMount ? orgMount.basePath : siteMarketingHub;
|
|
149
132
|
const router = useRouter();
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
133
|
+
/*
|
|
134
|
+
* The Filters panel and the search, bound to the grid. Held here rather
|
|
135
|
+
* than in a saved view: this list keeps no views.
|
|
136
|
+
*/ const declaration = campaignEmailsListQuery(!hostId);
|
|
137
|
+
const gridFilter = useListGridFilter({
|
|
138
|
+
selectFields: [
|
|
139
|
+
'status',
|
|
140
|
+
'emailCampaignId',
|
|
141
|
+
'site'
|
|
142
|
+
]
|
|
143
|
+
});
|
|
144
|
+
const emailPage = useListQuery({
|
|
145
|
+
collection: campaignSendsCollection(firestore, orgId),
|
|
146
|
+
declaration,
|
|
147
|
+
request: {
|
|
148
|
+
clauses: emailCampaignQueryClauses(gridFilter.clauses),
|
|
149
|
+
search: gridFilter.searchWords,
|
|
150
|
+
base: campaignSendsScope(hostId)
|
|
151
|
+
},
|
|
152
|
+
deps: [
|
|
153
|
+
firestore,
|
|
154
|
+
orgId,
|
|
155
|
+
hostId
|
|
156
|
+
],
|
|
158
157
|
idField: '$id'
|
|
159
158
|
});
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
* Newest first on the time each message SITS at — its send time where it
|
|
163
|
-
* has one, its creation where it does not.
|
|
164
|
-
*
|
|
165
|
-
* A draft has neither `sentAt` nor `sendAtMs`, so sorting on the send time
|
|
166
|
-
* alone gave every draft the key 0 and filed the email a merchant is in the
|
|
167
|
-
* middle of writing at the very bottom of the list, behind whatever paging
|
|
168
|
-
* it has. `emailListTimeMs` is the same ordering with that one gap closed;
|
|
169
|
-
* a SENT message still orders by when it went out, never by when it was
|
|
170
|
-
* drafted.
|
|
171
|
-
*/ const emails = useMemo(()=>[
|
|
172
|
-
...readEmails
|
|
173
|
-
].sort((a, b)=>emailListTimeMs(b) - emailListTimeMs(a)), [
|
|
174
|
-
readEmails
|
|
175
|
-
]);
|
|
159
|
+
const emails = emailPage.rows;
|
|
160
|
+
const filtering = gridFilter.clauses.length > 0 || gridFilter.searchWords.some((word)=>word.trim());
|
|
176
161
|
/*
|
|
177
162
|
* A message's own pages, beneath the Emails page this list is on — the
|
|
178
163
|
* site's or the organization's. A template is a site's design, so over the
|
|
@@ -183,11 +168,11 @@ const emailsDocsHelp = pluginDocsHelp('emailCampaigns', {
|
|
|
183
168
|
/** The site a row is sent as, which every action on it must name. */ const rowHostId = useCallback((email)=>hostId != null ? hostId : (email == null ? void 0 : email.hostId) ? String(email.hostId) : null, [
|
|
184
169
|
hostId
|
|
185
170
|
]);
|
|
186
|
-
const hostOfEmail = useMemo(()=>new Map(
|
|
171
|
+
const hostOfEmail = useMemo(()=>new Map(emails.map((email)=>[
|
|
187
172
|
String(email.$id),
|
|
188
173
|
(email == null ? void 0 : email.hostId) ? String(email.hostId) : null
|
|
189
174
|
])), [
|
|
190
|
-
|
|
175
|
+
emails
|
|
191
176
|
]);
|
|
192
177
|
const { confirm } = useConfirmationContext();
|
|
193
178
|
const { enqueueSnackbar } = useSnackbar();
|
|
@@ -406,18 +391,8 @@ const emailsDocsHelp = pluginDocsHelp('emailCampaigns', {
|
|
|
406
391
|
})).sort((a, b)=>a.label.localeCompare(b.label)), [
|
|
407
392
|
campaignDocs
|
|
408
393
|
]);
|
|
409
|
-
const
|
|
410
|
-
|
|
411
|
-
siteName: orgMount && (email == null ? void 0 : email.hostId) ? orgSiteName(orgMount, email.hostId) : ''
|
|
412
|
-
})), [
|
|
413
|
-
emails,
|
|
414
|
-
orgMount
|
|
415
|
-
]);
|
|
416
|
-
const filterFields = useMemo(()=>orgMount ? EMAIL_FILTER_FIELDS : EMAIL_FILTER_FIELDS.filter((field)=>field.column !== 'site'), [
|
|
417
|
-
orgMount
|
|
418
|
-
]);
|
|
419
|
-
const filterOptions = useMemo(()=>({
|
|
420
|
-
state: EMAIL_STATE_OPTIONS,
|
|
394
|
+
const filterOptions = useMemo(()=>_extends({
|
|
395
|
+
status: CAMPAIGN_SEND_STATUS_OPTIONS,
|
|
421
396
|
emailCampaignId: [
|
|
422
397
|
{
|
|
423
398
|
value: SINGLE_SEND_FILTER_VALUE,
|
|
@@ -425,16 +400,13 @@ const emailsDocsHelp = pluginDocsHelp('emailCampaigns', {
|
|
|
425
400
|
},
|
|
426
401
|
...campaignOptions
|
|
427
402
|
]
|
|
403
|
+
}, hostId ? {} : {
|
|
404
|
+
site: orgSites
|
|
428
405
|
}), [
|
|
429
|
-
campaignOptions
|
|
406
|
+
campaignOptions,
|
|
407
|
+
hostId,
|
|
408
|
+
orgSites
|
|
430
409
|
]);
|
|
431
|
-
const listFilter = useListRowsFilter({
|
|
432
|
-
rows: filterRows,
|
|
433
|
-
fields: filterFields,
|
|
434
|
-
options: filterOptions,
|
|
435
|
-
headers: EMAIL_FILTER_HEADERS,
|
|
436
|
-
search: EMAIL_SEARCH_FIELDS
|
|
437
|
-
});
|
|
438
410
|
/*==========================================
|
|
439
411
|
* CREATE, THEN GO TO THE EMAIL'S OWN PAGE.
|
|
440
412
|
*
|
|
@@ -520,9 +492,9 @@ const emailsDocsHelp = pluginDocsHelp('emailCampaigns', {
|
|
|
520
492
|
router
|
|
521
493
|
]);
|
|
522
494
|
/*
|
|
523
|
-
* One row per message, in the order
|
|
524
|
-
*
|
|
525
|
-
*
|
|
495
|
+
* One row per message, in the query's order. The subject is a link AND the
|
|
496
|
+
* row opens the report: a click handler cannot be middle-clicked or opened
|
|
497
|
+
* in a new tab.
|
|
526
498
|
*/ const columns = [
|
|
527
499
|
{
|
|
528
500
|
field: 'subject',
|
|
@@ -573,8 +545,6 @@ const emailsDocsHelp = pluginDocsHelp('emailCampaigns', {
|
|
|
573
545
|
field: 'when',
|
|
574
546
|
headerName: 'When',
|
|
575
547
|
width: 190,
|
|
576
|
-
// Sorted on the time the list is ordered by, so a draft sorts by its
|
|
577
|
-
// creation rather than as the oldest thing on the page.
|
|
578
548
|
valueGetter: (_value, row)=>emailListTimeMs(row),
|
|
579
549
|
renderCell: ({ row })=>{
|
|
580
550
|
const at = emailSendTimeMs(row);
|
|
@@ -615,6 +585,8 @@ const emailsDocsHelp = pluginDocsHelp('emailCampaigns', {
|
|
|
615
585
|
width: 72
|
|
616
586
|
})
|
|
617
587
|
];
|
|
588
|
+
const gridColumns = listFilterGridColumns(columns, declaration.fields, filterOptions, EMAIL_FILTER_HEADERS);
|
|
589
|
+
/** Nothing stored at all — not a filter that matched nothing. */ const none = emailPage.status !== 'loading' && emails.length === 0 && !filtering && emailPage.page === 0;
|
|
618
590
|
return /*#__PURE__*/ _jsxs(CardDisplay, {
|
|
619
591
|
header: 'Messages',
|
|
620
592
|
help: emailsDocsHelp,
|
|
@@ -630,52 +602,77 @@ const emailsDocsHelp = pluginDocsHelp('emailCampaigns', {
|
|
|
630
602
|
contentGutterY: true,
|
|
631
603
|
children: [
|
|
632
604
|
duplicate.dialog,
|
|
633
|
-
/*#__PURE__*/
|
|
605
|
+
/*#__PURE__*/ _jsx(Stack, {
|
|
634
606
|
spacing: 2,
|
|
635
|
-
children:
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
607
|
+
children: none ? /*#__PURE__*/ _jsxs(Stack, {
|
|
608
|
+
spacing: 2,
|
|
609
|
+
sx: {
|
|
610
|
+
alignItems: 'flex-start'
|
|
611
|
+
},
|
|
612
|
+
children: [
|
|
613
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
614
|
+
variant: "body2",
|
|
615
|
+
color: "text.secondary",
|
|
616
|
+
children: 'Nothing has been sent or scheduled yet. Write one here, or ' + 'from a campaign, and it appears in this list with its own ' + 'report.'
|
|
617
|
+
}),
|
|
618
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
619
|
+
variant: "contained",
|
|
620
|
+
onClick: ()=>setCreateOpen(true),
|
|
621
|
+
children: 'New email'
|
|
622
|
+
})
|
|
623
|
+
]
|
|
624
|
+
}) : /*#__PURE__*/ _jsxs(_Fragment, {
|
|
625
|
+
children: [
|
|
626
|
+
/*#__PURE__*/ _jsx(ListFilterChips, {
|
|
627
|
+
fields: declaration.fields,
|
|
628
|
+
headers: EMAIL_FILTER_HEADERS,
|
|
629
|
+
clauses: gridFilter.clauses,
|
|
630
|
+
onChange: gridFilter.setClauses,
|
|
631
|
+
options: filterOptions
|
|
632
|
+
}),
|
|
633
|
+
/*#__PURE__*/ _jsx(ListQueryNotices, {
|
|
634
|
+
refused: listQueryRefusals(emailPage.plan.refused, {
|
|
635
|
+
fields: declaration.fields,
|
|
636
|
+
headers: EMAIL_FILTER_HEADERS,
|
|
637
|
+
options: filterOptions
|
|
646
638
|
}),
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
639
|
+
notices: emailPage.plan.notices
|
|
640
|
+
}),
|
|
641
|
+
/*#__PURE__*/ _jsx(ListTable, {
|
|
642
|
+
"aria-label": "Messages",
|
|
643
|
+
rows: emails,
|
|
644
|
+
columns: gridColumns,
|
|
645
|
+
rowHeight: TABLE_ROW_HEIGHT,
|
|
646
|
+
onOpen: (_id, row)=>router.push(emailHref(row)),
|
|
647
|
+
loading: emailPage.status === 'loading',
|
|
648
|
+
/*
|
|
649
|
+
* The panel and the search are the grid's; every clause and
|
|
650
|
+
* the search word are on the list's query (AGL-3321), and the
|
|
651
|
+
* grid neither filters nor sorts the page it is handed: the
|
|
652
|
+
* query's one order, newest first, is the list's.
|
|
653
|
+
*/ filterMode: "server",
|
|
654
|
+
filterModel: gridFilter.filterModel,
|
|
655
|
+
onFilterModelChange: gridFilter.onFilterModelChange,
|
|
656
|
+
quickFilter: true,
|
|
657
|
+
disableColumnSorting: true,
|
|
658
|
+
hideFooter: true,
|
|
659
|
+
initialState: {
|
|
660
|
+
columns: {
|
|
661
|
+
columnVisibilityModel: hiddenFilterVisibility(declaration.fields, columns.map((column)=>column.field))
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
noRowsLabel: "No messages match these filters"
|
|
665
|
+
}),
|
|
666
|
+
/*#__PURE__*/ _jsx(ListPagination, {
|
|
667
|
+
page: emailPage.page,
|
|
668
|
+
pageSize: emailPage.pageSize,
|
|
669
|
+
rowCount: emails.length,
|
|
670
|
+
hasMore: emailPage.hasMore,
|
|
671
|
+
onPageChange: emailPage.setPage,
|
|
672
|
+
onPageSizeChange: emailPage.setPageSize
|
|
673
|
+
})
|
|
674
|
+
]
|
|
675
|
+
})
|
|
679
676
|
}),
|
|
680
677
|
/*#__PURE__*/ _jsx(CreateArtifactDrawer, {
|
|
681
678
|
open: createOpen,
|