From 56823b18edec0a1d4593f9bde31a9601f3d648bc Mon Sep 17 00:00:00 2001 From: Michal Klimek Date: Tue, 11 Feb 2025 12:07:01 -0600 Subject: [PATCH] feat: update to use translation function with English fallbacks --- assets/approval-requests-bundle.js | 74 ++++--- assets/shared-bundle.js | 34 ++- .../ApprovalRequestListPage.tsx | 11 +- .../ApprovalRequestListFilters.tsx | 48 +++- .../ApprovalRequestListTable.tsx | 22 +- .../ApprovalRequestDetails.tsx | 54 ++++- .../approval-request/ApprovalStatusTag.tsx | 42 ++-- .../ApprovalTicketDetails.tsx | 38 +++- .../approval-request/ApproverActions.tsx | 53 ++++- .../approval-requests/translations/en-us.yml | 208 ++++++++++++++++++ 10 files changed, 486 insertions(+), 98 deletions(-) diff --git a/assets/approval-requests-bundle.js b/assets/approval-requests-bundle.js index 7a838427f..47eaf7f1f 100644 --- a/assets/approval-requests-bundle.js +++ b/assets/approval-requests-bundle.js @@ -1,4 +1,4 @@ -import { r as reactExports, s as styled, d as Field, k as debounce, j as jsxRuntimeExports, e as Label, a as MediaInput, al as SvgSearchStroke, g as Combobox, O as Option, B as Tag, am as Ellipsis, G as getColorV8, A as Anchor, an as Table, ao as Head, ap as HeaderRow, aq as HeaderCell, ar as SortableCell, as as Body, at as Row, au as Cell, ad as MD, av as Spinner, aw as XXL, a4 as reactDomExports, a5 as ThemeProviders, a6 as createTheme, ah as ErrorBoundary, a9 as Grid, ab as Row$1, aa as Col, c as useNotify, F as Field$1, L as Label$1, ax as Avatar, T as Textarea, M as Message, Z as Button, ay as Breadcrumb } from 'shared'; +import { r as reactExports, s as styled, d as Field, u as useTranslation, k as debounce, j as jsxRuntimeExports, e as Label, a as MediaInput, al as SvgSearchStroke, g as Combobox, O as Option, B as Tag, am as Ellipsis, G as getColorV8, A as Anchor, an as Table, ao as Head, ap as HeaderRow, aq as HeaderCell, ar as SortableCell, as as Body, at as Row, au as Cell, ad as MD, av as Spinner, aw as XXL, a4 as reactDomExports, a5 as ThemeProviders, a6 as createTheme, ah as ErrorBoundary, a9 as Grid, ab as Row$1, aa as Col, c as useNotify, F as Field$1, L as Label$1, ax as Avatar, T as Textarea, M as Message, Z as Button, ay as Breadcrumb } from 'shared'; function useSearchApprovalRequests() { const [approvalRequests, setApprovalRequests] = reactExports.useState([]); @@ -76,6 +76,7 @@ const ApprovalRequestStatusInputMap = { withdrawn: "Withdrawn", }; function ApprovalRequestListFilters({ approvalRequestStatus, setApprovalRequestStatus, setSearchTerm, }) { + const { t } = useTranslation(); const handleChange = reactExports.useCallback((changes) => { if (!changes.selectionValue) { return; @@ -87,7 +88,7 @@ function ApprovalRequestListFilters({ approvalRequestStatus, setApprovalRequestS const handleSearch = reactExports.useCallback((event) => { debouncedSetSearchTerm(event.target.value); }, [debouncedSetSearchTerm]); - return (jsxRuntimeExports.jsxs(FiltersContainer, { children: [jsxRuntimeExports.jsxs(SearchField, { children: [jsxRuntimeExports.jsx(Label, { hidden: true, children: "Search approval requests" }), jsxRuntimeExports.jsx(MediaInput, { start: jsxRuntimeExports.jsx(SvgSearchStroke, {}), placeholder: "Search approval requests", onChange: handleSearch })] }), jsxRuntimeExports.jsxs(DropdownFilterField, { children: [jsxRuntimeExports.jsx(Label, { children: "Status:" }), jsxRuntimeExports.jsxs(Combobox, { isEditable: false, onChange: handleChange, selectionValue: approvalRequestStatus, inputValue: ApprovalRequestStatusInputMap[approvalRequestStatus], children: [jsxRuntimeExports.jsx(Option, { value: "any", label: "Any" }), jsxRuntimeExports.jsx(Option, { value: "active", label: "Decision pending" }), jsxRuntimeExports.jsx(Option, { value: "approved", label: "Approved" }), jsxRuntimeExports.jsx(Option, { value: "rejected", label: "Denied" }), jsxRuntimeExports.jsx(Option, { value: "withdrawn", label: "Withdrawn" })] })] })] })); + return (jsxRuntimeExports.jsxs(FiltersContainer, { children: [jsxRuntimeExports.jsxs(SearchField, { children: [jsxRuntimeExports.jsx(Label, { hidden: true, children: t("approval-requests.list.search-placeholder", "Search approval requests") }), jsxRuntimeExports.jsx(MediaInput, { start: jsxRuntimeExports.jsx(SvgSearchStroke, {}), placeholder: t("approval-requests.list.search-placeholder", "Search approval requests"), onChange: handleSearch })] }), jsxRuntimeExports.jsxs(DropdownFilterField, { children: [jsxRuntimeExports.jsx(Label, { children: t("approval-requests.list.status-dropdown.label", "Status:") }), jsxRuntimeExports.jsxs(Combobox, { isEditable: false, onChange: handleChange, selectionValue: approvalRequestStatus, inputValue: ApprovalRequestStatusInputMap[approvalRequestStatus], children: [jsxRuntimeExports.jsx(Option, { value: "any", label: t("approval-requests.list.status-dropdown.any", "Any") }), jsxRuntimeExports.jsx(Option, { value: "active", label: t("approval-requests.status.decision-pending", "Decision pending") }), jsxRuntimeExports.jsx(Option, { value: "approved", label: t("approval-requests.status.approved", "Approved") }), jsxRuntimeExports.jsx(Option, { value: "rejected", label: t("approval-requests.status.denied", "Denied") }), jsxRuntimeExports.jsx(Option, { value: "withdrawn", label: t("approval-requests.status.withdrawn", "Withdrawn") })] })] })] })); } var ApprovalRequestListFilters$1 = reactExports.memo(ApprovalRequestListFilters); @@ -99,18 +100,27 @@ const APPROVAL_REQUEST_STATES = { WITHDRAWN: "withdrawn", }; const DEFAULT_STATUS_CONFIG = { hue: "grey", label: "Unknown status" }; -const statusTagConfig = { - [APPROVAL_REQUEST_STATES.ACTIVE]: { hue: "blue", label: "Decision pending" }, - [APPROVAL_REQUEST_STATES.APPROVED]: { hue: "green", label: "Approved" }, - [APPROVAL_REQUEST_STATES.REJECTED]: { hue: "red", label: "Denied" }, - // [APPROVAL_REQUEST_STATES.CLARIFICATION_REQUESTED]: { - // hue: "yellow", - // label: "Info needed", - // }, - [APPROVAL_REQUEST_STATES.WITHDRAWN]: { hue: "grey", label: "Withdrawn" }, -}; function ApprovalStatusTag({ status }) { - const config = statusTagConfig[status] || DEFAULT_STATUS_CONFIG; + const { t } = useTranslation(); + const statusMap = { + [APPROVAL_REQUEST_STATES.ACTIVE]: { + hue: "blue", + label: t("approval-requests.status.decision-pending", "Decision pending"), + }, + [APPROVAL_REQUEST_STATES.APPROVED]: { + hue: "green", + label: t("approval-requests.status.approved", "Approved"), + }, + [APPROVAL_REQUEST_STATES.REJECTED]: { + hue: "red", + label: t("approval-requests.status.denied", "Denied"), + }, + [APPROVAL_REQUEST_STATES.WITHDRAWN]: { + hue: "grey", + label: t("approval-requests.status.withdrawn", "Withdrawn"), + }, + }; + const config = statusMap[status] || DEFAULT_STATUS_CONFIG; return (jsxRuntimeExports.jsx(Tag, { hue: config.hue, children: jsxRuntimeExports.jsx(Ellipsis, { children: config.label }) })); } var ApprovalStatusTag$1 = reactExports.memo(ApprovalStatusTag); @@ -141,6 +151,7 @@ const sortableCellProps = { isTruncated: true, }; function ApprovalRequestListTable({ requests, helpCenterPath, baseLocale, sortDirection, onSortChange, }) { + const { t } = useTranslation(); const handleSortClick = () => { if (sortDirection === "asc") { onSortChange("desc"); @@ -152,7 +163,7 @@ function ApprovalRequestListTable({ requests, helpCenterPath, baseLocale, sortDi onSortChange("asc"); } }; - return (jsxRuntimeExports.jsxs(Table, { size: "large", children: [jsxRuntimeExports.jsx(Head, { children: jsxRuntimeExports.jsxs(HeaderRow, { children: [jsxRuntimeExports.jsx(HeaderCell, { width: "40%", isTruncated: true, children: "Subject" }), jsxRuntimeExports.jsx(HeaderCell, { isTruncated: true, children: "Requester" }), jsxRuntimeExports.jsx(HeaderCell, { isTruncated: true, children: "Sent by" }), jsxRuntimeExports.jsx(SortableCell, { onClick: handleSortClick, sort: sortDirection, cellProps: sortableCellProps, children: "Sent on" }), jsxRuntimeExports.jsx(HeaderCell, { isTruncated: true, children: "Approval status" })] }) }), jsxRuntimeExports.jsx(Body, { children: requests.map((request) => (jsxRuntimeExports.jsxs(Row, { children: [jsxRuntimeExports.jsx(Cell, { isTruncated: true, children: jsxRuntimeExports.jsx(ApprovalRequestAnchor, { href: `${helpCenterPath}/approval_requests/${request.id}`, children: request.subject }) }), jsxRuntimeExports.jsx(Cell, { isTruncated: true, children: request.requester_name }), jsxRuntimeExports.jsx(Cell, { isTruncated: true, children: request.created_by_name }), jsxRuntimeExports.jsx(Cell, { isTruncated: true, children: formatApprovalRequestDate(request.created_at, baseLocale) }), jsxRuntimeExports.jsx(Cell, { isTruncated: true, children: jsxRuntimeExports.jsx(ApprovalStatusTag$1, { status: request.status }) })] }, request.id))) })] })); + return (jsxRuntimeExports.jsxs(Table, { size: "large", children: [jsxRuntimeExports.jsx(Head, { children: jsxRuntimeExports.jsxs(HeaderRow, { children: [jsxRuntimeExports.jsx(HeaderCell, { width: "40%", isTruncated: true, children: t("approval-requests.list.table.subject", "Subject") }), jsxRuntimeExports.jsx(HeaderCell, { isTruncated: true, children: t("approval-requests.list.table.requester", "Requester") }), jsxRuntimeExports.jsx(HeaderCell, { isTruncated: true, children: t("approval-requests.list.table.sent-by", "Sent by") }), jsxRuntimeExports.jsx(SortableCell, { onClick: handleSortClick, sort: sortDirection, cellProps: sortableCellProps, children: t("approval-requests.list.table.sent-on", "Sent on") }), jsxRuntimeExports.jsx(HeaderCell, { isTruncated: true, children: t("approval-requests.list.table.approval-status", "Approval status") })] }) }), jsxRuntimeExports.jsx(Body, { children: requests.map((request) => (jsxRuntimeExports.jsxs(Row, { children: [jsxRuntimeExports.jsx(Cell, { isTruncated: true, children: jsxRuntimeExports.jsx(ApprovalRequestAnchor, { href: `${helpCenterPath}/approval_requests/${request.id}`, children: request.subject }) }), jsxRuntimeExports.jsx(Cell, { isTruncated: true, children: request.requester_name }), jsxRuntimeExports.jsx(Cell, { isTruncated: true, children: request.created_by_name }), jsxRuntimeExports.jsx(Cell, { isTruncated: true, children: formatApprovalRequestDate(request.created_at, baseLocale) }), jsxRuntimeExports.jsx(Cell, { isTruncated: true, children: jsxRuntimeExports.jsx(ApprovalStatusTag$1, { status: request.status }) })] }, request.id))) })] })); } var ApprovalRequestListTable$1 = reactExports.memo(ApprovalRequestListTable); @@ -171,6 +182,7 @@ const NoApprovalRequestsText = styled(MD) ` color: ${(props) => getColorV8("grey", 600, props.theme)}; `; function ApprovalRequestListPage({ baseLocale, helpCenterPath, }) { + const { t } = useTranslation(); const [searchTerm, setSearchTerm] = reactExports.useState(""); const [sortDirection, setSortDirection] = reactExports.useState(undefined); const { approvalRequests, errorFetchingApprovalRequests: error, approvalRequestStatus, setApprovalRequestStatus, isLoading, } = useSearchApprovalRequests(); @@ -197,7 +209,7 @@ function ApprovalRequestListPage({ baseLocale, helpCenterPath, }) { if (isLoading) { return (jsxRuntimeExports.jsx(LoadingContainer$1, { children: jsxRuntimeExports.jsx(Spinner, { size: "64" }) })); } - return (jsxRuntimeExports.jsxs(Container$2, { children: [jsxRuntimeExports.jsx(XXL, { isBold: true, children: "Approval requests" }), jsxRuntimeExports.jsx(ApprovalRequestListFilters$1, { approvalRequestStatus: approvalRequestStatus, setApprovalRequestStatus: setApprovalRequestStatus, setSearchTerm: setSearchTerm }), approvalRequests.length === 0 ? (jsxRuntimeExports.jsx(NoApprovalRequestsText, { children: "No approval requests found." })) : (jsxRuntimeExports.jsx(ApprovalRequestListTable$1, { requests: sortedAndFilteredRequests, baseLocale: baseLocale, helpCenterPath: helpCenterPath, sortDirection: sortDirection, onSortChange: setSortDirection }))] })); + return (jsxRuntimeExports.jsxs(Container$2, { children: [jsxRuntimeExports.jsx(XXL, { isBold: true, children: t("approval-requests.list.header", "Approval requests") }), jsxRuntimeExports.jsx(ApprovalRequestListFilters$1, { approvalRequestStatus: approvalRequestStatus, setApprovalRequestStatus: setApprovalRequestStatus, setSearchTerm: setSearchTerm }), approvalRequests.length === 0 ? (jsxRuntimeExports.jsx(NoApprovalRequestsText, { children: t("approval-requests.list.no-requests", "No approval requests found.") })) : (jsxRuntimeExports.jsx(ApprovalRequestListTable$1, { requests: sortedAndFilteredRequests, baseLocale: baseLocale, helpCenterPath: helpCenterPath, sortDirection: sortDirection, onSortChange: setSortDirection }))] })); } var ApprovalRequestListPage$1 = reactExports.memo(ApprovalRequestListPage); @@ -224,7 +236,12 @@ const DetailRow = styled(Row$1) ` } `; function ApprovalRequestDetails({ approvalRequest, baseLocale, }) { - return (jsxRuntimeExports.jsxs(Container$1, { children: [jsxRuntimeExports.jsx(ApprovalRequestHeader, { isBold: true, children: "Approval request details" }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Sent by" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: approvalRequest.created_by_user.name }) })] }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Sent on" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: formatApprovalRequestDate(approvalRequest.created_at, baseLocale) }) })] }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Approver" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: approvalRequest.assignee_user.name }) })] }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Status" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: jsxRuntimeExports.jsx(ApprovalStatusTag$1, { status: approvalRequest.status }) }) })] }), approvalRequest.decision_notes.length > 0 && (jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Comment" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: approvalRequest.decision_notes[0] }) })] })), approvalRequest.decided_at && (jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: "Decided" }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: formatApprovalRequestDate(approvalRequest.decided_at, baseLocale) }) })] }))] })); + const { t } = useTranslation(); + return (jsxRuntimeExports.jsxs(Container$1, { children: [jsxRuntimeExports.jsx(ApprovalRequestHeader, { isBold: true, children: t("approval-requests.request.approval-request-details.header", "Approval request details") }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: t("approval-requests.request.approval-request-details.sent-by", "Sent by") }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: approvalRequest.created_by_user.name }) })] }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: t("approval-requests.request.approval-request-details.sent-on", "Sent on") }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: formatApprovalRequestDate(approvalRequest.created_at, baseLocale) }) })] }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: t("approval-requests.request.approval-request-details.approver", "Approver") }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: approvalRequest.assignee_user.name }) })] }), jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: t("approval-requests.request.approval-request-details.status", "Status") }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: jsxRuntimeExports.jsx(ApprovalStatusTag$1, { status: approvalRequest.status }) }) })] }), approvalRequest.decision_notes.length > 0 && (jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: t("approval-requests.request.approval-request-details.comment", "Comment") }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: approvalRequest.decision_notes[0] }) })] })), approvalRequest.decided_at && (jsxRuntimeExports.jsxs(DetailRow, { children: [jsxRuntimeExports.jsx(Col, { size: 4, children: jsxRuntimeExports.jsx(FieldLabel$1, { children: t(approvalRequest.status === "withdrawn" + ? "approval-requests.request.approval-request-details.withdrawn-on" + : "approval-requests.request.approval-request-details.decided", approvalRequest.status === "withdrawn" + ? "Withdrawn on" + : "Decided") }) }), jsxRuntimeExports.jsx(Col, { size: 8, children: jsxRuntimeExports.jsx(MD, { children: formatApprovalRequestDate(approvalRequest.decided_at, baseLocale) }) })] }))] })); } var ApprovalRequestDetails$1 = reactExports.memo(ApprovalRequestDetails); @@ -255,11 +272,14 @@ const CustomFieldsGrid = styled.div ` `; const NULL_VALUE_PLACEHOLDER = "-"; function CustomFieldValue({ value, }) { + const { t } = useTranslation(); if (Array.isArray(value) && value.length > 0) { return (jsxRuntimeExports.jsx(MD, { children: value.map((val) => (jsxRuntimeExports.jsx(MultiselectTag, { hue: "grey", children: val }, val))) })); } if (typeof value === "boolean") { - return jsxRuntimeExports.jsx(MD, { children: value ? "Yes" : "No" }); + return (jsxRuntimeExports.jsx(MD, { children: value + ? t("approval-requests.request.ticket-details.checkbox-value.yes", "Yes") + : t("approval-requests.request.ticket-details.checkbox-value.no", "No") })); } if (!value || (Array.isArray(value) && value.length === 0)) { return jsxRuntimeExports.jsx(MD, { children: NULL_VALUE_PLACEHOLDER }); @@ -267,7 +287,8 @@ function CustomFieldValue({ value, }) { return jsxRuntimeExports.jsx(MD, { children: value }); } function ApprovalTicketDetails({ ticket }) { - return (jsxRuntimeExports.jsxs(TicketContainer, { children: [jsxRuntimeExports.jsx(TicketDetailsHeader, { isBold: true, children: "Ticket Details" }), jsxRuntimeExports.jsxs(CustomFieldsGrid, { children: [jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx(FieldLabel, { children: "Requester" }), jsxRuntimeExports.jsx(MD, { children: ticket.requester.name })] }), jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx(FieldLabel, { children: "ID" }), jsxRuntimeExports.jsx(MD, { children: ticket.id })] }), jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx(FieldLabel, { children: "Priority" }), jsxRuntimeExports.jsx(MD, { children: ticket.priority })] }), ticket.custom_fields.map((field) => (jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx(FieldLabel, { children: field.title_in_portal }), jsxRuntimeExports.jsx(CustomFieldValue, { value: field.value })] }, String(field.id))))] })] })); + const { t } = useTranslation(); + return (jsxRuntimeExports.jsxs(TicketContainer, { children: [jsxRuntimeExports.jsx(TicketDetailsHeader, { isBold: true, children: t("approval-requests.request.ticket-details.header", "Ticket details") }), jsxRuntimeExports.jsxs(CustomFieldsGrid, { children: [jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx(FieldLabel, { children: t("approval-requests.request.ticket-details.requester", "Requester") }), jsxRuntimeExports.jsx(MD, { children: ticket.requester.name })] }), jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx(FieldLabel, { children: t("approval-requests.request.ticket-details.id", "ID") }), jsxRuntimeExports.jsx(MD, { children: ticket.id })] }), jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx(FieldLabel, { children: t("approval-requests.request.ticket-details.priority", "Priority") }), jsxRuntimeExports.jsx(MD, { children: ticket.priority })] }), ticket.custom_fields.map((field) => (jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsx(FieldLabel, { children: field.title_in_portal }), jsxRuntimeExports.jsx(CustomFieldValue, { value: field.value })] }, String(field.id))))] })] })); } var ApprovalTicketDetails$1 = reactExports.memo(ApprovalTicketDetails); @@ -338,6 +359,7 @@ const TextAreaContainer = styled.div ` align-items: flex-start; `; function ApproverActions({ approvalRequestId, approvalWorkflowInstanceId, setApprovalRequest, assigneeUser, }) { + const { t } = useTranslation(); const notify = useNotify(); const [comment, setComment] = reactExports.useState(""); const [pendingStatus, setPendingStatus] = reactExports.useState(null); @@ -374,7 +396,9 @@ function ApproverActions({ approvalRequestId, approvalWorkflowInstanceId, setApp if (response.ok) { const data = await response.json(); setApprovalRequest(data.approval_request); - const notificationTitle = decision === "approved" ? "Approval submitted" : "Denial submitted"; + const notificationTitle = decision === "approved" + ? t("approval-requests.request.notification.approval-submitted", "Approval submitted") + : t("approval-requests.request.notification.denial-submitted", "Denial submitted"); notify({ type: "success", title: notificationTitle, @@ -398,14 +422,14 @@ function ApproverActions({ approvalRequestId, approvalWorkflowInstanceId, setApp }; if (pendingStatus) { const fieldLabel = pendingStatus === PENDING_APPROVAL_STATUS.APPROVED - ? "Additional note" - : "Reason for denial* (Required)"; + ? t("approval-requests.request.approver-actions.additional-note-label", "Additional note") + : t("approval-requests.request.approver-actions.denial-reason-label", "Reason for denial* (Required)"); const shouldShowAvatar = Boolean(assigneeUser?.photo?.content_url); - return (jsxRuntimeExports.jsx(ActionWrapper, { children: jsxRuntimeExports.jsxs(CommentSection, { children: [jsxRuntimeExports.jsxs(Field$1, { children: [jsxRuntimeExports.jsx(Label$1, { children: fieldLabel }), jsxRuntimeExports.jsxs(TextAreaContainer, { children: [shouldShowAvatar && (jsxRuntimeExports.jsx(Avatar, { children: jsxRuntimeExports.jsx("img", { alt: "Assignee avatar", src: assigneeUser.photo.content_url ?? undefined }) })), jsxRuntimeExports.jsx(Textarea, { minRows: 5, value: comment, onChange: handleInputValueChange, disabled: isSubmitting, validation: shouldShowValidationError ? "error" : undefined })] }), shouldShowValidationError && (jsxRuntimeExports.jsx(Message, { validation: "error", children: "Enter a reason for denial" }))] }), jsxRuntimeExports.jsxs(ButtonContainer, { hasAvatar: shouldShowAvatar, isSubmitButton: true, children: [jsxRuntimeExports.jsx(Button, { isPrimary: pendingStatus === PENDING_APPROVAL_STATUS.APPROVED, onClick: handleSubmitDecisionClick, disabled: isSubmitting, children: pendingStatus === PENDING_APPROVAL_STATUS.APPROVED - ? "Submit approval" - : "Submit denial" }), jsxRuntimeExports.jsx(Button, { onClick: handleCancelClick, disabled: isSubmitting, children: "Cancel" })] })] }) })); + return (jsxRuntimeExports.jsx(ActionWrapper, { children: jsxRuntimeExports.jsxs(CommentSection, { children: [jsxRuntimeExports.jsxs(Field$1, { children: [jsxRuntimeExports.jsx(Label$1, { children: fieldLabel }), jsxRuntimeExports.jsxs(TextAreaContainer, { children: [shouldShowAvatar && (jsxRuntimeExports.jsx(Avatar, { children: jsxRuntimeExports.jsx("img", { alt: "Assignee avatar", src: assigneeUser.photo.content_url ?? undefined }) })), jsxRuntimeExports.jsx(Textarea, { minRows: 5, value: comment, onChange: handleInputValueChange, disabled: isSubmitting, validation: shouldShowValidationError ? "error" : undefined })] }), shouldShowValidationError && (jsxRuntimeExports.jsx(Message, { validation: "error", children: t("approval-requests.request.approver-actions.denial-reason-validation", "Enter a reason for denial") }))] }), jsxRuntimeExports.jsxs(ButtonContainer, { hasAvatar: shouldShowAvatar, isSubmitButton: true, children: [jsxRuntimeExports.jsx(Button, { isPrimary: pendingStatus === PENDING_APPROVAL_STATUS.APPROVED, onClick: handleSubmitDecisionClick, disabled: isSubmitting, children: pendingStatus === PENDING_APPROVAL_STATUS.APPROVED + ? t("approval-requests.request.approver-actions.submit-approval", "Submit approval") + : t("approval-requests.request.approver-actions.submit-denial", "Submit denial") }), jsxRuntimeExports.jsx(Button, { onClick: handleCancelClick, disabled: isSubmitting, children: t("approval-requests.request.approver-actions.cancel", "Cancel") })] })] }) })); } - return (jsxRuntimeExports.jsx(ActionWrapper, { children: jsxRuntimeExports.jsxs(ButtonContainer, { children: [jsxRuntimeExports.jsx(Button, { isPrimary: true, onClick: handleApproveRequestClick, children: "Approve request" }), jsxRuntimeExports.jsx(Button, { onClick: handleDenyRequestClick, children: "Deny request" })] }) })); + return (jsxRuntimeExports.jsx(ActionWrapper, { children: jsxRuntimeExports.jsxs(ButtonContainer, { children: [jsxRuntimeExports.jsx(Button, { isPrimary: true, onClick: handleApproveRequestClick, children: t("approval-requests.request.approver-actions.approve-request", "Approve request") }), jsxRuntimeExports.jsx(Button, { onClick: handleDenyRequestClick, children: t("approval-requests.request.approver-actions.deny-request", "Deny request") })] }) })); } var ApproverActions$1 = reactExports.memo(ApproverActions); diff --git a/assets/shared-bundle.js b/assets/shared-bundle.js index 8691e9d88..625d79e9c 100644 --- a/assets/shared-bundle.js +++ b/assets/shared-bundle.js @@ -157,17 +157,17 @@ var l=requireObjectAssign(),n=60103,p=60106;react_production_min.Fragment=60107; return react_production_min; } -var hasRequiredReact; +{ + react.exports = requireReact_production_min(); +} -function requireReact () { - if (hasRequiredReact) return react.exports; - hasRequiredReact = 1; +var reactExports = react.exports; +var React__default = /*@__PURE__*/getDefaultExportFromCjs(reactExports); - { - react.exports = requireReact_production_min(); - } - return react.exports; -} +var React = /*#__PURE__*/_mergeNamespaces({ + __proto__: null, + default: React__default +}, [reactExports]); /** @license React v17.0.2 * react-jsx-runtime.production.min.js @@ -183,7 +183,7 @@ var hasRequiredReactJsxRuntime_production_min; function requireReactJsxRuntime_production_min () { if (hasRequiredReactJsxRuntime_production_min) return reactJsxRuntime_production_min; hasRequiredReactJsxRuntime_production_min = 1; -requireObjectAssign();var f=requireReact(),g=60103;reactJsxRuntime_production_min.Fragment=60107;if("function"===typeof Symbol&&Symbol.for){var h=Symbol.for;g=h("react.element");reactJsxRuntime_production_min.Fragment=h("react.fragment");}var m=f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,n=Object.prototype.hasOwnProperty,p={key:!0,ref:!0,__self:!0,__source:!0}; +requireObjectAssign();var f=reactExports,g=60103;reactJsxRuntime_production_min.Fragment=60107;if("function"===typeof Symbol&&Symbol.for){var h=Symbol.for;g=h("react.element");reactJsxRuntime_production_min.Fragment=h("react.fragment");}var m=f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,n=Object.prototype.hasOwnProperty,p={key:!0,ref:!0,__self:!0,__source:!0}; function q(c,a,k){var b,d={},e=null,l=null;void 0!==k&&(e=""+k);void 0!==a.key&&(e=""+a.key);void 0!==a.ref&&(l=a.ref);for(b in a)n.call(a,b)&&!p.hasOwnProperty(b)&&(d[b]=a[b]);if(c&&c.defaultProps)for(b in a=c.defaultProps,a)void 0===d[b]&&(d[b]=a[b]);return {$$typeof:g,type:c,key:e,ref:l,props:d,_owner:m.current}}reactJsxRuntime_production_min.jsx=q;reactJsxRuntime_production_min.jsxs=q; return reactJsxRuntime_production_min; } @@ -259,7 +259,7 @@ var hasRequiredReactDom_production_min; function requireReactDom_production_min () { if (hasRequiredReactDom_production_min) return reactDom_production_min; hasRequiredReactDom_production_min = 1; -var aa=requireReact(),m=requireObjectAssign(),r=requireScheduler();function y(a){for(var b="https://reactjs.org/docs/error-decoder.html?invariant="+a,c=1;c(undefined); const { @@ -82,7 +84,9 @@ function ApprovalRequestListPage({ return ( - Approval requests + + {t("approval-requests.list.header", "Approval requests")} + {approvalRequests.length === 0 ? ( - No approval requests found. + {t( + "approval-requests.list.no-requests", + "No approval requests found." + )} ) : ( >( (changes) => { if (!changes.selectionValue) { @@ -88,27 +91,54 @@ function ApprovalRequestListFilters({ return ( - + } - placeholder="Search approval requests" + placeholder={t( + "approval-requests.list.search-placeholder", + "Search approval requests" + )} onChange={handleSearch} /> - + - diff --git a/src/modules/approval-requests/components/approval-request-list/ApprovalRequestListTable.tsx b/src/modules/approval-requests/components/approval-request-list/ApprovalRequestListTable.tsx index 5d56fddde..9d18f2641 100644 --- a/src/modules/approval-requests/components/approval-request-list/ApprovalRequestListTable.tsx +++ b/src/modules/approval-requests/components/approval-request-list/ApprovalRequestListTable.tsx @@ -1,5 +1,6 @@ import { memo } from "react"; import styled from "styled-components"; +import { useTranslation } from "react-i18next"; import { Table, Head, @@ -45,6 +46,8 @@ function ApprovalRequestListTable({ sortDirection, onSortChange, }: ApprovalRequestListTableProps) { + const { t } = useTranslation(); + const handleSortClick = () => { if (sortDirection === "asc") { onSortChange("desc"); @@ -60,18 +63,27 @@ function ApprovalRequestListTable({ - Subject + {t("approval-requests.list.table.subject", "Subject")} + + + {t("approval-requests.list.table.requester", "Requester")} + + + {t("approval-requests.list.table.sent-by", "Sent by")} - Requester - Sent by - Sent on + {t("approval-requests.list.table.sent-on", "Sent on")} - Approval status + + {t( + "approval-requests.list.table.approval-status", + "Approval status" + )} + diff --git a/src/modules/approval-requests/components/approval-request/ApprovalRequestDetails.tsx b/src/modules/approval-requests/components/approval-request/ApprovalRequestDetails.tsx index cc56d9c38..94c842929 100644 --- a/src/modules/approval-requests/components/approval-request/ApprovalRequestDetails.tsx +++ b/src/modules/approval-requests/components/approval-request/ApprovalRequestDetails.tsx @@ -1,5 +1,6 @@ import { memo } from "react"; import styled from "styled-components"; +import { useTranslation } from "react-i18next"; import { MD } from "@zendeskgarden/react-typography"; import { getColorV8 } from "@zendeskgarden/react-theming"; import { Grid, Row, Col } from "@zendeskgarden/react-grid"; @@ -38,14 +39,24 @@ function ApprovalRequestDetails({ approvalRequest, baseLocale, }: ApprovalRequestDetailsProps) { + const { t } = useTranslation(); + return ( - Approval request details + {t( + "approval-requests.request.approval-request-details.header", + "Approval request details" + )} - Sent by + + {t( + "approval-requests.request.approval-request-details.sent-by", + "Sent by" + )} + {approvalRequest.created_by_user.name} @@ -53,7 +64,12 @@ function ApprovalRequestDetails({ - Sent on + + {t( + "approval-requests.request.approval-request-details.sent-on", + "Sent on" + )} + @@ -63,7 +79,12 @@ function ApprovalRequestDetails({ - Approver + + {t( + "approval-requests.request.approval-request-details.approver", + "Approver" + )} + {approvalRequest.assignee_user.name} @@ -71,7 +92,12 @@ function ApprovalRequestDetails({ - Status + + {t( + "approval-requests.request.approval-request-details.status", + "Status" + )} + @@ -82,7 +108,12 @@ function ApprovalRequestDetails({ {approvalRequest.decision_notes.length > 0 && ( - Comment + + {t( + "approval-requests.request.approval-request-details.comment", + "Comment" + )} + {approvalRequest.decision_notes[0]} @@ -92,7 +123,16 @@ function ApprovalRequestDetails({ {approvalRequest.decided_at && ( - Decided + + {t( + approvalRequest.status === "withdrawn" + ? "approval-requests.request.approval-request-details.withdrawn-on" + : "approval-requests.request.approval-request-details.decided", + approvalRequest.status === "withdrawn" + ? "Withdrawn on" + : "Decided" + )} + diff --git a/src/modules/approval-requests/components/approval-request/ApprovalStatusTag.tsx b/src/modules/approval-requests/components/approval-request/ApprovalStatusTag.tsx index 5e1e50a93..882890549 100644 --- a/src/modules/approval-requests/components/approval-request/ApprovalStatusTag.tsx +++ b/src/modules/approval-requests/components/approval-request/ApprovalStatusTag.tsx @@ -1,4 +1,5 @@ import { memo } from "react"; +import { useTranslation } from "react-i18next"; import { Tag } from "@zendeskgarden/react-tags"; import { Ellipsis } from "@zendeskgarden/react-typography"; import type { ApprovalRequestStatus } from "../../types"; @@ -13,26 +14,37 @@ const APPROVAL_REQUEST_STATES = { const DEFAULT_STATUS_CONFIG = { hue: "grey", label: "Unknown status" }; -const statusTagConfig: Record< - ApprovalRequestStatus, - { hue: string; label: string } -> = { - [APPROVAL_REQUEST_STATES.ACTIVE]: { hue: "blue", label: "Decision pending" }, - [APPROVAL_REQUEST_STATES.APPROVED]: { hue: "green", label: "Approved" }, - [APPROVAL_REQUEST_STATES.REJECTED]: { hue: "red", label: "Denied" }, - // [APPROVAL_REQUEST_STATES.CLARIFICATION_REQUESTED]: { - // hue: "yellow", - // label: "Info needed", - // }, - [APPROVAL_REQUEST_STATES.WITHDRAWN]: { hue: "grey", label: "Withdrawn" }, -}; - interface ApprovalStatusTagProps { status: ApprovalRequestStatus; } function ApprovalStatusTag({ status }: ApprovalStatusTagProps) { - const config = statusTagConfig[status] || DEFAULT_STATUS_CONFIG; + const { t } = useTranslation(); + + const statusTagMap = { + [APPROVAL_REQUEST_STATES.ACTIVE]: { + hue: "blue", + label: t("approval-requests.status.decision-pending", "Decision pending"), + }, + [APPROVAL_REQUEST_STATES.APPROVED]: { + hue: "green", + label: t("approval-requests.status.approved", "Approved"), + }, + [APPROVAL_REQUEST_STATES.REJECTED]: { + hue: "red", + label: t("approval-requests.status.denied", "Denied"), + }, + // [APPROVAL_REQUEST_STATES.CLARIFICATION_REQUESTED]: { + // hue: "yellow", + // label: t("approval-requests.status.info-needed", "Info needed"), + // }, + [APPROVAL_REQUEST_STATES.WITHDRAWN]: { + hue: "grey", + label: t("approval-requests.status.withdrawn", "Withdrawn"), + }, + }; + + const config = statusTagMap[status] || DEFAULT_STATUS_CONFIG; return ( {config.label} diff --git a/src/modules/approval-requests/components/approval-request/ApprovalTicketDetails.tsx b/src/modules/approval-requests/components/approval-request/ApprovalTicketDetails.tsx index bc89f71a2..514969bbd 100644 --- a/src/modules/approval-requests/components/approval-request/ApprovalTicketDetails.tsx +++ b/src/modules/approval-requests/components/approval-request/ApprovalTicketDetails.tsx @@ -1,5 +1,6 @@ import { memo } from "react"; import styled from "styled-components"; +import { useTranslation } from "react-i18next"; import { MD } from "@zendeskgarden/react-typography"; import { getColorV8 } from "@zendeskgarden/react-theming"; import { Grid } from "@zendeskgarden/react-grid"; @@ -43,6 +44,8 @@ function CustomFieldValue({ }: { value: string | boolean | Array | undefined; }) { + const { t } = useTranslation(); + if (Array.isArray(value) && value.length > 0) { return ( @@ -56,7 +59,19 @@ function CustomFieldValue({ } if (typeof value === "boolean") { - return {value ? "Yes" : "No"}; + return ( + + {value + ? t( + "approval-requests.request.ticket-details.checkbox-value.yes", + "Yes" + ) + : t( + "approval-requests.request.ticket-details.checkbox-value.no", + "No" + )} + + ); } if (!value || (Array.isArray(value) && value.length === 0)) { @@ -71,20 +86,33 @@ interface ApprovalTicketDetailsProps { } function ApprovalTicketDetails({ ticket }: ApprovalTicketDetailsProps) { + const { t } = useTranslation(); + return ( - Ticket Details + + {t("approval-requests.request.ticket-details.header", "Ticket details")} +
- Requester + + {t( + "approval-requests.request.ticket-details.requester", + "Requester" + )} + {ticket.requester.name}
- ID + + {t("approval-requests.request.ticket-details.id", "ID")} + {ticket.id}
- Priority + + {t("approval-requests.request.ticket-details.priority", "Priority")} + {ticket.priority}
{ticket.custom_fields.map((field) => ( diff --git a/src/modules/approval-requests/components/approval-request/ApproverActions.tsx b/src/modules/approval-requests/components/approval-request/ApproverActions.tsx index fc628c11b..e45c4231d 100644 --- a/src/modules/approval-requests/components/approval-request/ApproverActions.tsx +++ b/src/modules/approval-requests/components/approval-request/ApproverActions.tsx @@ -1,5 +1,6 @@ import { useState, useCallback, memo } from "react"; import styled from "styled-components"; +import { useTranslation } from "react-i18next"; import { Button } from "@zendeskgarden/react-buttons"; import { Field, Label, Message, Textarea } from "@zendeskgarden/react-forms"; import { Avatar } from "@zendeskgarden/react-avatars"; @@ -71,6 +72,7 @@ function ApproverActions({ setApprovalRequest, assigneeUser, }: ApproverActionsProps) { + const { t } = useTranslation(); const notify = useNotify(); const [comment, setComment] = useState(""); const [pendingStatus, setPendingStatus] = useState< @@ -129,7 +131,15 @@ function ApproverActions({ setApprovalRequest(data.approval_request); const notificationTitle = - decision === "approved" ? "Approval submitted" : "Denial submitted"; + decision === "approved" + ? t( + "approval-requests.request.notification.approval-submitted", + "Approval submitted" + ) + : t( + "approval-requests.request.notification.denial-submitted", + "Denial submitted" + ); notify({ type: "success", title: notificationTitle, @@ -152,8 +162,14 @@ function ApproverActions({ if (pendingStatus) { const fieldLabel = pendingStatus === PENDING_APPROVAL_STATUS.APPROVED - ? "Additional note" - : "Reason for denial* (Required)"; + ? t( + "approval-requests.request.approver-actions.additional-note-label", + "Additional note" + ) + : t( + "approval-requests.request.approver-actions.denial-reason-label", + "Reason for denial* (Required)" + ); const shouldShowAvatar = Boolean(assigneeUser?.photo?.content_url); return ( @@ -179,7 +195,12 @@ function ApproverActions({ /> {shouldShowValidationError && ( - Enter a reason for denial + + {t( + "approval-requests.request.approver-actions.denial-reason-validation", + "Enter a reason for denial" + )} + )} @@ -189,11 +210,17 @@ function ApproverActions({ disabled={isSubmitting} > {pendingStatus === PENDING_APPROVAL_STATUS.APPROVED - ? "Submit approval" - : "Submit denial"} + ? t( + "approval-requests.request.approver-actions.submit-approval", + "Submit approval" + ) + : t( + "approval-requests.request.approver-actions.submit-denial", + "Submit denial" + )} @@ -205,9 +232,17 @@ function ApproverActions({ + - ); diff --git a/src/modules/approval-requests/translations/en-us.yml b/src/modules/approval-requests/translations/en-us.yml index e69de29bb..eaf267060 100644 --- a/src/modules/approval-requests/translations/en-us.yml +++ b/src/modules/approval-requests/translations/en-us.yml @@ -0,0 +1,208 @@ +# +# This file is used for the internal Zendesk translation system, and it is generated from the extract-strings.mjs script. +# It contains the English strings to be translated, which are used for generating the JSON files containing the translation strings +# for each language. +# +# If you are building your own theme, you can remove this file and just load the translation JSON files, or provide +# your translations with a different method. +# + +title: "Copenhagen Theme Approval requests" +packages: + - "approval-requests" +parts: + - translation: + key: "approval-requests.request.ticket-details.header" + title: "Header for the ticket details section displayed on the individual approval request page" + screenshot: "https://drive.google.com/file/d/1-mngvtPAewxxavZdD5s9XZrIUgtGW4Vj/view?usp=drive_link" + value: "Ticket details" + - translation: + key: "approval-requests.request.ticket-details.requester" + title: "Label for the person who submitted the ticket associated with the approval request" + screenshot: "https://drive.google.com/file/d/14qPWuPcsMFDC6J_HhOBbNlI9hBeLMKA-/view?usp=sharing" + value: "Requester" + - translation: + key: "approval-requests.request.ticket-details.id" + title: "Label for the unique identifier of the ticket associated with the approval request" + screenshot: "https://drive.google.com/file/d/1IJdg-vXQAUtcgS-JWWwgVOyRg5IO8Cey/view?usp=drive_link" + value: "ID" + - translation: + key: "approval-requests.request.ticket-details.priority" + title: "Label for the priority of the ticket associated with the approval request" + screenshot: "https://drive.google.com/file/d/1rB8uGfpnaDXGATBlsNyRdbntZKvS4BeW/view?usp=sharing" + value: "Priority" + - translation: + key: "approval-requests.request.ticket-details.checkbox-value.yes" + title: "Value representing true for a checkbox custom field" + screenshot: "https://drive.google.com/file/d/1Vk8x7k2DzF7t9DT5Q-KfmEbCZRmFOBeE/view?usp=drive_link" + value: "Yes" + - translation: + key: "approval-requests.request.ticket-details.checkbox-value.no" + title: "Value representing false for a checkbox custom field" + screenshot: "https://drive.google.com/file/d/1AiuLQXnW6qELTJtIFQX0JaBCA7zViMXA/view?usp=drive_link" + value: "No" + - translation: + key: "approval-requests.request.approval-request-details.header" + title: "Header for the approval request section displayed on the individual approval request page" + screenshot: "https://drive.google.com/file/d/1fteldN_Z4yTgd7UPzQi0xYv8TTPJxX9c/view?usp=drive_link" + value: "Approval request details" + - translation: + key: "approval-requests.request.approval-request-details.sent-by" + title: "Label for the person who submitted the approval request - Subject: 'approval request'" + screenshot: "https://drive.google.com/file/d/1-RFlHvEdegvChs6TuVTXxx6ubeSab-hc/view?usp=drive_link" + value: "Sent by" + - translation: + key: "approval-requests.request.approval-request-details.sent-on" + title: "Label for the date that the approval request was submitted - Subject: 'approval request'" + screenshot: "https://drive.google.com/file/d/1Kmy-XgNfCE5dgh-oipsc1P_sZ3gmvjD6/view?usp=drive_link" + value: "Sent on" + - translation: + key: "approval-requests.request.approval-request-details.approver" + title: "Label for the individual assigned to review and approve the request" + screenshot: "https://drive.google.com/file/d/1VnGlaQE9sSsKqwY3iKZn-AiJK8RnfUL8/view?usp=drive_link" + value: "Approver" + - translation: + key: "approval-requests.request.approval-request-details.status" + title: "Label for the current status of the approval request" + screenshot: "https://drive.google.com/file/d/11G6qZpoQoMzyEUxncBo4RovT93thSuXx/view?usp=drive_link" + value: "Status" + - translation: + key: "approval-requests.request.approval-request-details.comment" + title: "Noun - Label for the decision comment on an approval request" + screenshot: "https://drive.google.com/file/d/1j9IzjnAa1AVXzWq6r4x4QcaQN-Y64lM5/view?usp=drive_link" + value: "Comment" + - translation: + key: "approval-requests.request.approval-request-details.decided" + title: "Label for the decision date on an approval request - Subject: 'approval request'" + screenshot: "https://drive.google.com/file/d/1xpM_3Rt3hCD8aE-U7mEbL0Sh5dsC0ScN/view?usp=drive_link" + value: "Decided" + - translation: + key: "approval-requests.request.approval-request-details.withdrawn-on" + title: "Label for the withdrawn date on an approval request - Subject: 'approval request'" + screenshot: "https://drive.google.com/file/d/1hkgy-71WFkLQnZ0PmEHFaWhfnuguiUmv/view?usp=drive_link" + value: "Withdrawn on" + - translation: + key: "approval-requests.request.approver-actions.approve-request" + title: "Label for the approve request button to begin approving an approval request" + screenshot: "https://drive.google.com/file/d/1uWDMNa7cfF2EdD5HpDxcTVHTa6M07v81/view?usp=drive_link" + value: "Approve request" + - translation: + key: "approval-requests.request.approver-actions.deny-request" + title: "Label for the deny request button to begin denying an approval request" + screenshot: "https://drive.google.com/file/d/1sEO2wxGJU6Jz1ZClBvkYDTXCXT9yqsGZ/view?usp=drive_link" + value: "Deny request" + - translation: + key: "approval-requests.request.approver-actions.denial-reason-label" + title: "Label for the input box where the reason for denying an approval request is provided" + screenshot: "https://drive.google.com/file/d/1WZx7DbwkudNbNYMIEwF56npryQGIpsG7/view?usp=drive_link" + value: "Reason for denial* (Required)" + - translation: + key: "approval-requests.request.approver-actions.denial-reason-validation" + title: "Validation message shown when attempting to deny an approval request without a reason for denial" + screenshot: "https://drive.google.com/file/d/1-wo8BGxMuV6bHD7mjlX8Lm3OTc_9RyFz/view?usp=drive_link" + value: "Enter a reason for denial" + - translation: + key: "approval-requests.request.approver-actions.additional-note-label" + title: "Label for the input box where the additional note when approving an approval request is provided" + screenshot: "https://drive.google.com/file/d/1gacesWd8MkyIY6UXvQSatv2ok67ZhbKk/view?usp=drive_link" + value: "Additional note" + - translation: + key: "approval-requests.request.approver-actions.submit-approval" + title: "Label for the submit approval button when approving an approval request" + screenshot: "https://drive.google.com/file/d/12C2F8zoCD_nMU-jSeu4kaMWwTeJNE3HJ/view?usp=drive_link" + value: "Submit approval" + - translation: + key: "approval-requests.request.approver-actions.submit-denial" + title: "Label for the submit denial button when denying an approval request" + screenshot: "https://drive.google.com/file/d/153Idb3CgJ_eFfWxLE4esAdB0DceOH8gj/view?usp=drive_link" + value: "Submit denial" + - translation: + key: "approval-requests.request.approver-actions.cancel" + title: "Label for the cancel button when approving or denying an approval request" + screenshot: "https://drive.google.com/file/d/1TjjF7CrDr-VYbZ-rpGs0pLCersevq9uL/view?usp=drive_link" + value: "Cancel" + - translation: + key: "approval-requests.request.notification.denial-submitted" + title: "Notification message shown when the denial of an approval request was submitted" + screenshot: "https://drive.google.com/file/d/1_Af2Xi2l6kcKI9QmFFQxH3SvI_Eaarg5/view?usp=drive_link" + value: "Denial submitted" + - translation: + key: "approval-requests.request.notification.approval-submitted" + title: "Notification message shown when the approval of an approval request was submitted" + screenshot: "https://drive.google.com/file/d/16BOEFXrbM29me3KdGgROerXXO5ns-7oh/view?usp=drive_link" + value: "Approval submitted" + - translation: + key: "approval-requests.list.header" + title: "Header for the approval requests list page" + screenshot: "https://drive.google.com/file/d/1MUj23YI3kUT-Udmh1LA0rt85-q078SMj/view?usp=drive_link" + value: "Approval requests" + - translation: + key: "approval-requests.list.search-placeholder" + title: "Placeholder for the search dropdown on the approval requests list page" + screenshot: "https://drive.google.com/file/d/10Mdnw0YkIq3w4CjdDOSD9efAAxDapzYr/view?usp=drive_link" + value: "Search approval requests" + - translation: + key: "approval-requests.list.no-requests" + title: "Text to convey that no approval requests exist on the approval requests list page." + screenshot: "https://drive.google.com/file/d/1rrZ1MZKAsY7mNo89McYaZNwEB5pDjKtk/view?usp=sharing" + value: "No approval requests found." + - translation: + key: "approval-requests.list.status-dropdown.label" + title: "Label for the status dropdown on the approval requests list page" + screenshot: "https://drive.google.com/file/d/18_4fS0yROAMC1yVdDYLfYvjKWeUdWCDH/view?usp=drive_link" + value: "Status:" + - translation: + key: "approval-requests.list.status-dropdown.any" + title: "Label for any dropdown option within the status dropdown on the approval requests list page - Subject: 'status'" + screenshot: "https://drive.google.com/file/d/1dIURRxQu-EkQD9f1U0gKj_4mIBqBSRz3/view?usp=drive_link" + value: "Any" + - translation: + key: "approval-requests.list.table.subject" + title: "Header cell label for the subject column of the approval requests list table" + screenshot: "https://drive.google.com/file/d/1AfMOHvrRQoTODXWor5gtn7wn8AFI_5n-/view?usp=drive_link" + value: "Subject" + - translation: + key: "approval-requests.list.table.requester" + title: "Header cell label for the requester column of the approval requests list table" + screenshot: "https://drive.google.com/file/d/1tUTbmtSZCYxxDVbpQtZ6C50QDYlJU88I/view?usp=drive_link" + value: "Requester" + - translation: + key: "approval-requests.list.table.sent-by" + title: "Header cell label for the sent by column of the approval requests list table - Subject: 'approval request'" + screenshot: "https://drive.google.com/file/d/1k49KpSKk1OT4NYfeZqdb7WZLEwJZndpq/view?usp=drive_link" + value: "Sent by" + - translation: + key: "approval-requests.list.table.sent-on" + title: "Header cell label for the sent on column of the approval requests list table - Subject: 'approval request'" + screenshot: "https://drive.google.com/file/d/1i2fKqUDlWbNnYRZdxp041dAPhMsFznXO/view?usp=drive_link" + value: "Sent on" + - translation: + key: "approval-requests.list.table.approval-status" + title: "Header cell label for the approval status column of the approval requests list table" + screenshot: "https://drive.google.com/file/d/1ltG2DXbLbR1-6CaK_su1pbKQeN7kVMMV/view?usp=drive_link" + value: "Approval status" + - translation: + key: "approval-requests.status.decision-pending" + title: "Status label for the decision pending status of an approval request - Subject: 'status'" + screenshot: "https://drive.google.com/file/d/1wMA0ZAm8f_Mw0wgj7UKl7wkBU8XGH_ox/view?usp=drive_link" + value: "Decision pending" + - translation: + key: "approval-requests.status.info-needed" + title: "Status label for the info needed status of an approval request - Subject: 'status'" + screenshot: "https://drive.google.com/file/d/11Isf_F0qGOFh6Dv5RnR44ta5yJxX9n_4/view?usp=drive_link" + value: "Info needed" + - translation: + key: "approval-requests.status.approved" + title: "Status label for the approved status of an approval request - Subject: 'status'" + screenshot: "https://drive.google.com/file/d/1Xc8uehxpLHQR2Pjxfyo-wbvooPwe8-WX/view?usp=drive_link" + value: "Approved" + - translation: + key: "approval-requests.status.denied" + title: "Status label for the denied status of an approval request - Subject: 'status'" + screenshot: "https://drive.google.com/file/d/13qjrnfFVk61r5QMxd4CL_B8RY4cYzO1r/view?usp=drive_link" + value: "Denied" + - translation: + key: "approval-requests.status.withdrawn" + title: "Status label for the withdrawn status of an approval request - Subject: 'status'" + screenshot: "https://drive.google.com/file/d/1iOTsHEB5xae4LGZbjr4ibtdSDf0h9BOE/view?usp=drive_link" + value: "Withdrawn"