diff --git a/src/actions/email-actions.js b/src/actions/email-actions.js index 2e0799df0..63f6ff57c 100644 --- a/src/actions/email-actions.js +++ b/src/actions/email-actions.js @@ -251,7 +251,7 @@ const normalizeEntity = (entity) => { return normalizedEntity; }; -export const queryTemplates = debounce(async (input, callback) => { +export const queryTemplates = debounce(async (input, callback, onError) => { const accessToken = await getAccessTokenSafely(); const endpoint = URI(`${window.EMAIL_API_BASE_URL}/api/v1/mail-templates`); @@ -274,7 +274,10 @@ export const queryTemplates = debounce(async (input, callback) => { callback(options); }) - .catch(fetchErrorHandler); + .catch((err) => { + fetchErrorHandler(err); + if (onError) onError(err); + }); }, DEBOUNCE_WAIT); /** ********************************************************************************************************* */ diff --git a/src/i18n/en.json b/src/i18n/en.json index 58eb3a2c0..9406755e9 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -3265,6 +3265,7 @@ } }, "emails": { + "emails": "Emails", "email_templates": "Email Templates", "sent": "Sent", "templates": "Templates", @@ -3319,6 +3320,9 @@ "email_logs": "Email Logs", "email_list": "Email List", "apply_filters": "Apply Filters", + "enabled_filters": "Enabled Filters", + "all": "All", + "not_sent": "Not Sent", "email_templates": "Email Templates", "subject": "Subject", "from_email": "From Email", @@ -3328,7 +3332,6 @@ "payload": "Payload", "select_fields": "Show Columns", "placeholders": { - "select_fields": "Select data to display", "template": "Filter by Template", "sent_date_from": "Filter Sent Date from", "sent_date_to": "Filter Sent Date to" diff --git a/src/pages/emails/email-log-list-page.js b/src/pages/emails/email-log-list-page.js index 417c16571..7fe83ecdc 100644 --- a/src/pages/emails/email-log-list-page.js +++ b/src/pages/emails/email-log-list-page.js @@ -11,40 +11,54 @@ * limitations under the License. * */ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { connect } from "react-redux"; import T from "i18n-react/dist/i18n-react"; -import { Pagination } from "react-bootstrap"; -import FreeTextSearch from "openstack-uicore-foundation/lib/components/free-text-search" -import Table from "openstack-uicore-foundation/lib/components/table" -import Dropdown from "openstack-uicore-foundation/lib/components/inputs/dropdown" -import DateTimePicker from "openstack-uicore-foundation/lib/components/inputs/datetimepicker"; +import { + Autocomplete, + Box, + Button, + CircularProgress, + FormControl, + Grid2, + InputLabel, + MenuItem, + OutlinedInput, + Select, + TextField, + ToggleButton, + ToggleButtonGroup +} from "@mui/material"; +import { DateTimePicker } from "@mui/x-date-pickers/DateTimePicker"; +import MuiTable from "openstack-uicore-foundation/lib/components/mui/table"; +import SearchInput from "openstack-uicore-foundation/lib/components/mui/search-input"; import { epochToMomentTimeZone } from "openstack-uicore-foundation/lib/utils/methods"; -import { SegmentedControl } from "segmented-control"; -import { getSentEmails } from "../../actions/email-actions"; -import "../../styles/email-logs-page.less"; -import EmailTemplateInput from "../../components/inputs/email-template-input"; +import { getSentEmails, queryTemplates } from "../../actions/email-actions"; import { DATE_FILTER_ARRAY_SIZE, DEFAULT_CURRENT_PAGE } from "../../utils/constants"; -const SentEmailListPage = function ({ +const SentEmailListPage = ({ emails, - lastPage, currentPage, term, order, orderDir, totalEmails, - match, perPage, filters, - getSentEmails, - ...props -}) { + getSentEmails +}) => { useEffect(() => { - getSentEmails(term, currentPage, perPage, order, orderDir, filters); + getSentEmails( + term, + DEFAULT_CURRENT_PAGE, + perPage, + order, + orderDir, + filters + ); }, []); const defaultFilters = { @@ -65,15 +79,52 @@ const SentEmailListPage = function ({ ...filters }); const [selectedColumns, setSelectedColumns] = useState([]); + const [templateOptions, setTemplateOptions] = useState([]); + const [templateLoading, setTemplateLoading] = useState(false); + const templateRequestSeqRef = useRef(0); + + const fetchTemplateOptions = (input) => { + const seq = ++templateRequestSeqRef.current; + setTemplateLoading(true); + queryTemplates( + input, + (results) => { + if (seq !== templateRequestSeqRef.current) return; + setTemplateOptions( + results.map((t) => ({ value: t.identifier, label: t.identifier })) + ); + setTemplateLoading(false); + }, + () => { + if (seq !== templateRequestSeqRef.current) return; + setTemplateLoading(false); + } + ); + }; + + useEffect(() => { + fetchTemplateOptions(""); + }, []); const handlePageChange = (newPage) => { getSentEmails(term, newPage, perPage, order, orderDir, emailFilters); }; - const handleSort = (index, key, dir, func) => { + const handleSort = (index, key, dir) => { getSentEmails(term, currentPage, perPage, key, dir, emailFilters); }; + const handlePerPageChange = (newPerPage) => { + getSentEmails( + term, + DEFAULT_CURRENT_PAGE, + newPerPage, + order, + orderDir, + emailFilters + ); + }; + const handleSearch = (newTerm) => { getSentEmails( newTerm, @@ -113,37 +164,19 @@ const SentEmailListPage = function ({ } }; - const handleChangeDateFilter = (ev, lastDate) => { - const { value, id } = ev.target; - const newDateFilter = emailFilters[id]; + const handleChangeDateFilter = (value, lastDate) => { + const newDateFilter = emailFilters.sent_date_filter; setEmailFilters({ ...emailFilters, - [id]: lastDate - ? [newDateFilter[0], value.unix()] - : [value.unix(), newDateFilter[1]] + sent_date_filter: lastDate + ? [newDateFilter[0], value ? value.unix() : null] + : [value ? value.unix() : null, newDateFilter[1]] }); }; const handleEmailFilterChange = (ev) => { - const { type, id } = ev.target; - let { value } = ev.target; - if (type === "operatorinput") { - value = Array.isArray(value) - ? value - : `${ev.target.operator}${ev.target.value}`; - if (id === "duration_filter") { - value = Array.isArray(value) - ? value - : `${ev.target.operator}${ev.target.value}`; - } - } - if (type === "mediatypeinput") { - value = { - operator: ev.target.operator, - value: ev.target.value - }; - } + const { id, value } = ev.target; setEmailFilters({ ...emailFilters, [id]: value }); }; @@ -170,11 +203,11 @@ const SentEmailListPage = function ({ }; const fieldNames = [ - { columnKey: "last_error", value: "last_error" }, + { columnKey: "last_error", header: "last_error" }, { columnKey: "payload", - value: "payload", - render: (row, data) =>
{data}
+ header: "payload", + render: (row, data) => {data} } ]; @@ -183,7 +216,7 @@ const SentEmailListPage = function ({ .map((f2) => { let c = { columnKey: f2.columnKey, - value: T.translate(`email_logs.${f2.value}`), + header: T.translate(`email_logs.${f2.header}`), sortable: f2.sortable }; // optional fields @@ -195,23 +228,23 @@ const SentEmailListPage = function ({ }); let columns = [ - { columnKey: "id", value: T.translate("general.id"), sortable: true }, + { columnKey: "id", header: T.translate("general.id"), sortable: true }, { columnKey: "template", - value: T.translate("email_logs.email_templates"), + header: T.translate("email_logs.email_templates"), styles: { wordBreak: "break-all" }, sortable: true }, - { columnKey: "subject", value: T.translate("email_logs.subject") }, - { columnKey: "from_email", value: T.translate("email_logs.from_email") }, + { columnKey: "subject", header: T.translate("email_logs.subject") }, + { columnKey: "from_email", header: T.translate("email_logs.from_email") }, { columnKey: "to_email", - value: T.translate("email_logs.to_email"), + header: T.translate("email_logs.to_email"), styles: { wordBreak: "break-word" } }, { columnKey: "sent_date", - value: T.translate("email_logs.sent_date"), + header: T.translate("email_logs.sent_date"), sortable: true } ]; @@ -236,172 +269,245 @@ const SentEmailListPage = function ({ return (
-

- {" "} - {T.translate("email_logs.email_list")} ({totalEmails}) -

-
-
- -
-
-
-
-
- -
-
- -
-
-
+ + + + {enabledFilters.includes("is_sent_filter") && ( -
- handleSetSentFilter(newValue)} - style={{ + + handleSetSentFilter(newValue)} + sx={(theme) => ({ width: "100%", height: 40, - color: "#337ab7", - fontSize: "10px" - }} - /> -
+ "& .MuiToggleButtonGroup-grouped": { + flex: 1, + "&.Mui-selected": { + backgroundColor: theme.palette.primary.main, + color: theme.palette.primary.contrastText, + "&:hover": { + backgroundColor: theme.palette.primary.dark + } + } + } + })} + > + + {T.translate("email_logs.all")} + + + {T.translate("emails.sent")} + + + {T.translate("email_logs.not_sent")} + + +
)} {enabledFilters.includes("sent_date_filter") && ( <> -
+ handleChangeDateFilter(ev, false)} + label={T.translate("email_logs.placeholders.sent_date_from")} + format="YYYY-MM-DD hh:mm A" + ampm + onChange={(value) => handleChangeDateFilter(value, false)} timezone="UTC" value={epochToMomentTimeZone( emailFilters.sent_date_filter[0], "UTC" )} - className="event-list-date-picker" + slotProps={{ + textField: { fullWidth: true, size: "small" } + }} /> -
-
+ + handleChangeDateFilter(ev, true)} + label={T.translate("email_logs.placeholders.sent_date_to")} + format="YYYY-MM-DD hh:mm A" + ampm + onChange={(value) => handleChangeDateFilter(value, true)} timezone="UTC" value={epochToMomentTimeZone( emailFilters.sent_date_filter[1], "UTC" )} - className="event-list-date-picker" + slotProps={{ + textField: { fullWidth: true, size: "small" } + }} /> -
+ )} {enabledFilters.includes("template_filter") && ( -
- + option.label || ""} + isOptionEqualToValue={(option, val) => option.value === val.value} + onInputChange={(ev, newInput) => fetchTemplateOptions(newInput)} + onChange={(ev, selected) => + handleEmailFilterChange({ + target: { + id: "template_filter", + value: selected?.value ?? "" + } + }) + } + renderInput={(params) => ( + + {templateLoading && ( + + )} + {params.InputProps?.endAdornment} + + ) + } + }} + /> + )} /> -
+ )} -
-
-
- - + + + {emails.length === 0 &&
{T.translate("emails.no_emails")}
} {emails.length > 0 && ( - <> -
- - - - + )} ); diff --git a/src/styles/email-logs-page.less b/src/styles/email-logs-page.less deleted file mode 100644 index 3e3ad68c4..000000000 --- a/src/styles/email-logs-page.less +++ /dev/null @@ -1,7 +0,0 @@ -.email-logs-table-wrapper { - overflow: auto; -} - -.email-table-payload { - max-width: 300px; -}