@aglyn/plugins-email 1.0.0-beta.179 → 1.0.0-beta.180

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.
Files changed (59) hide show
  1. package/README.md +2 -1
  2. package/package.json +17 -17
  3. package/src/lib/components/email-org-mount.d.ts +116 -0
  4. package/src/lib/components/email-org-mount.js +211 -0
  5. package/src/lib/components/email-org-mount.js.map +1 -0
  6. package/src/lib/components/email-topic-detail.d.ts +2 -1
  7. package/src/lib/components/email-topic-detail.js +7 -1
  8. package/src/lib/components/email-topic-detail.js.map +1 -1
  9. package/src/lib/components/email-topics-card.d.ts +2 -1
  10. package/src/lib/components/email-topics-card.js +7 -1
  11. package/src/lib/components/email-topics-card.js.map +1 -1
  12. package/src/lib/components/email-zones.d.ts +28 -1
  13. package/src/lib/components/email-zones.js.map +1 -1
  14. package/src/lib/components/emails-console-page.d.ts +4 -0
  15. package/src/lib/components/emails-console-page.js +107 -5
  16. package/src/lib/components/emails-console-page.js.map +1 -1
  17. package/src/lib/components/list-detail-card.d.ts +19 -3
  18. package/src/lib/components/list-detail-card.js +52 -13
  19. package/src/lib/components/list-detail-card.js.map +1 -1
  20. package/src/lib/components/list-edit-card.d.ts +2 -1
  21. package/src/lib/components/list-edit-card.js +56 -17
  22. package/src/lib/components/list-edit-card.js.map +1 -1
  23. package/src/lib/components/lists-card.d.ts +2 -1
  24. package/src/lib/components/lists-card.js +5 -5
  25. package/src/lib/components/lists-card.js.map +1 -1
  26. package/src/lib/components/org-email-templates-card.d.ts +34 -0
  27. package/src/lib/components/org-email-templates-card.js +470 -0
  28. package/src/lib/components/org-email-templates-card.js.map +1 -0
  29. package/src/lib/components/org-sending-card.d.ts +30 -0
  30. package/src/lib/components/org-sending-card.js +680 -0
  31. package/src/lib/components/org-sending-card.js.map +1 -0
  32. package/src/lib/components/org-sending-domain-detail.d.ts +28 -0
  33. package/src/lib/components/org-sending-domain-detail.js +497 -0
  34. package/src/lib/components/org-sending-domain-detail.js.map +1 -0
  35. package/src/lib/components/org-site-suppressions.d.ts +20 -0
  36. package/src/lib/components/org-site-suppressions.js +99 -0
  37. package/src/lib/components/org-site-suppressions.js.map +1 -0
  38. package/src/lib/components/org-suppressions-card.d.ts +22 -0
  39. package/src/lib/components/org-suppressions-card.js +196 -0
  40. package/src/lib/components/org-suppressions-card.js.map +1 -0
  41. package/src/lib/components/sending-domain-detail.d.ts +12 -0
  42. package/src/lib/components/sending-domain-detail.js +4 -1
  43. package/src/lib/components/sending-domain-detail.js.map +1 -1
  44. package/src/lib/components/suppression-totals.d.ts +63 -0
  45. package/src/lib/components/suppression-totals.js +105 -0
  46. package/src/lib/components/suppression-totals.js.map +1 -0
  47. package/src/lib/components/suppressions-card.js +7 -80
  48. package/src/lib/components/suppressions-card.js.map +1 -1
  49. package/src/lib/components/use-org-email-topics.d.ts +9 -1
  50. package/src/lib/components/use-org-email-topics.js +4 -3
  51. package/src/lib/components/use-org-email-topics.js.map +1 -1
  52. package/src/lib/components/use-org-sending-views.d.ts +39 -0
  53. package/src/lib/components/use-org-sending-views.js +124 -0
  54. package/src/lib/components/use-org-sending-views.js.map +1 -0
  55. package/src/lib/model/sending-domain-status.d.ts +36 -0
  56. package/src/lib/model/sending-domain-status.js +46 -0
  57. package/src/lib/model/sending-domain-status.js.map +1 -1
  58. package/src/lib/plugin.js +29 -1
  59. package/src/lib/plugin.js.map +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/email/src/lib/components/org-sending-card.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { ICON_VARIANT_CLOSE } from '@aglyn/shared-data-enums'\nimport {\n mdiDeleteOutline,\n mdiDnsOutline,\n mdiEmailCheckOutline,\n mdiRefresh,\n} from '@aglyn/shared-data-mdi'\nimport {\n AppLink,\n CardDisplay,\n Container,\n MdiIcon,\n SrOnly,\n useConfirmationContext,\n} from '@aglyn/shared-ui-jsx'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { NavigationDrawerComponent } from '@aglyn/shared-ui-jsx/components/navigation-drawer.component'\nimport RowActionsMenu, {\n type RowActionsMenuItem,\n} from '@aglyn/shared-ui-jsx/components/row-actions-menu.component'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n useSendingApi,\n type SendingIdentityView,\n} from '@aglyn/tenant-feature-instance/hooks/use-sending-identity-api'\nimport {\n Alert,\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogContentText,\n DialogTitle,\n IconButton,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useRouter } from 'next/navigation'\nimport { useCallback, useRef, useState } from 'react'\nimport {\n describeOrgSendingDomainRemoval,\n describeSendingDomain,\n INCONCLUSIVE_CHECK,\n} from '../model/sending-domain-status'\nimport {\n OrgSiteSelect,\n orgSiteEmailsPath,\n orgSiteName,\n orgSitePageLabel,\n useEmailOrgMount,\n useOrgSitePage,\n type EmailOrgMount,\n} from './email-org-mount'\nimport SendingSenderDrawer from './sending-sender-drawer'\nimport { useOrgSendingViews } from './use-org-sending-views'\n\nexport interface OrgSendingCardProps {\n /** The organization's Emails page, which the domain pages hang beneath. */\n basePath: string\n}\n\n/** How a site's identity reads in one chip. */\nfunction identityChip(view: SendingIdentityView): {\n label: string\n color: 'default' | 'primary' | 'warning'\n} {\n if (view.refusal) return { label: 'Cannot send', color: 'warning' }\n if (view.identitySource === 'custom') {\n return { label: 'Own domain', color: 'primary' }\n }\n return { label: 'Shared address', color: 'default' }\n}\n\n/**\n * WHO EVERY SITE'S MAIL COMES FROM, AND THE DOMAINS THE ORGANIZATION PROVED.\n *\n * The two halves of a site's Sending section, over the organization. A domain\n * is proved once by the org — publishing its records is a statement about a\n * zone — and each site then chooses which proved domain it sends as, so the\n * page is two tables: the sites, each with what it sends as right now and its\n * default sender, and the domains, each with the sites sending as it.\n *\n * Every site row is read through the same route the site's own page reads,\n * so what it says is what a campaign sent as that site would get. The reads\n * are one per site over one page of sites, and the org's domains come back on\n * each of them, so there is no separate read for the domain table. What the\n * domain table says about which sites send as a domain is what the pages read\n * so far say, and the removal confirmation counts the sites not yet read.\n *\n * Managing — adding a domain, checking it, choosing what a site sends as, or\n * editing a sender — needs the organization admin role, exactly as on a\n * site's page, and the page says so to anybody else rather than offering\n * controls that would refuse.\n */\nexport function OrgSendingCard(props: OrgSendingCardProps) {\n const mount = useEmailOrgMount()\n return mount ? (\n <OrgSendingTables mount={mount} basePath={props.basePath} />\n ) : null\n}\nOrgSendingCard.displayName = 'OrgSendingCard'\n\nfunction OrgSendingTables(props: { mount: EmailOrgMount; basePath: string }) {\n const { mount, basePath } = props\n const call = useSendingApi()\n const router = useRouter()\n const { confirm } = useConfirmationContext()\n const { enqueueSnackbar } = useSnackbar()\n // Held in a ref for the reason the site card holds its own: the callbacks\n // below depend on it, and the hook hands back a fresh function per render.\n const notifyRef = useRef(enqueueSnackbar)\n notifyRef.current = enqueueSnackbar\n\n const sitePage = useOrgSitePage(mount)\n const { sites } = sitePage\n const { views, errors, loading, reload, first } = useOrgSendingViews(sites)\n const canManage = first?.canManage === true\n const entitled = first?.entitled === true\n const domains = first?.domains ?? []\n\n const [senderEditor, setSenderEditor] = useState<{\n hostId: string\n senderId: string | null\n } | null>(null)\n const [domainBusy, setDomainBusy] = useState('')\n /** The domain a site is being chosen for, with the site chosen so far. */\n const [assigning, setAssigning] = useState<{\n domain: string\n hostId: string\n } | null>(null)\n const [adding, setAdding] = useState(false)\n const [newDomain, setNewDomain] = useState('')\n const [addError, setAddError] = useState('')\n const [addingBusy, setAddingBusy] = useState(false)\n\n /** A domain's own page, the org route's twin of a site's. */\n const domainPath = useCallback(\n (domain: string) => `${basePath}/sending/${encodeURIComponent(domain)}`,\n [basePath],\n )\n /** The sites read so far whose mail leaves on `domain`. */\n const sitesSendingAs = (domain: string) =>\n mount.hosts.filter((site) => views[site.id]?.selected === domain)\n\n const handleVerifyDomain = useCallback(\n async (domain: string) => {\n if (domainBusy) return\n setDomainBusy(domain)\n const { response, payload } = await call({\n path: 'sending-domains',\n method: 'POST',\n body: { orgId: mount.orgId, domain, action: 'verify' },\n })\n setDomainBusy('')\n // No answer from DNS changes nothing about the record; see the site\n // card, which holds the same third outcome.\n if (response.status === 503) {\n return void notifyRef.current(INCONCLUSIVE_CHECK.text, {\n variant: 'info',\n })\n }\n if (!response.ok) {\n return void notifyRef.current(\n payload?.error ?? 'The check could not run',\n { variant: 'warning' },\n )\n }\n await reload()\n notifyRef.current(\n payload?.verified\n ? `Verified — ${domain} can send`\n : `Checked. Some of ${domain}’s records are still missing.`,\n { variant: payload?.verified ? 'success' : 'info' },\n )\n },\n [call, domainBusy, mount.orgId, reload],\n )\n\n const handleUseDomain = useCallback(\n async (hostId: string, domain: string) => {\n if (domainBusy) return\n setDomainBusy(domain)\n const { response, payload } = await call({\n path: 'sending-identity',\n method: 'POST',\n body: { hostId, domain },\n })\n setDomainBusy('')\n if (!response.ok) {\n return void notifyRef.current(\n payload?.error ?? 'Could not change the identity',\n { variant: 'warning' },\n )\n }\n setAssigning(null)\n await reload(hostId)\n // The address the ROUTE settled on, not the one this click asked for.\n const site = orgSiteName(mount, hostId)\n notifyRef.current(\n payload?.from\n ? `${site} now sends as ${payload.from}`\n : `${site}’s sending address was changed`,\n { variant: 'success' },\n )\n },\n [call, domainBusy, mount, reload],\n )\n\n const handleReleaseDomain = useCallback(\n async (domain: string) => {\n if (domainBusy) return\n const ok = await confirm({\n ...describeOrgSendingDomainRemoval({\n domain,\n sites: mount.hosts\n .filter((site) => views[site.id]?.selected === domain)\n .map((site) => ({\n name: orgSiteName(mount, site.id),\n issued: views[site.id]?.platformDomain === domain,\n })),\n unchecked: mount.hosts.filter((site) => !views[site.id]).length,\n }),\n confirmationButtonProps: { color: 'error' },\n })\n // `confirm` resolves with no value and REJECTS on cancel.\n .then(() => true)\n .catch(() => false)\n if (!ok) return\n setDomainBusy(domain)\n const { response, payload } = await call({\n path: 'sending-domains',\n method: 'DELETE',\n query: { orgId: mount.orgId, domain },\n })\n setDomainBusy('')\n if (!response.ok) {\n return void notifyRef.current(\n payload?.error ?? 'Could not remove the domain',\n { variant: 'warning' },\n )\n }\n await reload()\n },\n [call, confirm, domainBusy, mount, reload, views],\n )\n\n const handleAdd = useCallback(async () => {\n const domain = newDomain.trim()\n if (!domain || addingBusy) return\n setAddError('')\n setAddingBusy(true)\n const { response, payload } = await call({\n path: 'sending-domains',\n method: 'POST',\n body: { orgId: mount.orgId, domain, action: 'request' },\n })\n setAddingBusy(false)\n if (!response.ok) {\n setAddError(payload?.error ?? 'Could not add that domain')\n return\n }\n setAdding(false)\n setNewDomain('')\n // Straight to the records, which are what the person came for.\n router.push(domainPath(payload?.domain ?? domain))\n }, [addingBusy, call, domainPath, mount.orgId, newDomain, router])\n\n /**\n * What may be done to one domain from here, disabled with the reason rather\n * than hidden — the same four entries, gated the same way, as the site\n * card's row menu. The difference is the send-as entry: over the org it\n * asks which site.\n */\n const domainActions = (\n record: SendingIdentityView['domains'][number],\n ): RowActionsMenuItem[] => {\n const working = Boolean(domainBusy)\n const domainRouteReason = !canManage\n ? 'Managing sending domains needs the organization admin role.'\n : !entitled\n ? 'Managing sending domains needs a plan that carries sending as ' +\n 'your own domain.'\n : ''\n return [\n {\n key: 'open',\n label: 'Open domain',\n icon: <MdiIcon path={mdiDnsOutline.path} size={0.8} />,\n href: domainPath(record.domain),\n },\n {\n key: 'verify',\n label: 'Check DNS',\n icon: <MdiIcon path={mdiRefresh.path} size={0.8} />,\n disabled:\n working ||\n record.status === 'requested' ||\n Boolean(domainRouteReason),\n disabledReason:\n record.status === 'requested'\n ? 'No records have been issued for this domain yet, so there is ' +\n 'nothing to look for. Open it to see what it is waiting on.'\n : domainRouteReason || undefined,\n onClick: () => void handleVerifyDomain(record.domain),\n },\n {\n key: 'use',\n label: 'Send a site’s email as this domain…',\n icon: <MdiIcon path={mdiEmailCheckOutline.path} size={0.8} />,\n disabled: working || record.status !== 'verified' || !canManage,\n disabledReason:\n record.status !== 'verified'\n ? 'Only a verified domain can be sent as. Publish its records and ' +\n 'check DNS first.'\n : !canManage\n ? 'Choosing what a site sends as needs the organization admin ' +\n 'role.'\n : undefined,\n onClick: () => {\n if (mount.hosts.length === 1) {\n return void handleUseDomain(mount.hosts[0].id, record.domain)\n }\n setAssigning({\n domain: record.domain,\n hostId: mount.pickedHostId ?? '',\n })\n },\n },\n {\n key: 'release',\n label: 'Remove domain',\n icon: <MdiIcon path={mdiDeleteOutline.path} size={0.8} />,\n destructive: true,\n disabled: working || Boolean(domainRouteReason),\n disabledReason: domainRouteReason || undefined,\n onClick: () => void handleReleaseDomain(record.domain),\n },\n ]\n }\n\n const noSites = mount.hostsReady && mount.hosts.length === 0\n const editorView = senderEditor ? (views[senderEditor.hostId] ?? null) : null\n\n return (\n <CardDisplay\n header=\"Sending\"\n help={pluginDocsHelp('emailCampaigns', { anchor: '#sending-domains' })}\n contentGutterX\n contentGutterY\n contentBordered=\"all\"\n HeaderProps={{\n action: canManage ? (\n <Button\n size=\"small\"\n variant=\"contained\"\n disabled={!entitled}\n onClick={() => setAdding(true)}\n >\n {'Add domain'}\n </Button>\n ) : null,\n }}\n >\n <Stack spacing={1.5}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Receipts, password resets, booking confirmations and other ' +\n 'account email send from every site on every plan, including ' +\n 'Free. A domain is proved once for the whole organization; each ' +\n 'site then chooses which proved domain its mail leaves on, and ' +\n 'which senders it may use.'}\n </Typography>\n\n {first && !canManage ? (\n <Alert severity=\"info\">\n {'Adding a domain, choosing what a site sends as and editing its ' +\n 'senders need the organization admin role. You can see the ' +\n 'current state here.'}\n </Alert>\n ) : null}\n\n <Typography variant=\"body2\" sx={{ fontWeight: 'bold' }}>\n {'Sites'}\n </Typography>\n {noSites ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'This organization has no sites yet. What a site sends as is ' +\n 'chosen per site, so there is nothing to show until there is one.'}\n </Typography>\n ) : (\n <ScrollTable size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>{'Site'}</TableCell>\n <TableCell>{'Sends as'}</TableCell>\n <TableCell>{'Status'}</TableCell>\n <TableCell>{'Default sender'}</TableCell>\n <TableCell align=\"right\">\n <SrOnly>{'Actions'}</SrOnly>\n </TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {sites.map((site) => {\n const view = views[site.id]\n const error = errors[site.id]\n const sendingPage = orgSiteEmailsPath(mount, site.id, 'sending')\n const sender = view?.senders.find((entry) => entry.isDefault)\n const chip = view ? identityChip(view) : null\n return (\n <TableRow key={site.id}>\n <TableCell>\n {sendingPage ? (\n <AppLink href={sendingPage}>\n {orgSiteName(mount, site.id)}\n </AppLink>\n ) : (\n orgSiteName(mount, site.id)\n )}\n </TableCell>\n <TableCell\n sx={{ fontFamily: view ? 'monospace' : undefined }}\n >\n {view ? (\n (view.refusal?.message ?? view.identity)\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {error || 'Loading…'}\n </Typography>\n )}\n </TableCell>\n <TableCell>\n {chip ? (\n <Chip\n size=\"small\"\n label={chip.label}\n color={chip.color}\n />\n ) : null}\n </TableCell>\n <TableCell>\n {sender\n ? [\n sender.fromName,\n sender.from ?? `${sender.localPart}@`,\n ]\n .filter(Boolean)\n .join(' · ')\n : view\n ? '—'\n : null}\n </TableCell>\n <TableCell align=\"right\">\n {view && canManage ? (\n <Button\n size=\"small\"\n onClick={() =>\n setSenderEditor({\n hostId: site.id,\n senderId: sender?.id ?? null,\n })\n }\n >\n {'Edit sender'}\n </Button>\n ) : null}\n </TableCell>\n </TableRow>\n )\n })}\n </TableBody>\n </ScrollTable>\n )}\n {noSites ? null : (\n <ListPagination\n page={sitePage.page}\n pageSize={sitePage.pageSize}\n rowCount={sites.length}\n count={sitePage.count}\n onPageChange={sitePage.setPage}\n labelDisplayedRows={orgSitePageLabel}\n />\n )}\n\n <Typography variant=\"body2\" sx={{ fontWeight: 'bold' }}>\n {'Domains'}\n </Typography>\n {first && !entitled ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {(first.customDomainPlan\n ? `Sending as your own domain starts on the ${first.customDomainPlan} plan. `\n : '') +\n 'Until then each site sends on a shared sending address, whose ' +\n 'delivery reputation is pooled with the other sites on it.'}\n </Typography>\n ) : null}\n {!first ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {noSites\n ? 'Domains are listed once the organization has a site.'\n : loading\n ? 'Loading…'\n : 'The organization’s domains could not be read, because no ' +\n 'site’s sending identity could.'}\n </Typography>\n ) : domains.length ? (\n <ScrollTable size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>{'Domain'}</TableCell>\n <TableCell>{'State'}</TableCell>\n <TableCell>{'Sites sending as it'}</TableCell>\n <TableCell align=\"right\">\n <SrOnly>{'Actions'}</SrOnly>\n </TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {domains.map((record) => {\n const state = describeSendingDomain({\n status: record.status,\n pendingProvider: record.status === 'requested',\n issueError: record.lastIssueError ?? null,\n })\n const using = sitesSendingAs(record.domain)\n return (\n <TableRow\n key={record.domain}\n hover\n sx={{ cursor: 'pointer' }}\n onClick={() => router.push(domainPath(record.domain))}\n >\n <TableCell sx={{ fontFamily: 'monospace' }}>\n {record.domain}\n </TableCell>\n <TableCell>\n <Chip\n size=\"small\"\n label={state.label}\n color={state.color}\n variant={state.sending ? 'filled' : 'outlined'}\n />\n </TableCell>\n <TableCell>\n {using.length ? (\n using\n .map((site) => orgSiteName(mount, site.id))\n .join(', ')\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'—'}\n </Typography>\n )}\n </TableCell>\n <TableCell align=\"right\" padding=\"none\">\n <RowActionsMenu\n label={record.domain}\n items={domainActions(record)}\n />\n </TableCell>\n </TableRow>\n )\n })}\n </TableBody>\n </ScrollTable>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No domain has been added yet.'}\n </Typography>\n )}\n </Stack>\n\n {/* One site's sender, in the same drawer the site's own page opens. */}\n {senderEditor && editorView ? (\n <SendingSenderDrawer\n open\n hostId={senderEditor.hostId}\n view={editorView}\n senderId={senderEditor.senderId}\n onClose={() => setSenderEditor(null)}\n onSaved={() => void reload(senderEditor.hostId)}\n />\n ) : null}\n\n <Dialog\n open={Boolean(assigning)}\n onClose={domainBusy ? undefined : () => setAssigning(null)}\n fullWidth\n maxWidth=\"xs\"\n >\n <DialogTitle>{`Send as ${assigning?.domain ?? ''}`}</DialogTitle>\n <DialogContent>\n <DialogContentText sx={{ mb: 2 }}>\n {'The site whose email should leave on this domain. Its receipts, ' +\n 'account email and campaigns all move to it.'}\n </DialogContentText>\n {assigning ? (\n <OrgSiteSelect\n mount={mount}\n label=\"Site\"\n value={assigning.hostId}\n onChange={(hostId) =>\n setAssigning((current) =>\n current ? { ...current, hostId } : current,\n )\n }\n />\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button\n onClick={() => setAssigning(null)}\n disabled={Boolean(domainBusy)}\n >\n {'Cancel'}\n </Button>\n <Button\n variant=\"contained\"\n disabled={!assigning?.hostId || Boolean(domainBusy)}\n onClick={() =>\n assigning\n ? void handleUseDomain(assigning.hostId, assigning.domain)\n : undefined\n }\n >\n {domainBusy ? 'Changing…' : 'Send as this domain'}\n </Button>\n </DialogActions>\n </Dialog>\n\n {/* Adding is a drawer, as on a site's page; see the site card. */}\n <NavigationDrawerComponent\n open={adding}\n anchor=\"right\"\n variant=\"temporary\"\n onClose={() => setAdding(false)}\n AppBarProps={{ color: 'surface' }}\n appBarLeft={\n <>\n <IconButton\n color=\"inherit\"\n edge=\"start\"\n onClick={() => setAdding(false)}\n sx={{ mr: 2 }}\n >\n <MdiIcon path={ICON_VARIANT_CLOSE.path} />\n <SrOnly>close drawer</SrOnly>\n </IconButton>\n <Typography variant=\"h6\" component=\"div\">\n {'Add a sending domain'}\n </Typography>\n </>\n }\n >\n <Container gutterY>\n <Stack spacing={2}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'The domain your mail should come from — the part after the @. ' +\n 'Use a domain you control the DNS for; you will be given ' +\n 'records to publish on it. Once it verifies, any of this ' +\n 'organization’s sites can send as it.'}\n </Typography>\n <TextField\n label=\"Domain\"\n value={newDomain}\n onChange={(event) => setNewDomain(event.target.value)}\n size=\"small\"\n autoFocus\n placeholder=\"acme.com\"\n helperText=\"For example acme.com — not an address\"\n />\n {addError ? <Alert severity=\"error\">{addError}</Alert> : null}\n <Button\n variant=\"contained\"\n disabled={!newDomain.trim() || addingBusy}\n onClick={() => void handleAdd()}\n >\n {addingBusy ? 'Adding…' : 'Add domain'}\n </Button>\n </Stack>\n </Container>\n </NavigationDrawerComponent>\n </CardDisplay>\n )\n}\nOrgSendingTables.displayName = 'OrgSendingTables'\n\nexport default OrgSendingCard\n"],"names":["pluginDocsHelp","ICON_VARIANT_CLOSE","mdiDeleteOutline","mdiDnsOutline","mdiEmailCheckOutline","mdiRefresh","AppLink","CardDisplay","Container","MdiIcon","SrOnly","useConfirmationContext","ListPagination","NavigationDrawerComponent","RowActionsMenu","ScrollTable","useSnackbar","useSendingApi","Alert","Button","Chip","Dialog","DialogActions","DialogContent","DialogContentText","DialogTitle","IconButton","Stack","TableBody","TableCell","TableHead","TableRow","TextField","Typography","useRouter","useCallback","useRef","useState","describeOrgSendingDomainRemoval","describeSendingDomain","INCONCLUSIVE_CHECK","OrgSiteSelect","orgSiteEmailsPath","orgSiteName","orgSitePageLabel","useEmailOrgMount","useOrgSitePage","SendingSenderDrawer","useOrgSendingViews","identityChip","view","refusal","label","color","identitySource","OrgSendingCard","props","mount","OrgSendingTables","basePath","displayName","views","call","router","confirm","enqueueSnackbar","notifyRef","current","sitePage","sites","errors","loading","reload","first","canManage","entitled","domains","senderEditor","setSenderEditor","domainBusy","setDomainBusy","assigning","setAssigning","adding","setAdding","newDomain","setNewDomain","addError","setAddError","addingBusy","setAddingBusy","domainPath","domain","encodeURIComponent","sitesSendingAs","hosts","filter","site","id","selected","handleVerifyDomain","response","payload","path","method","body","orgId","action","status","text","variant","ok","error","verified","handleUseDomain","hostId","from","handleReleaseDomain","map","name","issued","platformDomain","unchecked","length","confirmationButtonProps","then","catch","query","handleAdd","trim","push","domainActions","record","working","Boolean","domainRouteReason","key","icon","size","href","disabled","disabledReason","undefined","onClick","pickedHostId","destructive","noSites","hostsReady","editorView","header","help","anchor","contentGutterX","contentGutterY","contentBordered","HeaderProps","spacing","severity","sx","fontWeight","align","sender","sendingPage","senders","find","entry","isDefault","chip","fontFamily","message","identity","fromName","localPart","join","senderId","page","pageSize","rowCount","count","onPageChange","setPage","labelDisplayedRows","customDomainPlan","state","pendingProvider","issueError","lastIssueError","using","hover","cursor","sending","padding","items","open","onClose","onSaved","fullWidth","maxWidth","mb","value","onChange","AppBarProps","appBarLeft","edge","mr","component","gutterY","event","target","autoFocus","placeholder","helperText"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ export interface OrgSendingDomainDetailProps {
2
+ domain: string;
3
+ /** The organization's Emails page, for the way back to Sending. */
4
+ basePath: string;
5
+ }
6
+ /**
7
+ * ONE SENDING DOMAIN, from the organization's page —
8
+ * `/[orgSlug]/emails/sending/{domain}`.
9
+ *
10
+ * The domain is the organization's, so its page reads the same as it does
11
+ * from a site's: what to publish, whether a lookup can see it, and the checks
12
+ * that move it on. What changes is the half that is a site's choice. Under a
13
+ * site this page asks whether THIS site sends as the domain; over the org it
14
+ * lists the sites that do, and offers to move another site onto it.
15
+ *
16
+ * The records come from the domains route, which is owner-or-admin. An editor
17
+ * still sees the domain's state and the sites sending as it — both come back
18
+ * on each site's own identity read, which an editor may make — and is told
19
+ * why the records are not shown rather than handed an error.
20
+ *
21
+ * `inconclusive` is held apart from the record exactly as on the site's page:
22
+ * a lookup nobody answered changed nothing.
23
+ */
24
+ export declare function OrgSendingDomainDetail(props: OrgSendingDomainDetailProps): import("react").JSX.Element;
25
+ export declare namespace OrgSendingDomainDetail {
26
+ var displayName: string;
27
+ }
28
+ export default OrgSendingDomainDetail;
@@ -0,0 +1,497 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { _ as _extends } from "@swc/helpers/_/_extends";
18
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
19
+ import { PageHeaderRecord, pluginDocsHelp } from "@aglyn/aglyn";
20
+ import { mdiDeleteOutline, mdiEmailCheckOutline } from "@aglyn/shared-data-mdi";
21
+ import { AppLink, CardDisplay, MdiIcon, useConfirmationContext } from "@aglyn/shared-ui-jsx";
22
+ import RowActionsMenu from "@aglyn/shared-ui-jsx/components/row-actions-menu.component";
23
+ import { useSnackbar } from "@aglyn/shared-ui-snackstack";
24
+ import { useSendingApi } from "@aglyn/tenant-feature-instance/hooks/use-sending-identity-api";
25
+ import { Alert, Button, Chip, Divider, Stack, Typography } from "@mui/material";
26
+ import { useRouter } from "next/navigation";
27
+ import { useCallback, useEffect, useRef, useState } from "react";
28
+ import { describeOrgSendingDomainRemoval, describeSendingDomain, INCONCLUSIVE_CHECK } from "../model/sending-domain-status.js";
29
+ import { OrgSiteSelect, orgSiteName, useEmailOrgMount, useOrgSitePage } from "./email-org-mount.js";
30
+ import { RecordRow } from "./sending-domain-detail.js";
31
+ import { useOrgSendingViews } from "./use-org-sending-views.js";
32
+ /**
33
+ * ONE SENDING DOMAIN, from the organization's page —
34
+ * `/[orgSlug]/emails/sending/{domain}`.
35
+ *
36
+ * The domain is the organization's, so its page reads the same as it does
37
+ * from a site's: what to publish, whether a lookup can see it, and the checks
38
+ * that move it on. What changes is the half that is a site's choice. Under a
39
+ * site this page asks whether THIS site sends as the domain; over the org it
40
+ * lists the sites that do, and offers to move another site onto it.
41
+ *
42
+ * The records come from the domains route, which is owner-or-admin. An editor
43
+ * still sees the domain's state and the sites sending as it — both come back
44
+ * on each site's own identity read, which an editor may make — and is told
45
+ * why the records are not shown rather than handed an error.
46
+ *
47
+ * `inconclusive` is held apart from the record exactly as on the site's page:
48
+ * a lookup nobody answered changed nothing.
49
+ */ export function OrgSendingDomainDetail(props) {
50
+ const mount = useEmailOrgMount();
51
+ return mount ? /*#__PURE__*/ _jsx(OrgSendingDomainPage, _extends({
52
+ mount: mount
53
+ }, props)) : null;
54
+ }
55
+ OrgSendingDomainDetail.displayName = 'OrgSendingDomainDetail';
56
+ function OrgSendingDomainPage(props) {
57
+ var _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7;
58
+ var _record_records, _record_dmarc;
59
+ const { mount, domain, basePath } = props;
60
+ const call = useSendingApi();
61
+ const router = useRouter();
62
+ const { confirm } = useConfirmationContext();
63
+ const { enqueueSnackbar } = useSnackbar();
64
+ // Held in a ref: `load` depends on it and the hook hands a fresh function
65
+ // back per render, which would re-run the fetch on every render.
66
+ const notifyRef = useRef(enqueueSnackbar);
67
+ notifyRef.current = enqueueSnackbar;
68
+ // The first page of sites by name: enough to say which of them send as
69
+ // this domain, and bounded however many sites the organization runs.
70
+ const { sites } = useOrgSitePage(mount);
71
+ const { views, reload, first, loading: viewsLoading } = useOrgSendingViews(sites);
72
+ const canManage = (first == null ? void 0 : first.canManage) === true;
73
+ const [record, setRecord] = useState(null);
74
+ const [refusal, setRefusal] = useState('');
75
+ const [loading, setLoading] = useState(true);
76
+ const [busy, setBusy] = useState(false);
77
+ const [unreachable, setUnreachable] = useState(false);
78
+ const [assignHostId, setAssignHostId] = useState('');
79
+ const load = useCallback(async ()=>{
80
+ var _find, _ref;
81
+ setLoading(true);
82
+ const { response, payload } = await call({
83
+ path: 'sending-domains',
84
+ method: 'GET',
85
+ query: {
86
+ orgId: mount.orgId
87
+ }
88
+ });
89
+ setLoading(false);
90
+ if (!response.ok) {
91
+ var _ref1;
92
+ setRecord(null);
93
+ setRefusal((_ref1 = payload == null ? void 0 : payload.error) != null ? _ref1 : 'This domain’s records could not be read.');
94
+ return;
95
+ }
96
+ setRefusal('');
97
+ setRecord((_find = ((_ref = payload == null ? void 0 : payload.domains) != null ? _ref : []).find((one)=>one.domain === domain)) != null ? _find : null);
98
+ }, [
99
+ call,
100
+ mount.orgId,
101
+ domain
102
+ ]);
103
+ useEffect(()=>{
104
+ void load();
105
+ }, [
106
+ load
107
+ ]);
108
+ /** The domain as the list knows it, for a reader the records route refused. */ const listed = (_ref = first == null ? void 0 : first.domains.find((one)=>one.domain === domain)) != null ? _ref : null;
109
+ const status = (_ref1 = (_ref2 = record == null ? void 0 : record.status) != null ? _ref2 : listed == null ? void 0 : listed.status) != null ? _ref1 : null;
110
+ const using = mount.hosts.filter((site)=>{
111
+ var _views_site_id;
112
+ return ((_views_site_id = views[site.id]) == null ? void 0 : _views_site_id.selected) === domain;
113
+ });
114
+ /** Sites whose identity this page has not read, so cannot speak for. */ const unchecked = mount.hosts.filter((site)=>!views[site.id]).length;
115
+ const offered = mount.hosts.filter((site)=>{
116
+ var _views_site_id;
117
+ return ((_views_site_id = views[site.id]) == null ? void 0 : _views_site_id.selected) !== domain;
118
+ });
119
+ const handleVerify = useCallback(async ()=>{
120
+ if (busy) return;
121
+ setBusy(true);
122
+ setUnreachable(false);
123
+ const { response, payload } = await call({
124
+ path: 'sending-domains',
125
+ method: 'POST',
126
+ body: {
127
+ orgId: mount.orgId,
128
+ domain,
129
+ action: 'verify'
130
+ }
131
+ });
132
+ setBusy(false);
133
+ if (response.status === 503) {
134
+ setUnreachable(true);
135
+ return;
136
+ }
137
+ if (!response.ok) {
138
+ var _ref;
139
+ return void notifyRef.current((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'The check could not run', {
140
+ variant: 'warning'
141
+ });
142
+ }
143
+ await Promise.all([
144
+ load(),
145
+ reload()
146
+ ]);
147
+ notifyRef.current((payload == null ? void 0 : payload.verified) ? 'Verified — this domain can send' : 'Checked. Some records are still missing.', {
148
+ variant: (payload == null ? void 0 : payload.verified) ? 'success' : 'info'
149
+ });
150
+ }, [
151
+ busy,
152
+ call,
153
+ domain,
154
+ load,
155
+ mount.orgId,
156
+ reload
157
+ ]);
158
+ const handleRequestRecords = useCallback(async ()=>{
159
+ if (busy) return;
160
+ setBusy(true);
161
+ const { response, payload } = await call({
162
+ path: 'sending-domains',
163
+ method: 'POST',
164
+ body: {
165
+ orgId: mount.orgId,
166
+ domain,
167
+ action: 'request'
168
+ }
169
+ });
170
+ setBusy(false);
171
+ if (!response.ok) {
172
+ var _ref;
173
+ return void notifyRef.current((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'Could not request records', {
174
+ variant: 'warning'
175
+ });
176
+ }
177
+ await load();
178
+ }, [
179
+ busy,
180
+ call,
181
+ domain,
182
+ load,
183
+ mount.orgId
184
+ ]);
185
+ /** Moves one site onto this domain, or off it with `'platform'`. */ const handleUse = useCallback(async (hostId, next)=>{
186
+ if (busy || !hostId) return;
187
+ setBusy(true);
188
+ const { response, payload } = await call({
189
+ path: 'sending-identity',
190
+ method: 'POST',
191
+ body: {
192
+ hostId,
193
+ domain: next
194
+ }
195
+ });
196
+ setBusy(false);
197
+ if (!response.ok) {
198
+ var _ref;
199
+ return void notifyRef.current((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'Could not change the identity', {
200
+ variant: 'warning'
201
+ });
202
+ }
203
+ setAssignHostId('');
204
+ await reload(hostId);
205
+ // The address the ROUTE settled on — see the site's page.
206
+ const site = orgSiteName(mount, hostId);
207
+ notifyRef.current((payload == null ? void 0 : payload.from) ? `${site} now sends as ${payload.from}` : `${site}’s sending address was changed`, {
208
+ variant: 'success'
209
+ });
210
+ }, [
211
+ busy,
212
+ call,
213
+ mount,
214
+ reload
215
+ ]);
216
+ const handleRelease = useCallback(async ()=>{
217
+ const ok = await confirm(_extends({}, describeOrgSendingDomainRemoval({
218
+ domain,
219
+ sites: using.map((site)=>{
220
+ var _views_site_id;
221
+ return {
222
+ name: orgSiteName(mount, site.id),
223
+ issued: ((_views_site_id = views[site.id]) == null ? void 0 : _views_site_id.platformDomain) === domain
224
+ };
225
+ }),
226
+ unchecked
227
+ }), {
228
+ confirmationButtonProps: {
229
+ color: 'error'
230
+ }
231
+ }))// `confirm` resolves with no value and REJECTS on cancel.
232
+ .then(()=>true).catch(()=>false);
233
+ if (!ok) return;
234
+ const { response, payload } = await call({
235
+ path: 'sending-domains',
236
+ method: 'DELETE',
237
+ query: {
238
+ orgId: mount.orgId,
239
+ domain
240
+ }
241
+ });
242
+ if (!response.ok) {
243
+ var _ref;
244
+ return void notifyRef.current((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'Could not remove the domain', {
245
+ variant: 'warning'
246
+ });
247
+ }
248
+ router.push(`${basePath}/sending`);
249
+ }, [
250
+ basePath,
251
+ call,
252
+ confirm,
253
+ domain,
254
+ mount,
255
+ router,
256
+ unchecked,
257
+ using,
258
+ views
259
+ ]);
260
+ const state = status ? describeSendingDomain({
261
+ status,
262
+ pendingProvider: (_ref3 = record == null ? void 0 : record.pendingProvider) != null ? _ref3 : status === 'requested',
263
+ issueError: (_ref4 = (_ref5 = record == null ? void 0 : record.lastIssueError) != null ? _ref5 : listed == null ? void 0 : listed.lastIssueError) != null ? _ref4 : null,
264
+ missing: (_ref6 = record == null ? void 0 : record.lastMissing) != null ? _ref6 : null
265
+ }) : null;
266
+ const missing = new Set((_ref7 = record == null ? void 0 : record.lastMissing) != null ? _ref7 : []);
267
+ const actions = canManage && record ? [
268
+ {
269
+ key: 'release',
270
+ label: 'Remove domain',
271
+ icon: /*#__PURE__*/ _jsx(MdiIcon, {
272
+ path: mdiDeleteOutline.path,
273
+ size: 0.8
274
+ }),
275
+ destructive: true,
276
+ onClick: ()=>void handleRelease()
277
+ }
278
+ ] : [];
279
+ const card = /*#__PURE__*/ _jsx(CardDisplay, {
280
+ header: 'Sending domain',
281
+ help: pluginDocsHelp('emailCampaigns', {
282
+ anchor: '#sending-domains'
283
+ }),
284
+ contentGutterX: true,
285
+ contentGutterY: true,
286
+ contentBordered: "all",
287
+ HeaderProps: {
288
+ action: /*#__PURE__*/ _jsxs(Stack, {
289
+ direction: "row",
290
+ spacing: 1,
291
+ sx: {
292
+ alignItems: 'center'
293
+ },
294
+ children: [
295
+ /*#__PURE__*/ _jsx(Button, _extends({
296
+ component: AppLink
297
+ }, {
298
+ componentVariant: 'naked',
299
+ nativeButton: false
300
+ }, {
301
+ href: `${basePath}/sending`,
302
+ size: "small",
303
+ color: "primary",
304
+ children: 'All of Sending'
305
+ })),
306
+ actions.length ? /*#__PURE__*/ _jsx(RowActionsMenu, {
307
+ items: actions
308
+ }) : null
309
+ ]
310
+ })
311
+ },
312
+ children: (loading || viewsLoading) && !state ? /*#__PURE__*/ _jsx(Typography, {
313
+ variant: "body2",
314
+ color: "text.secondary",
315
+ children: 'Loading…'
316
+ }) : !state ? /*#__PURE__*/ _jsx(Alert, {
317
+ severity: "warning",
318
+ children: refusal || `${domain} is not claimed by this organization. It may have been ` + 'removed — go back and add it again if you still want it.'
319
+ }) : /*#__PURE__*/ _jsxs(Stack, {
320
+ spacing: 2,
321
+ children: [
322
+ /*#__PURE__*/ _jsx(Stack, {
323
+ direction: "row",
324
+ spacing: 1,
325
+ useFlexGap: true,
326
+ sx: {
327
+ alignItems: 'center',
328
+ flexWrap: 'wrap'
329
+ },
330
+ children: /*#__PURE__*/ _jsx(Chip, {
331
+ label: state.label,
332
+ color: state.color,
333
+ variant: state.sending ? 'filled' : 'outlined'
334
+ })
335
+ }),
336
+ /*#__PURE__*/ _jsx(Alert, {
337
+ severity: state.severity,
338
+ children: state.text
339
+ }),
340
+ unreachable ? /*#__PURE__*/ _jsxs(Alert, {
341
+ severity: INCONCLUSIVE_CHECK.severity,
342
+ icon: false,
343
+ children: [
344
+ /*#__PURE__*/ _jsx(Typography, {
345
+ variant: "body2",
346
+ sx: {
347
+ fontWeight: 'bold'
348
+ },
349
+ children: INCONCLUSIVE_CHECK.label
350
+ }),
351
+ /*#__PURE__*/ _jsx(Typography, {
352
+ variant: "body2",
353
+ children: INCONCLUSIVE_CHECK.text
354
+ })
355
+ ]
356
+ }) : null,
357
+ /*#__PURE__*/ _jsx(Divider, {}),
358
+ /*#__PURE__*/ _jsx(Typography, {
359
+ variant: "body2",
360
+ sx: {
361
+ fontWeight: 'bold'
362
+ },
363
+ children: 'Sites sending as this domain'
364
+ }),
365
+ using.length ? /*#__PURE__*/ _jsx(Stack, {
366
+ spacing: 1,
367
+ children: using.map((site)=>/*#__PURE__*/ _jsxs(Stack, {
368
+ direction: "row",
369
+ spacing: 1,
370
+ sx: {
371
+ alignItems: 'center'
372
+ },
373
+ children: [
374
+ /*#__PURE__*/ _jsx(Typography, {
375
+ variant: "body2",
376
+ children: orgSiteName(mount, site.id)
377
+ }),
378
+ canManage ? /*#__PURE__*/ _jsx(Button, {
379
+ size: "small",
380
+ disabled: busy,
381
+ onClick: ()=>void handleUse(site.id, 'platform'),
382
+ children: 'Stop sending as this domain'
383
+ }) : null
384
+ ]
385
+ }, site.id))
386
+ }) : /*#__PURE__*/ _jsx(Typography, {
387
+ variant: "body2",
388
+ color: "text.secondary",
389
+ children: unchecked ? 'None of the sites checked sends as it.' : 'No site sends as it.'
390
+ }),
391
+ unchecked && !viewsLoading ? /*#__PURE__*/ _jsx(Typography, {
392
+ variant: "caption",
393
+ color: "text.secondary",
394
+ children: `${unchecked} more ${unchecked === 1 ? 'site was' : 'sites were'} ` + 'not checked; the Sending page reads them a page at a time.'
395
+ }) : null,
396
+ canManage && status === 'verified' && offered.length ? /*#__PURE__*/ _jsxs(Stack, {
397
+ direction: "row",
398
+ spacing: 1,
399
+ useFlexGap: true,
400
+ sx: {
401
+ alignItems: 'center',
402
+ flexWrap: 'wrap'
403
+ },
404
+ children: [
405
+ /*#__PURE__*/ _jsx(OrgSiteSelect, {
406
+ mount: mount,
407
+ label: "Send a site’s email as this domain",
408
+ value: assignHostId,
409
+ onChange: setAssignHostId,
410
+ sites: offered
411
+ }),
412
+ /*#__PURE__*/ _jsx(Button, {
413
+ variant: "outlined",
414
+ startIcon: /*#__PURE__*/ _jsx(MdiIcon, {
415
+ path: mdiEmailCheckOutline.path,
416
+ size: 0.8
417
+ }),
418
+ disabled: busy || !assignHostId,
419
+ onClick: ()=>void handleUse(assignHostId, domain),
420
+ children: 'Send as this domain'
421
+ })
422
+ ]
423
+ }) : null,
424
+ /*#__PURE__*/ _jsx(Divider, {}),
425
+ refusal ? /*#__PURE__*/ _jsx(Alert, {
426
+ severity: "info",
427
+ children: canManage ? refusal : 'The records to publish, and the checks that verify them, ' + 'are shown to the organization’s owners and admins.'
428
+ }) : record ? /*#__PURE__*/ _jsxs(_Fragment, {
429
+ children: [
430
+ record.dmarc ? /*#__PURE__*/ _jsx(Alert, {
431
+ severity: record.dmarc.policy === 'reject' && record.status !== 'verified' ? 'error' : 'info',
432
+ children: record.dmarc.consequence
433
+ }) : null,
434
+ ((_record_records = record.records) == null ? void 0 : _record_records.some((entry)=>entry.value)) ? /*#__PURE__*/ _jsxs(_Fragment, {
435
+ children: [
436
+ /*#__PURE__*/ _jsx(Typography, {
437
+ variant: "body2",
438
+ sx: {
439
+ fontWeight: 'bold'
440
+ },
441
+ children: 'Publish these records'
442
+ }),
443
+ /*#__PURE__*/ _jsxs(Stack, {
444
+ spacing: 2,
445
+ children: [
446
+ record.records.filter((entry)=>entry.value).map((entry)=>/*#__PURE__*/ _jsx(RecordRow, {
447
+ record: entry,
448
+ missing: missing.has(`${entry.type}:${entry.name}`)
449
+ }, `${entry.type}:${entry.name}`)),
450
+ record.dmarcSuggestion && ((_record_dmarc = record.dmarc) == null ? void 0 : _record_dmarc.policy) === 'absent' ? /*#__PURE__*/ _jsx(RecordRow, {
451
+ record: record.dmarcSuggestion,
452
+ missing: false
453
+ }) : null
454
+ ]
455
+ })
456
+ ]
457
+ }) : null,
458
+ /*#__PURE__*/ _jsxs(Stack, {
459
+ direction: "row",
460
+ spacing: 1,
461
+ sx: {
462
+ flexWrap: 'wrap',
463
+ gap: 1
464
+ },
465
+ children: [
466
+ record.status === 'requested' && canManage ? /*#__PURE__*/ _jsx(Button, {
467
+ variant: "contained",
468
+ disabled: busy,
469
+ onClick: ()=>void handleRequestRecords(),
470
+ children: busy ? 'Working…' : 'Request records'
471
+ }) : null,
472
+ record.status !== 'requested' ? /*#__PURE__*/ _jsx(Button, {
473
+ variant: "contained",
474
+ disabled: busy,
475
+ onClick: ()=>void handleVerify(),
476
+ children: busy ? 'Checking…' : 'Check DNS'
477
+ }) : null
478
+ ]
479
+ })
480
+ ]
481
+ }) : null
482
+ ]
483
+ })
484
+ });
485
+ return /*#__PURE__*/ _jsxs(_Fragment, {
486
+ children: [
487
+ /*#__PURE__*/ _jsx(PageHeaderRecord, {
488
+ title: domain
489
+ }),
490
+ card
491
+ ]
492
+ });
493
+ }
494
+ OrgSendingDomainPage.displayName = 'OrgSendingDomainPage';
495
+ export default OrgSendingDomainDetail;
496
+
497
+ //# sourceMappingURL=org-sending-domain-detail.js.map