@gooddata/sdk-ui-dashboard 10.37.0 → 10.38.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +173 -661
- package/esm/__version.d.ts +1 -1
- package/esm/__version.d.ts.map +1 -1
- package/esm/__version.js +1 -1
- package/esm/__version.js.map +1 -1
- package/esm/_staging/dateFilterConfig/defaultConfig.d.ts +0 -4
- package/esm/_staging/dateFilterConfig/defaultConfig.d.ts.map +1 -1
- package/esm/_staging/dateFilterConfig/defaultConfig.js +294 -15
- package/esm/_staging/dateFilterConfig/defaultConfig.js.map +1 -1
- package/esm/_staging/sharedHooks/useFiltersNamings.d.ts.map +1 -1
- package/esm/_staging/sharedHooks/useFiltersNamings.js +2 -1
- package/esm/_staging/sharedHooks/useFiltersNamings.js.map +1 -1
- package/esm/locales.d.ts +3 -0
- package/esm/locales.d.ts.map +1 -1
- package/esm/locales.js +1 -0
- package/esm/locales.js.map +1 -1
- package/esm/model/commandHandlers/dashboard/exportDashboardToExcelHandler.d.ts.map +1 -1
- package/esm/model/commandHandlers/dashboard/exportDashboardToExcelHandler.js +4 -1
- package/esm/model/commandHandlers/dashboard/exportDashboardToExcelHandler.js.map +1 -1
- package/esm/model/commandHandlers/drill/common/filterValuesResolver.d.ts.map +1 -1
- package/esm/model/commandHandlers/drill/common/filterValuesResolver.js +4 -2
- package/esm/model/commandHandlers/drill/common/filterValuesResolver.js.map +1 -1
- package/esm/model/commandHandlers/widgets/common/filterOperations.d.ts.map +1 -1
- package/esm/model/commandHandlers/widgets/common/filterOperations.js +6 -1
- package/esm/model/commandHandlers/widgets/common/filterOperations.js.map +1 -1
- package/esm/model/store/filterContext/filterContextSelectors.js +6 -6
- package/esm/model/store/filterContext/filterContextSelectors.js.map +1 -1
- package/esm/model/store/filterContext/filterContextUtils.d.ts.map +1 -1
- package/esm/model/store/filterContext/filterContextUtils.js +1 -0
- package/esm/model/store/filterContext/filterContextUtils.js.map +1 -1
- package/esm/model/store/index.d.ts +1 -1
- package/esm/model/store/index.d.ts.map +1 -1
- package/esm/model/store/index.js +1 -1
- package/esm/model/store/index.js.map +1 -1
- package/esm/model/store/topBar/topBarSelectors.d.ts +5 -0
- package/esm/model/store/topBar/topBarSelectors.d.ts.map +1 -1
- package/esm/model/store/topBar/topBarSelectors.js +8 -3
- package/esm/model/store/topBar/topBarSelectors.js.map +1 -1
- package/esm/presentation/componentDefinition/index.d.ts +1 -1
- package/esm/presentation/componentDefinition/index.d.ts.map +1 -1
- package/esm/presentation/componentDefinition/index.js +1 -2
- package/esm/presentation/componentDefinition/index.js.map +1 -1
- package/esm/presentation/dashboard/DashboardHeader/ShareDialogDashboardHeader.d.ts.map +1 -1
- package/esm/presentation/dashboard/DashboardHeader/ShareDialogDashboardHeader.js +2 -2
- package/esm/presentation/dashboard/DashboardHeader/ShareDialogDashboardHeader.js.map +1 -1
- package/esm/presentation/dashboardContexts/index.d.ts +1 -1
- package/esm/presentation/dashboardContexts/index.d.ts.map +1 -1
- package/esm/presentation/dashboardContexts/index.js +0 -1
- package/esm/presentation/dashboardContexts/index.js.map +1 -1
- package/esm/presentation/dashboardList/index.d.ts +1 -1
- package/esm/presentation/dashboardList/index.d.ts.map +1 -1
- package/esm/presentation/dashboardList/index.js +0 -2
- package/esm/presentation/dashboardList/index.js.map +1 -1
- package/esm/presentation/export/index.d.ts +1 -1
- package/esm/presentation/export/index.d.ts.map +1 -1
- package/esm/presentation/export/index.js +0 -1
- package/esm/presentation/export/index.js.map +1 -1
- package/esm/presentation/filterBar/attributeFilter/index.d.ts +1 -1
- package/esm/presentation/filterBar/attributeFilter/index.d.ts.map +1 -1
- package/esm/presentation/filterBar/attributeFilter/index.js +1 -2
- package/esm/presentation/filterBar/attributeFilter/index.js.map +1 -1
- package/esm/presentation/filterBar/dateFilter/configuration/DateFilterConfigurationBody.d.ts.map +1 -1
- package/esm/presentation/filterBar/dateFilter/configuration/DateFilterConfigurationBody.js +6 -3
- package/esm/presentation/filterBar/dateFilter/configuration/DateFilterConfigurationBody.js.map +1 -1
- package/esm/presentation/filterBar/dateFilter/index.d.ts +1 -1
- package/esm/presentation/filterBar/dateFilter/index.d.ts.map +1 -1
- package/esm/presentation/filterBar/dateFilter/index.js +1 -2
- package/esm/presentation/filterBar/dateFilter/index.js.map +1 -1
- package/esm/presentation/filterBar/dateFilter/useDateFilterConfig.d.ts.map +1 -1
- package/esm/presentation/filterBar/dateFilter/useDateFilterConfig.js +7 -2
- package/esm/presentation/filterBar/dateFilter/useDateFilterConfig.js.map +1 -1
- package/esm/presentation/filterBar/filterBar/ResetFiltersButton.d.ts.map +1 -1
- package/esm/presentation/filterBar/filterBar/ResetFiltersButton.js +3 -3
- package/esm/presentation/filterBar/filterBar/ResetFiltersButton.js.map +1 -1
- package/esm/presentation/filterBar/filterBar/filterViews/FilterViews.d.ts.map +1 -1
- package/esm/presentation/filterBar/filterBar/filterViews/FilterViews.js +10 -3
- package/esm/presentation/filterBar/filterBar/filterViews/FilterViews.js.map +1 -1
- package/esm/presentation/filterBar/filterBar/index.d.ts +1 -1
- package/esm/presentation/filterBar/filterBar/index.d.ts.map +1 -1
- package/esm/presentation/filterBar/filterBar/index.js +0 -1
- package/esm/presentation/filterBar/filterBar/index.js.map +1 -1
- package/esm/presentation/filterBar/types.d.ts +3 -3
- package/esm/presentation/filterBar/types.d.ts.map +1 -1
- package/esm/presentation/filterBar/types.js +1 -4
- package/esm/presentation/filterBar/types.js.map +1 -1
- package/esm/presentation/flexibleLayout/DashboardLayoutWidget.js +1 -1
- package/esm/presentation/flexibleLayout/DashboardLayoutWidget.js.map +1 -1
- package/esm/presentation/flexibleLayout/DefaultDashboardLayoutRenderer/DashboardLayoutExportSectionHeaderRenderer.d.ts.map +1 -1
- package/esm/presentation/flexibleLayout/DefaultDashboardLayoutRenderer/DashboardLayoutExportSectionHeaderRenderer.js +4 -3
- package/esm/presentation/flexibleLayout/DefaultDashboardLayoutRenderer/DashboardLayoutExportSectionHeaderRenderer.js.map +1 -1
- package/esm/presentation/flexibleLayout/index.d.ts +1 -1
- package/esm/presentation/flexibleLayout/index.d.ts.map +1 -1
- package/esm/presentation/flexibleLayout/index.js +1 -2
- package/esm/presentation/flexibleLayout/index.js.map +1 -1
- package/esm/presentation/index.d.ts +1 -1
- package/esm/presentation/index.d.ts.map +1 -1
- package/esm/presentation/index.js +0 -2
- package/esm/presentation/index.js.map +1 -1
- package/esm/presentation/insightList/index.d.ts +1 -1
- package/esm/presentation/insightList/index.d.ts.map +1 -1
- package/esm/presentation/insightList/index.js +0 -2
- package/esm/presentation/insightList/index.js.map +1 -1
- package/esm/presentation/layout/index.d.ts +1 -1
- package/esm/presentation/layout/index.d.ts.map +1 -1
- package/esm/presentation/layout/index.js +1 -2
- package/esm/presentation/layout/index.js.map +1 -1
- package/esm/presentation/localization/bundles/en-US.json +8 -0
- package/esm/presentation/localization/bundles/en-US.localization-bundle.d.ts +2 -0
- package/esm/presentation/localization/bundles/en-US.localization-bundle.d.ts.map +1 -1
- package/esm/presentation/localization/bundles/en-US.localization-bundle.js +2 -0
- package/esm/presentation/localization/bundles/en-US.localization-bundle.js.map +1 -1
- package/esm/presentation/presentationComponents/DashboardItems/DashboardItem.d.ts.map +1 -1
- package/esm/presentation/presentationComponents/DashboardItems/DashboardItem.js +1 -1
- package/esm/presentation/presentationComponents/DashboardItems/DashboardItem.js.map +1 -1
- package/esm/presentation/saveAs/DefaultSaveAsDialog/SaveAsDialogRenderer.d.ts +2 -19
- package/esm/presentation/saveAs/DefaultSaveAsDialog/SaveAsDialogRenderer.d.ts.map +1 -1
- package/esm/presentation/saveAs/DefaultSaveAsDialog/SaveAsDialogRenderer.js +36 -51
- package/esm/presentation/saveAs/DefaultSaveAsDialog/SaveAsDialogRenderer.js.map +1 -1
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/Attachments/AttachmentsList.d.ts.map +1 -1
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/Attachments/AttachmentsList.js +1 -1
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/Attachments/AttachmentsList.js.map +1 -1
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentFilters.d.ts.map +1 -1
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentFilters.js +3 -1
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentFilters.js.map +1 -1
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/MessageForm/MessageForm.js.map +1 -1
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelectRenderer.d.ts +1 -40
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelectRenderer.d.ts.map +1 -1
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelectRenderer.js +232 -225
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelectRenderer.js.map +1 -1
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/Textarea.d.ts +3 -16
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/Textarea.d.ts.map +1 -1
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/Textarea.js +12 -22
- package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/Textarea.js.map +1 -1
- package/esm/presentation/toolbar/index.d.ts +1 -1
- package/esm/presentation/toolbar/index.d.ts.map +1 -1
- package/esm/presentation/toolbar/index.js +1 -2
- package/esm/presentation/toolbar/index.js.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/cancelButton/index.d.ts +1 -1
- package/esm/presentation/topBar/buttonBar/button/cancelButton/index.d.ts.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/cancelButton/index.js +1 -2
- package/esm/presentation/topBar/buttonBar/button/cancelButton/index.js.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/editButton/index.d.ts +1 -1
- package/esm/presentation/topBar/buttonBar/button/editButton/index.d.ts.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/editButton/index.js +1 -2
- package/esm/presentation/topBar/buttonBar/button/editButton/index.js.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/saveAsButton/index.d.ts +1 -1
- package/esm/presentation/topBar/buttonBar/button/saveAsButton/index.d.ts.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/saveAsButton/index.js +0 -1
- package/esm/presentation/topBar/buttonBar/button/saveAsButton/index.js.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/saveButton/index.d.ts +1 -1
- package/esm/presentation/topBar/buttonBar/button/saveButton/index.d.ts.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/saveButton/index.js +1 -2
- package/esm/presentation/topBar/buttonBar/button/saveButton/index.js.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/settingButton/index.d.ts +1 -1
- package/esm/presentation/topBar/buttonBar/button/settingButton/index.d.ts.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/settingButton/index.js +0 -1
- package/esm/presentation/topBar/buttonBar/button/settingButton/index.js.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/shareButton/index.d.ts +1 -1
- package/esm/presentation/topBar/buttonBar/button/shareButton/index.d.ts.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/shareButton/index.js +1 -2
- package/esm/presentation/topBar/buttonBar/button/shareButton/index.js.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/types.d.ts +6 -6
- package/esm/presentation/topBar/buttonBar/button/types.d.ts.map +1 -1
- package/esm/presentation/topBar/buttonBar/button/types.js +1 -7
- package/esm/presentation/topBar/buttonBar/button/types.js.map +1 -1
- package/esm/presentation/topBar/buttonBar/index.d.ts +1 -1
- package/esm/presentation/topBar/buttonBar/index.d.ts.map +1 -1
- package/esm/presentation/topBar/buttonBar/index.js +1 -2
- package/esm/presentation/topBar/buttonBar/index.js.map +1 -1
- package/esm/presentation/topBar/menuButton/index.d.ts +1 -1
- package/esm/presentation/topBar/menuButton/index.d.ts.map +1 -1
- package/esm/presentation/topBar/menuButton/index.js +1 -2
- package/esm/presentation/topBar/menuButton/index.js.map +1 -1
- package/esm/presentation/topBar/shareIndicators/index.d.ts +2 -2
- package/esm/presentation/topBar/shareIndicators/index.d.ts.map +1 -1
- package/esm/presentation/topBar/shareIndicators/index.js +1 -3
- package/esm/presentation/topBar/shareIndicators/index.js.map +1 -1
- package/esm/presentation/topBar/title/index.d.ts +1 -1
- package/esm/presentation/topBar/title/index.d.ts.map +1 -1
- package/esm/presentation/topBar/title/index.js +1 -2
- package/esm/presentation/topBar/title/index.js.map +1 -1
- package/esm/presentation/topBar/topBar/index.d.ts +1 -1
- package/esm/presentation/topBar/topBar/index.d.ts.map +1 -1
- package/esm/presentation/topBar/topBar/index.js +0 -1
- package/esm/presentation/topBar/topBar/index.js.map +1 -1
- package/esm/presentation/topBar/types.d.ts +5 -5
- package/esm/presentation/topBar/types.d.ts.map +1 -1
- package/esm/presentation/topBar/types.js +1 -6
- package/esm/presentation/topBar/types.js.map +1 -1
- package/esm/presentation/types.d.ts +8 -8
- package/esm/presentation/types.d.ts.map +1 -1
- package/esm/presentation/types.js +1 -9
- package/esm/presentation/types.js.map +1 -1
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useInsightWidgetAlerting.js +1 -1
- package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useInsightWidgetAlerting.js.map +1 -1
- package/esm/presentation/widget/insight/configuration/InsightAlertsNew.js +1 -1
- package/esm/presentation/widget/insight/configuration/InsightAlertsNew.js.map +1 -1
- package/esm/presentation/widget/insight/configuration/InsightDrillConfigPanel/useInsightDrillConfigPanel.d.ts.map +1 -1
- package/esm/presentation/widget/insight/configuration/InsightDrillConfigPanel/useInsightDrillConfigPanel.js +7 -4
- package/esm/presentation/widget/insight/configuration/InsightDrillConfigPanel/useInsightDrillConfigPanel.js.map +1 -1
- package/esm/presentation/widget/insight/insightToTable.js +1 -1
- package/esm/presentation/widget/insight/insightToTable.js.map +1 -1
- package/esm/presentation/widget/widget/DashboardNestedLayoutWidget/Toolbar.d.ts.map +1 -1
- package/esm/presentation/widget/widget/DashboardNestedLayoutWidget/Toolbar.js +6 -3
- package/esm/presentation/widget/widget/DashboardNestedLayoutWidget/Toolbar.js.map +1 -1
- package/esm/sdk-ui-dashboard.d.ts +6 -0
- package/package.json +20 -20
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// (C) 2019-2025 GoodData Corporation
|
|
2
2
|
/* eslint-disable import/named,import/namespace */
|
|
3
3
|
import { isAutomationUserRecipient, } from "@gooddata/sdk-model";
|
|
4
|
-
import React from "react";
|
|
4
|
+
import React, { memo, useRef, useState, useEffect, useCallback, useMemo } from "react";
|
|
5
5
|
import { FormattedMessage, useIntl } from "react-intl";
|
|
6
6
|
import ReactSelect, { components as ReactSelectComponents, } from "react-select";
|
|
7
7
|
import debounce from "lodash/debounce.js";
|
|
@@ -31,39 +31,45 @@ const TOOLTIP_ALIGN_POINTS = [
|
|
|
31
31
|
offset: { x: 0, y: -2 },
|
|
32
32
|
},
|
|
33
33
|
];
|
|
34
|
-
export
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
export const RecipientsSelectRenderer = memo(function RecipientsSelectRenderer(props) {
|
|
35
|
+
const { isMulti, options, value, maxRecipients, className, usersError, allowOnlyLoggedUserRecipients, id, externalRecipientOverride, allowExternalRecipients, loggedUser, notificationChannel, showLabel, onChange, onLoad, isLoading, canListUsersInProject, allowEmptySelection, onKeyDownSubmit, } = props;
|
|
36
|
+
const [state, setState] = useState({
|
|
37
|
+
menuOpen: false,
|
|
38
|
+
minRecipientsError: false,
|
|
39
|
+
focusedRecipientIndex: -1,
|
|
40
|
+
});
|
|
41
|
+
const recipientRef = useRef(null);
|
|
42
|
+
const intl = useIntl();
|
|
43
|
+
const keyboardRecipientNavigationHandler = makeKeyboardNavigation({
|
|
44
|
+
onFocusPrevious: [{ code: ["ArrowLeft"] }],
|
|
45
|
+
onFocusNext: [{ code: ["ArrowRight"] }],
|
|
46
|
+
onSubmit: [{ code: ["Enter"] }],
|
|
47
|
+
onRecipientRemove: [{ code: ["Delete", "Backspace", "Enter"] }],
|
|
48
|
+
});
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
const { current } = recipientRef;
|
|
46
51
|
if (!current) {
|
|
47
52
|
return;
|
|
48
53
|
}
|
|
49
54
|
// update owner component style after recipient rendered
|
|
50
55
|
const ownerContainer = current.querySelector(".gd-owner-user");
|
|
51
|
-
const style =
|
|
56
|
+
const style = getStyle();
|
|
52
57
|
if (ownerContainer && style) {
|
|
53
58
|
ownerContainer.setAttribute("style", `max-width: ${style.maxWidth}px`);
|
|
54
59
|
}
|
|
55
|
-
}
|
|
56
|
-
keyboardRecipientNavigationHandler = makeKeyboardNavigation({
|
|
57
|
-
onFocusPrevious: [{ code: ["ArrowLeft"] }],
|
|
58
|
-
onFocusNext: [{ code: ["ArrowRight"] }],
|
|
59
|
-
onSubmit: [{ code: ["Enter"] }],
|
|
60
|
-
onRecipientRemove: [{ code: ["Delete", "Backspace", "Enter"] }],
|
|
61
60
|
});
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
const isEmailChannel = useCallback(() => {
|
|
62
|
+
return notificationChannel?.destinationType === "smtp";
|
|
63
|
+
}, [notificationChannel]);
|
|
64
|
+
const getHasEmail = useCallback((recipient) => {
|
|
65
|
+
return isEmailChannel() && isAutomationUserRecipient(recipient)
|
|
66
|
+
? isEmail(recipient.email ?? "")
|
|
67
|
+
: true;
|
|
68
|
+
}, [isEmailChannel]);
|
|
69
|
+
const evaluateErrors = useCallback(() => {
|
|
64
70
|
const maxRecipientsError = maxRecipients !== undefined && value.length > maxRecipients;
|
|
65
|
-
const minRecipientsError =
|
|
66
|
-
const someRecipientsMissingEmail =
|
|
71
|
+
const minRecipientsError = state.minRecipientsError;
|
|
72
|
+
const someRecipientsMissingEmail = isEmailChannel()
|
|
67
73
|
? value.some((v) => (isAutomationUserRecipient(v) ? !isEmail(v.email ?? "") : false))
|
|
68
74
|
: false;
|
|
69
75
|
const invalidExternalRecipients = value.filter((v) => v.type === "externalUser");
|
|
@@ -75,7 +81,7 @@ export class RecipientsSelectRenderer extends React.PureComponent {
|
|
|
75
81
|
.join(", ");
|
|
76
82
|
const authorOnlyError = allowOnlyLoggedUserRecipients &&
|
|
77
83
|
((value.length === 1 && value[0].id !== loggedUser?.id) || value.length > 1);
|
|
78
|
-
const missingEmailRecipients = value.filter((v) =>
|
|
84
|
+
const missingEmailRecipients = value.filter((v) => !getHasEmail(v));
|
|
79
85
|
const missingEmailRecipientsValues = missingEmailRecipients.map((v) => v.name ?? v.id).join(", ");
|
|
80
86
|
const missingEmailError = !!missingEmailRecipients.length;
|
|
81
87
|
return {
|
|
@@ -89,58 +95,17 @@ export class RecipientsSelectRenderer extends React.PureComponent {
|
|
|
89
95
|
missingEmailRecipientsValues,
|
|
90
96
|
someRecipientsMissingEmail,
|
|
91
97
|
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
NoOptionsMessage: this.renderNoOptionsContainer,
|
|
104
|
-
MultiValueRemove: this.renderMultiValueRemove,
|
|
105
|
-
};
|
|
106
|
-
const { maxRecipientsError, minRecipientsError, invalidExternalError, invalidUnknownError, someRecipientsMissingEmail, authorOnlyError, missingEmailError, invalidRecipientsValues, missingEmailRecipientsValues, } = this.evaluateErrors();
|
|
107
|
-
const showInputError = maxRecipientsError ||
|
|
108
|
-
minRecipientsError ||
|
|
109
|
-
invalidExternalError ||
|
|
110
|
-
invalidUnknownError ||
|
|
111
|
-
someRecipientsMissingEmail ||
|
|
112
|
-
!!usersError ||
|
|
113
|
-
authorOnlyError ||
|
|
114
|
-
missingEmailError;
|
|
115
|
-
const someExternalRecipients = value.some((v) => v.type === "externalUser");
|
|
116
|
-
const renderExternalRecipientsNote = someExternalRecipients && !externalRecipientOverride;
|
|
117
|
-
return (React.createElement("div", { className: cx("gd-input-component gd-recipients-field s-gd-notifications-channels-dialog-recipients", className) },
|
|
118
|
-
this.props.showLabel ? (React.createElement("label", { htmlFor: id, className: "gd-label" },
|
|
119
|
-
React.createElement(FormattedMessage, { id: "dialogs.schedule.email.recipients.label" }))) : null,
|
|
120
|
-
React.createElement("div", { ref: this.recipientRef, className: "gd-input s-gd-recipients-value" },
|
|
121
|
-
React.createElement(ReactSelect, { tabSelectsValue: false, id: id, className: cx("gd-recipients-container", {
|
|
122
|
-
"gd-input-component--invalid": showInputError,
|
|
123
|
-
}), classNamePrefix: "gd-recipients", components: creatableSelectComponent, formatOptionLabel: this.renderOptionLabel, filterOption: (opt, value) => {
|
|
124
|
-
return matchRecipient(opt.data, value);
|
|
125
|
-
}, isClearable: false, isDisabled: !isMulti, isMulti: isMulti, onChange:
|
|
126
|
-
// using as any as it would be too tricky to type properly
|
|
127
|
-
this.handleOnChange, onInputChange: this.onSearch, onMenuOpen: this.onMenuOpen, onMenuClose: () => this.setState({ menuOpen: false }), onKeyDown: this.handleKeyDown, options: options, onBlur: this.onBlur, value: value, getOptionValue: (o) => o.id, getOptionLabel: (o) => o.name ?? o.id, "aria-describedby": showInputError ? "gd-recipients-field-error" : undefined, "aria-invalid": showInputError }),
|
|
128
|
-
showInputError ? (this.renderInputError({
|
|
129
|
-
authorOnlyError,
|
|
130
|
-
invalidExternalError,
|
|
131
|
-
invalidUnknownError,
|
|
132
|
-
maxRecipientsError,
|
|
133
|
-
minRecipientsError,
|
|
134
|
-
missingEmailError,
|
|
135
|
-
invalidRecipientsValues,
|
|
136
|
-
missingEmailRecipientsValues,
|
|
137
|
-
maxRecipients,
|
|
138
|
-
usersError,
|
|
139
|
-
})) : renderExternalRecipientsNote ? (React.createElement("div", { className: "gd-recipients-field-note" },
|
|
140
|
-
React.createElement(FormattedMessage, { id: "dialogs.schedule.email.recipients.note" }))) : allowOnlyLoggedUserRecipients ? (React.createElement("div", { className: "gd-recipients-field-note" },
|
|
141
|
-
React.createElement(FormattedMessage, { id: "dialogs.schedule.email.destinationWarning" }))) : null)));
|
|
142
|
-
}
|
|
143
|
-
renderInputError = ({ authorOnlyError, invalidExternalError, invalidUnknownError, maxRecipientsError, minRecipientsError, missingEmailError, invalidRecipientsValues, missingEmailRecipientsValues, maxRecipients, usersError, }) => {
|
|
98
|
+
}, [
|
|
99
|
+
maxRecipients,
|
|
100
|
+
value,
|
|
101
|
+
state.minRecipientsError,
|
|
102
|
+
isEmailChannel,
|
|
103
|
+
allowExternalRecipients,
|
|
104
|
+
allowOnlyLoggedUserRecipients,
|
|
105
|
+
loggedUser?.id,
|
|
106
|
+
getHasEmail,
|
|
107
|
+
]);
|
|
108
|
+
const renderInputError = useCallback(({ authorOnlyError, invalidExternalError, invalidUnknownError, maxRecipientsError, minRecipientsError, missingEmailError, invalidRecipientsValues, missingEmailRecipientsValues, maxRecipients, usersError, }) => {
|
|
144
109
|
return (React.createElement("div", { id: "gd-recipients-field-error", className: "gd-recipients-field-error" },
|
|
145
110
|
authorOnlyError ? (React.createElement("div", { className: "gd-recipients-field-error-item" },
|
|
146
111
|
React.createElement(FormattedMessage, { id: "dialogs.schedule.email.user.invalid.onlyYou" }))) : null,
|
|
@@ -154,31 +119,26 @@ export class RecipientsSelectRenderer extends React.PureComponent {
|
|
|
154
119
|
React.createElement(FormattedMessage, { id: "dialogs.schedule.email.user.missing.email", values: { recipients: missingEmailRecipientsValues } }))) : null,
|
|
155
120
|
usersError ? (React.createElement("div", { className: "gd-recipients-field-error-item" },
|
|
156
121
|
React.createElement(FormattedMessage, { id: "dialogs.schedule.email.usersLoad.error" }))) : null));
|
|
157
|
-
};
|
|
158
|
-
renderEmptyContainer = () => {
|
|
122
|
+
}, []);
|
|
123
|
+
const renderEmptyContainer = useCallback(() => {
|
|
159
124
|
return null;
|
|
160
|
-
};
|
|
161
|
-
getStyle() {
|
|
162
|
-
const { current } =
|
|
125
|
+
}, []);
|
|
126
|
+
const getStyle = useCallback(() => {
|
|
127
|
+
const { current } = recipientRef;
|
|
163
128
|
const { width } = (!isEmpty(current) && current.getBoundingClientRect()) || { width: undefined };
|
|
164
129
|
return {
|
|
165
130
|
maxWidth: width ? width - PADDING : "100%",
|
|
166
131
|
width,
|
|
167
132
|
};
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return notificationChannel?.destinationType === "smtp";
|
|
172
|
-
}
|
|
173
|
-
renderNoOptionsContainer = () => {
|
|
174
|
-
if (this.props.externalRecipientOverride) {
|
|
133
|
+
}, []);
|
|
134
|
+
const renderNoOptionsContainer = useCallback(() => {
|
|
135
|
+
if (externalRecipientOverride) {
|
|
175
136
|
return null;
|
|
176
137
|
}
|
|
177
138
|
return (React.createElement("div", { className: "gd-recipients-no-match" },
|
|
178
139
|
React.createElement(FormattedMessage, { id: "dialogs.schedule.email.user.noMatch" })));
|
|
179
|
-
};
|
|
180
|
-
renderMultiValueRemove = (props) => {
|
|
181
|
-
const intl = useIntl();
|
|
140
|
+
}, [externalRecipientOverride]);
|
|
141
|
+
const renderMultiValueRemove = useCallback((props) => {
|
|
182
142
|
const modifiedProps = {
|
|
183
143
|
...props,
|
|
184
144
|
innerProps: {
|
|
@@ -187,43 +147,42 @@ export class RecipientsSelectRenderer extends React.PureComponent {
|
|
|
187
147
|
},
|
|
188
148
|
};
|
|
189
149
|
return React.createElement(MultiValueRemove, { ...modifiedProps });
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
|
|
150
|
+
}, [intl]);
|
|
151
|
+
const renderLoadingIcon = useCallback((menuProps) => {
|
|
152
|
+
return (React.createElement(OverlayControllerProvider, { overlayController: overlayController },
|
|
153
|
+
React.createElement(Menu, { className: "s-gd-recipients-menu-container", ...menuProps },
|
|
154
|
+
React.createElement(LoadingMask, { height: LOADING_MENU_HEIGHT }))));
|
|
155
|
+
}, []);
|
|
156
|
+
const renderMenuOptionsContainer = useCallback((menuProps) => {
|
|
157
|
+
const style = getStyle();
|
|
158
|
+
return (React.createElement(OverlayControllerProvider, { overlayController: overlayController },
|
|
159
|
+
React.createElement(Overlay, { alignTo: ".gd-recipients-container", alignPoints: [{ align: "bc tc" }] },
|
|
160
|
+
React.createElement("div", { className: "gd-recipients-overlay", style: { width: style.width } },
|
|
161
|
+
React.createElement(Menu, { className: "s-gd-recipients-menu-container", ...menuProps }, menuProps.children)))));
|
|
162
|
+
}, [getStyle]);
|
|
163
|
+
const renderMenuOptions = useCallback((menuProps) => {
|
|
193
164
|
const { getValue, selectProps: { inputValue }, } = menuProps;
|
|
194
165
|
const selectedValues = getValue() || [];
|
|
195
166
|
const selectedItemsCount = selectedValues.length;
|
|
196
167
|
const areAllValuesSelected = false;
|
|
197
168
|
if (isLoading) {
|
|
198
|
-
return
|
|
169
|
+
return renderLoadingIcon(menuProps);
|
|
199
170
|
}
|
|
200
171
|
if (!inputValue && (selectedItemsCount >= MAXIMUM_RECIPIENTS_RECEIVE || areAllValuesSelected)) {
|
|
201
|
-
return
|
|
172
|
+
return renderEmptyContainer();
|
|
202
173
|
}
|
|
203
|
-
return
|
|
204
|
-
};
|
|
205
|
-
renderMenuList = (menuListProps) => {
|
|
174
|
+
return renderMenuOptionsContainer(menuProps);
|
|
175
|
+
}, [isLoading, renderEmptyContainer, renderLoadingIcon, renderMenuOptionsContainer]);
|
|
176
|
+
const renderMenuList = useCallback((menuListProps) => {
|
|
206
177
|
const modifiedInnerProps = {
|
|
207
178
|
...menuListProps.innerProps,
|
|
208
179
|
id: MENU_LIST_ID,
|
|
209
180
|
};
|
|
210
181
|
return React.createElement(MenuList, { ...menuListProps, innerProps: modifiedInnerProps });
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
const style =
|
|
214
|
-
|
|
215
|
-
React.createElement(Overlay, { alignTo: ".gd-recipients-container", alignPoints: [{ align: "bc tc" }] },
|
|
216
|
-
React.createElement("div", { className: "gd-recipients-overlay", style: { width: style.width } },
|
|
217
|
-
React.createElement(Menu, { className: "s-gd-recipients-menu-container", ...menuProps }, menuProps.children)))));
|
|
218
|
-
};
|
|
219
|
-
renderLoadingIcon = (menuProps) => {
|
|
220
|
-
return (React.createElement(OverlayControllerProvider, { overlayController: overlayController },
|
|
221
|
-
React.createElement(Menu, { className: "s-gd-recipients-menu-container", ...menuProps },
|
|
222
|
-
React.createElement(LoadingMask, { height: LOADING_MENU_HEIGHT }))));
|
|
223
|
-
};
|
|
224
|
-
renderMultiValueItemContainer = (label, removeIcon, recipientIndex, options = {}) => {
|
|
225
|
-
const style = this.getStyle();
|
|
226
|
-
const { focusedRecipientIndex } = this.state;
|
|
182
|
+
}, []);
|
|
183
|
+
const renderMultiValueItemContainer = useCallback((label, removeIcon, recipientIndex, options = {}) => {
|
|
184
|
+
const style = getStyle();
|
|
185
|
+
const { focusedRecipientIndex } = state;
|
|
227
186
|
const render = () => {
|
|
228
187
|
const showErrorIcon = options.noExternal ||
|
|
229
188
|
options.invalidExternal ||
|
|
@@ -279,25 +238,19 @@ export class RecipientsSelectRenderer extends React.PureComponent {
|
|
|
279
238
|
React.createElement(Bubble, { className: "bubble-primary", alignPoints: TOOLTIP_ALIGN_POINTS }, options.email)));
|
|
280
239
|
}
|
|
281
240
|
return render();
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
return this.isEmailChannel() && isAutomationUserRecipient(recipient)
|
|
285
|
-
? isEmail(recipient.email ?? "")
|
|
286
|
-
: true;
|
|
287
|
-
};
|
|
288
|
-
renderMultiValueContainer = (multiValueProps) => {
|
|
289
|
-
const { allowExternalRecipients, allowOnlyLoggedUserRecipients, loggedUser, value } = this.props;
|
|
241
|
+
}, [getStyle, state]);
|
|
242
|
+
const renderMultiValueContainer = useCallback((multiValueProps) => {
|
|
290
243
|
const { data, children } = multiValueProps;
|
|
291
244
|
// MultiValueRemove component from react-select
|
|
292
245
|
const removeIcon = children[1];
|
|
293
246
|
const name = data.name ?? data.id;
|
|
294
|
-
const hasEmail =
|
|
247
|
+
const hasEmail = getHasEmail(data);
|
|
295
248
|
const noExternal = data.type === "externalUser" && !allowExternalRecipients;
|
|
296
249
|
const invalidExternal = data.type === "unknownUser";
|
|
297
250
|
const invalidLoggedUser = allowOnlyLoggedUserRecipients ? data.id !== loggedUser?.id : false;
|
|
298
251
|
// Find the index of this recipient in the value array
|
|
299
252
|
const recipientIndex = value.findIndex((recipient) => recipient.id === data.id);
|
|
300
|
-
return
|
|
253
|
+
return renderMultiValueItemContainer(name, removeIcon, recipientIndex, {
|
|
301
254
|
hasEmail,
|
|
302
255
|
noExternal,
|
|
303
256
|
invalidLoggedUser,
|
|
@@ -305,18 +258,31 @@ export class RecipientsSelectRenderer extends React.PureComponent {
|
|
|
305
258
|
type: data.type,
|
|
306
259
|
email: data.email,
|
|
307
260
|
});
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
|
|
261
|
+
}, [
|
|
262
|
+
allowExternalRecipients,
|
|
263
|
+
allowOnlyLoggedUserRecipients,
|
|
264
|
+
loggedUser,
|
|
265
|
+
value,
|
|
266
|
+
getHasEmail,
|
|
267
|
+
renderMultiValueItemContainer,
|
|
268
|
+
]);
|
|
269
|
+
const renderRecipientValue = useCallback((recipient) => {
|
|
270
|
+
const email = isAutomationUserRecipient(recipient) ? (recipient.email ?? "") : "";
|
|
271
|
+
if (isEmail(email)) {
|
|
272
|
+
return (React.createElement("span", { className: "gd-recipient-option-value-item s-gd-recipient-option-value-item" }, email));
|
|
273
|
+
}
|
|
274
|
+
return renderEmptyContainer();
|
|
275
|
+
}, [renderEmptyContainer]);
|
|
276
|
+
const renderOptionLabel = useCallback((recipient) => {
|
|
311
277
|
const displayName = recipient.name ?? recipient.id;
|
|
312
278
|
const email = isAutomationUserRecipient(recipient) ? (recipient.email ?? "") : "";
|
|
313
|
-
const
|
|
279
|
+
const renderValue = renderRecipientValue(recipient);
|
|
314
280
|
return (React.createElement(BubbleHoverTrigger, null,
|
|
315
281
|
React.createElement("div", { className: "gd-recipient-option-item s-gd-recipient-option-item" },
|
|
316
282
|
React.createElement("span", { className: "gd-recipient-option-label-item s-gd-recipient-option-label-item" }, displayName),
|
|
317
283
|
allowExternalRecipients && recipient.type === "externalUser" ? (React.createElement("span", { className: "gd-recipient-quest" },
|
|
318
284
|
"\u00A0",
|
|
319
|
-
React.createElement(FormattedMessage, { id: "dialogs.schedule.email.user.guest" }))) : (
|
|
285
|
+
React.createElement(FormattedMessage, { id: "dialogs.schedule.email.user.guest" }))) : (renderValue),
|
|
320
286
|
!externalRecipientOverride &&
|
|
321
287
|
allowExternalRecipients &&
|
|
322
288
|
recipient.type === "externalUser" ? (React.createElement("div", { className: "gd-recipient-option-label-external-warning" },
|
|
@@ -326,114 +292,52 @@ export class RecipientsSelectRenderer extends React.PureComponent {
|
|
|
326
292
|
displayName,
|
|
327
293
|
" ",
|
|
328
294
|
isEmail(email) ? `(${email})` : "")));
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
const email = isAutomationUserRecipient(recipient) ? (recipient.email ?? "") : "";
|
|
332
|
-
if (isEmail(email)) {
|
|
333
|
-
return (React.createElement("span", { className: "gd-recipient-option-value-item s-gd-recipient-option-value-item" }, email));
|
|
334
|
-
}
|
|
335
|
-
return this.renderEmptyContainer();
|
|
336
|
-
};
|
|
337
|
-
renderInputContainer = (inputProps) => {
|
|
338
|
-
const { isMulti } = this.props;
|
|
295
|
+
}, [allowExternalRecipients, externalRecipientOverride, renderRecipientValue]);
|
|
296
|
+
const renderInputContainer = useCallback((inputProps) => {
|
|
339
297
|
if (!isMulti) {
|
|
340
|
-
return
|
|
298
|
+
return renderEmptyContainer();
|
|
341
299
|
}
|
|
342
300
|
const props = {
|
|
343
301
|
...inputProps,
|
|
344
|
-
id:
|
|
302
|
+
id: id,
|
|
345
303
|
"aria-controls": MENU_LIST_ID,
|
|
346
304
|
};
|
|
347
305
|
return (React.createElement("div", { className: "gd-recipient-input s-gd-recipient-input" },
|
|
348
306
|
React.createElement(Input, { ...props })));
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
if (isEscapeKey(e)) {
|
|
353
|
-
e.stopPropagation();
|
|
354
|
-
}
|
|
355
|
-
if (!menuOpen) {
|
|
356
|
-
this.handleKeyboardNavigation(e);
|
|
357
|
-
}
|
|
358
|
-
};
|
|
359
|
-
handleOnChange = (selectedValues, actionTypes) => {
|
|
360
|
-
const newSelectedValues = selectedValues;
|
|
361
|
-
const { value, allowEmptySelection } = this.props;
|
|
362
|
-
const { action } = actionTypes;
|
|
363
|
-
if (value.length >= MAXIMUM_RECIPIENTS_RECEIVE &&
|
|
364
|
-
(action === CREATE_OPTION || action === SELECT_OPTION)) {
|
|
365
|
-
this.props.onChange?.(value);
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
if (newSelectedValues?.length === 0) {
|
|
369
|
-
if (allowEmptySelection) {
|
|
370
|
-
this.props.onChange?.([]);
|
|
371
|
-
//this.setState({ minRecipientsError: true });
|
|
372
|
-
}
|
|
373
|
-
else {
|
|
374
|
-
this.props.onChange?.([value[0]]);
|
|
375
|
-
}
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
else {
|
|
379
|
-
this.setState({ minRecipientsError: false });
|
|
380
|
-
}
|
|
381
|
-
this.props.onChange?.(newSelectedValues);
|
|
382
|
-
};
|
|
383
|
-
onBlur = () => {
|
|
384
|
-
const { value, allowEmptySelection } = this.props;
|
|
385
|
-
if (allowEmptySelection && value.length === 0) {
|
|
386
|
-
this.setState({ minRecipientsError: true });
|
|
387
|
-
}
|
|
388
|
-
};
|
|
389
|
-
loadUserListItems = (searchString) => {
|
|
390
|
-
const { value, canListUsersInProject, onLoad } = this.props;
|
|
391
|
-
const isRecipientAdded = this.isRecipientAdded(value, searchString);
|
|
392
|
-
if (!canListUsersInProject || isRecipientAdded) {
|
|
307
|
+
}, [isMulti, id, renderEmptyContainer]);
|
|
308
|
+
const handleKeyboardRecipientRemove = useCallback((index) => {
|
|
309
|
+
if (index < 0 || index >= value.length) {
|
|
393
310
|
return;
|
|
394
311
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
onLoad?.();
|
|
403
|
-
}
|
|
404
|
-
};
|
|
405
|
-
onSearchCore = (searchString) => {
|
|
406
|
-
this.loadUserListItems(searchString);
|
|
407
|
-
};
|
|
408
|
-
onSearch = debounce(this.onSearchCore, DELAY_TIME);
|
|
409
|
-
isRecipientAdded = (value, searchKey) => {
|
|
410
|
-
return value.some((recipient) => isEqual(recipient.id, searchKey));
|
|
411
|
-
};
|
|
412
|
-
handleKeyboardNavigation = (e) => {
|
|
413
|
-
const { focusedRecipientIndex } = this.state;
|
|
414
|
-
const { value, onKeyDownSubmit, onChange } = this.props;
|
|
312
|
+
const newValues = value.filter((_, i) => i !== index);
|
|
313
|
+
onChange?.(newValues);
|
|
314
|
+
const newFocusIndex = newValues.length === 0 ? -1 : Math.min(index, newValues.length - 1);
|
|
315
|
+
setState((prev) => ({ ...prev, focusedRecipientIndex: newFocusIndex }));
|
|
316
|
+
}, [value, onChange]);
|
|
317
|
+
const handleKeyboardNavigation = useCallback((e) => {
|
|
318
|
+
const { focusedRecipientIndex } = state;
|
|
415
319
|
const totalRecipients = value.length;
|
|
416
|
-
const keyboardHandler =
|
|
320
|
+
const keyboardHandler = keyboardRecipientNavigationHandler({
|
|
417
321
|
onFocusPrevious: () => {
|
|
418
322
|
if (focusedRecipientIndex === -1 && totalRecipients > 0) {
|
|
419
323
|
const lastIndex = totalRecipients - 1;
|
|
420
|
-
|
|
324
|
+
setState((prev) => ({ ...prev, focusedRecipientIndex: lastIndex }));
|
|
421
325
|
}
|
|
422
326
|
else if (focusedRecipientIndex > 0) {
|
|
423
327
|
const prevIndex = focusedRecipientIndex - 1;
|
|
424
|
-
|
|
328
|
+
setState((prev) => ({ ...prev, focusedRecipientIndex: prevIndex }));
|
|
425
329
|
}
|
|
426
330
|
else {
|
|
427
|
-
|
|
331
|
+
setState((prev) => ({ ...prev, focusedRecipientIndex: -1 }));
|
|
428
332
|
}
|
|
429
333
|
},
|
|
430
334
|
onFocusNext: () => {
|
|
431
335
|
if (focusedRecipientIndex < totalRecipients - 1) {
|
|
432
336
|
const nextIndex = focusedRecipientIndex + 1;
|
|
433
|
-
|
|
337
|
+
setState((prev) => ({ ...prev, focusedRecipientIndex: nextIndex }));
|
|
434
338
|
}
|
|
435
339
|
else if (focusedRecipientIndex === totalRecipients - 1) {
|
|
436
|
-
|
|
340
|
+
setState((prev) => ({ ...prev, focusedRecipientIndex: -1 }));
|
|
437
341
|
}
|
|
438
342
|
},
|
|
439
343
|
onSubmit: () => {
|
|
@@ -441,7 +345,7 @@ export class RecipientsSelectRenderer extends React.PureComponent {
|
|
|
441
345
|
onKeyDownSubmit?.(e);
|
|
442
346
|
}
|
|
443
347
|
else {
|
|
444
|
-
|
|
348
|
+
handleKeyboardRecipientRemove(focusedRecipientIndex);
|
|
445
349
|
}
|
|
446
350
|
},
|
|
447
351
|
onRecipientRemove: () => {
|
|
@@ -450,24 +354,127 @@ export class RecipientsSelectRenderer extends React.PureComponent {
|
|
|
450
354
|
onChange?.(newValues);
|
|
451
355
|
}
|
|
452
356
|
if (focusedRecipientIndex !== -1) {
|
|
453
|
-
|
|
357
|
+
handleKeyboardRecipientRemove(focusedRecipientIndex);
|
|
454
358
|
}
|
|
455
359
|
},
|
|
456
360
|
onUnhandledKeyDown: () => {
|
|
457
|
-
|
|
361
|
+
setState((prev) => ({ ...prev, focusedRecipientIndex: -1 }));
|
|
458
362
|
},
|
|
459
363
|
});
|
|
460
364
|
keyboardHandler(e);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
365
|
+
}, [
|
|
366
|
+
state,
|
|
367
|
+
value,
|
|
368
|
+
keyboardRecipientNavigationHandler,
|
|
369
|
+
onKeyDownSubmit,
|
|
370
|
+
handleKeyboardRecipientRemove,
|
|
371
|
+
onChange,
|
|
372
|
+
]);
|
|
373
|
+
const handleKeyDown = useCallback((e) => {
|
|
374
|
+
const { menuOpen } = state;
|
|
375
|
+
if (isEscapeKey(e)) {
|
|
376
|
+
e.stopPropagation();
|
|
377
|
+
}
|
|
378
|
+
if (!menuOpen) {
|
|
379
|
+
handleKeyboardNavigation(e);
|
|
380
|
+
}
|
|
381
|
+
}, [handleKeyboardNavigation, state]);
|
|
382
|
+
const handleOnChange = useCallback((selectedValues, actionTypes) => {
|
|
383
|
+
const newSelectedValues = selectedValues;
|
|
384
|
+
const { action } = actionTypes;
|
|
385
|
+
if (value.length >= MAXIMUM_RECIPIENTS_RECEIVE &&
|
|
386
|
+
(action === CREATE_OPTION || action === SELECT_OPTION)) {
|
|
387
|
+
onChange?.(value);
|
|
465
388
|
return;
|
|
466
389
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
390
|
+
if (newSelectedValues?.length === 0) {
|
|
391
|
+
if (allowEmptySelection) {
|
|
392
|
+
onChange?.([]);
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
onChange?.([value[0]]);
|
|
396
|
+
}
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
setState((prev) => ({ ...prev, minRecipientsError: false }));
|
|
401
|
+
}
|
|
402
|
+
onChange?.(newSelectedValues);
|
|
403
|
+
}, [value, allowEmptySelection, onChange]);
|
|
404
|
+
const onBlur = useCallback(() => {
|
|
405
|
+
if (allowEmptySelection && value.length === 0) {
|
|
406
|
+
setState((prev) => ({ ...prev, minRecipientsError: true }));
|
|
407
|
+
}
|
|
408
|
+
}, [allowEmptySelection, value.length]);
|
|
409
|
+
const isRecipientAddedFn = useCallback((value, searchKey) => {
|
|
410
|
+
return value.some((recipient) => isEqual(recipient.id, searchKey));
|
|
411
|
+
}, []);
|
|
412
|
+
const loadUserListItems = useCallback((searchString) => {
|
|
413
|
+
const isRecipientAdded = isRecipientAddedFn(value, searchString);
|
|
414
|
+
if (!canListUsersInProject || isRecipientAdded) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
onLoad?.({ search: searchString });
|
|
418
|
+
}, [isRecipientAddedFn, value, canListUsersInProject, onLoad]);
|
|
419
|
+
const onMenuOpen = useCallback(() => {
|
|
420
|
+
const userListCount = options.length;
|
|
421
|
+
setState((prev) => ({ ...prev, menuOpen: true, focusedRecipientIndex: -1 }));
|
|
422
|
+
if (!userListCount && canListUsersInProject) {
|
|
423
|
+
onLoad?.();
|
|
424
|
+
}
|
|
425
|
+
}, [options.length, canListUsersInProject, onLoad]);
|
|
426
|
+
const onSearchCore = useCallback((searchString) => {
|
|
427
|
+
loadUserListItems(searchString);
|
|
428
|
+
}, [loadUserListItems]);
|
|
429
|
+
const onSearch = useMemo(() => debounce((searchString) => {
|
|
430
|
+
onSearchCore(searchString);
|
|
431
|
+
}, DELAY_TIME), [onSearchCore]);
|
|
432
|
+
const creatableSelectComponent = {
|
|
433
|
+
...ReactSelectComponents,
|
|
434
|
+
IndicatorsContainer: renderEmptyContainer,
|
|
435
|
+
Input: renderInputContainer,
|
|
436
|
+
MultiValueContainer: renderMultiValueContainer,
|
|
437
|
+
Menu: renderMenuOptions,
|
|
438
|
+
MenuList: renderMenuList,
|
|
439
|
+
Placeholder: renderEmptyContainer,
|
|
440
|
+
NoOptionsMessage: renderNoOptionsContainer,
|
|
441
|
+
MultiValueRemove: renderMultiValueRemove,
|
|
471
442
|
};
|
|
472
|
-
}
|
|
443
|
+
const { maxRecipientsError, minRecipientsError, invalidExternalError, invalidUnknownError, someRecipientsMissingEmail, authorOnlyError, missingEmailError, invalidRecipientsValues, missingEmailRecipientsValues, } = evaluateErrors();
|
|
444
|
+
const showInputError = maxRecipientsError ||
|
|
445
|
+
minRecipientsError ||
|
|
446
|
+
invalidExternalError ||
|
|
447
|
+
invalidUnknownError ||
|
|
448
|
+
someRecipientsMissingEmail ||
|
|
449
|
+
!!usersError ||
|
|
450
|
+
authorOnlyError ||
|
|
451
|
+
missingEmailError;
|
|
452
|
+
const someExternalRecipients = value.some((v) => v.type === "externalUser");
|
|
453
|
+
const renderExternalRecipientsNote = someExternalRecipients && !externalRecipientOverride;
|
|
454
|
+
return (React.createElement("div", { className: cx("gd-input-component gd-recipients-field s-gd-notifications-channels-dialog-recipients", className) },
|
|
455
|
+
showLabel ? (React.createElement("label", { htmlFor: id, className: "gd-label" },
|
|
456
|
+
React.createElement(FormattedMessage, { id: "dialogs.schedule.email.recipients.label" }))) : null,
|
|
457
|
+
React.createElement("div", { ref: recipientRef, className: "gd-input s-gd-recipients-value" },
|
|
458
|
+
React.createElement(ReactSelect, { tabSelectsValue: false, id: id, className: cx("gd-recipients-container", {
|
|
459
|
+
"gd-input-component--invalid": showInputError,
|
|
460
|
+
}), classNamePrefix: "gd-recipients", components: creatableSelectComponent, formatOptionLabel: renderOptionLabel, filterOption: (opt, value) => {
|
|
461
|
+
return matchRecipient(opt.data, value);
|
|
462
|
+
}, isClearable: false, isDisabled: !isMulti, isMulti: isMulti, onChange:
|
|
463
|
+
// using as any as it would be too tricky to type properly
|
|
464
|
+
handleOnChange, onInputChange: onSearch, onMenuOpen: onMenuOpen, onMenuClose: () => setState((prev) => ({ ...prev, menuOpen: false })), onKeyDown: handleKeyDown, options: options, onBlur: onBlur, value: value, getOptionValue: (o) => o.id, getOptionLabel: (o) => o.name ?? o.id, "aria-describedby": showInputError ? "gd-recipients-field-error" : undefined, "aria-invalid": showInputError }),
|
|
465
|
+
showInputError ? (renderInputError({
|
|
466
|
+
authorOnlyError,
|
|
467
|
+
invalidExternalError,
|
|
468
|
+
invalidUnknownError,
|
|
469
|
+
maxRecipientsError,
|
|
470
|
+
minRecipientsError,
|
|
471
|
+
missingEmailError,
|
|
472
|
+
invalidRecipientsValues,
|
|
473
|
+
missingEmailRecipientsValues,
|
|
474
|
+
maxRecipients,
|
|
475
|
+
usersError,
|
|
476
|
+
})) : renderExternalRecipientsNote ? (React.createElement("div", { className: "gd-recipients-field-note" },
|
|
477
|
+
React.createElement(FormattedMessage, { id: "dialogs.schedule.email.recipients.note" }))) : allowOnlyLoggedUserRecipients ? (React.createElement("div", { className: "gd-recipients-field-note" },
|
|
478
|
+
React.createElement(FormattedMessage, { id: "dialogs.schedule.email.destinationWarning" }))) : null)));
|
|
479
|
+
});
|
|
473
480
|
//# sourceMappingURL=RecipientsSelectRenderer.js.map
|