@sapui5/sap.fe.core 1.108.2 → 1.108.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/sap/fe/core/.library +1 -1
- package/src/sap/fe/core/ActionRuntime.js +2 -2
- package/src/sap/fe/core/ActionRuntime.ts +1 -1
- package/src/sap/fe/core/CommonUtils.js +7 -3
- package/src/sap/fe/core/CommonUtils.ts +2 -2
- package/src/sap/fe/core/TemplateModel.js +16 -2
- package/src/sap/fe/core/TemplateModel.ts +15 -1
- package/src/sap/fe/core/controllerextensions/EditFlow.js +2 -1
- package/src/sap/fe/core/controllerextensions/EditFlow.ts +1 -0
- package/src/sap/fe/core/controllerextensions/editFlow/operations.js +386 -357
- package/src/sap/fe/core/controllerextensions/editFlow/operations.ts +260 -224
- package/src/sap/fe/core/controls/ActionParameterDialog.fragment.xml +1 -0
- package/src/sap/fe/core/converters/controls/Common/Action.js +4 -2
- package/src/sap/fe/core/converters/controls/Common/Action.ts +1 -1
- package/src/sap/fe/core/converters/controls/Common/Table.js +7 -10
- package/src/sap/fe/core/converters/controls/Common/Table.ts +6 -6
- package/src/sap/fe/core/formatters/ValueFormatter.js +5 -3
- package/src/sap/fe/core/formatters/ValueFormatter.ts +17 -7
- package/src/sap/fe/core/helpers/BindingToolkit.js +2 -2
- package/src/sap/fe/core/helpers/BindingToolkit.ts +1 -1
- package/src/sap/fe/core/helpers/ModelHelper.js +2 -2
- package/src/sap/fe/core/helpers/ModelHelper.ts +1 -1
- package/src/sap/fe/core/library.js +1 -1
- package/src/sap/fe/core/messagebundle_ar.properties +18 -18
- package/src/sap/fe/core/messagebundle_bg.properties +17 -17
- package/src/sap/fe/core/messagebundle_ca.properties +18 -18
- package/src/sap/fe/core/messagebundle_cs.properties +18 -18
- package/src/sap/fe/core/messagebundle_cy.properties +18 -18
- package/src/sap/fe/core/messagebundle_da.properties +18 -18
- package/src/sap/fe/core/messagebundle_el.properties +17 -17
- package/src/sap/fe/core/messagebundle_en_GB.properties +18 -18
- package/src/sap/fe/core/messagebundle_es.properties +9 -9
- package/src/sap/fe/core/messagebundle_es_MX.properties +17 -17
- package/src/sap/fe/core/messagebundle_et.properties +18 -18
- package/src/sap/fe/core/messagebundle_fi.properties +18 -18
- package/src/sap/fe/core/messagebundle_fr.properties +17 -17
- package/src/sap/fe/core/messagebundle_fr_CA.properties +18 -18
- package/src/sap/fe/core/messagebundle_hi.properties +18 -18
- package/src/sap/fe/core/messagebundle_hr.properties +18 -18
- package/src/sap/fe/core/messagebundle_hu.properties +17 -17
- package/src/sap/fe/core/messagebundle_id.properties +18 -18
- package/src/sap/fe/core/messagebundle_it.properties +17 -17
- package/src/sap/fe/core/messagebundle_iw.properties +18 -18
- package/src/sap/fe/core/messagebundle_ja.properties +21 -21
- package/src/sap/fe/core/messagebundle_kk.properties +18 -18
- package/src/sap/fe/core/messagebundle_ko.properties +18 -18
- package/src/sap/fe/core/messagebundle_lt.properties +17 -17
- package/src/sap/fe/core/messagebundle_lv.properties +18 -18
- package/src/sap/fe/core/messagebundle_ms.properties +18 -18
- package/src/sap/fe/core/messagebundle_nl.properties +18 -18
- package/src/sap/fe/core/messagebundle_no.properties +17 -17
- package/src/sap/fe/core/messagebundle_pl.properties +17 -17
- package/src/sap/fe/core/messagebundle_pt.properties +18 -18
- package/src/sap/fe/core/messagebundle_pt_PT.properties +18 -18
- package/src/sap/fe/core/messagebundle_ro.properties +17 -17
- package/src/sap/fe/core/messagebundle_ru.properties +18 -18
- package/src/sap/fe/core/messagebundle_sh.properties +17 -17
- package/src/sap/fe/core/messagebundle_sk.properties +17 -17
- package/src/sap/fe/core/messagebundle_sl.properties +18 -18
- package/src/sap/fe/core/messagebundle_sv.properties +17 -17
- package/src/sap/fe/core/messagebundle_th.properties +17 -17
- package/src/sap/fe/core/messagebundle_tr.properties +18 -18
- package/src/sap/fe/core/messagebundle_uk.properties +18 -18
- package/src/sap/fe/core/messagebundle_vi.properties +18 -18
- package/src/sap/fe/core/messagebundle_zh_CN.properties +17 -17
- package/src/sap/fe/core/messagebundle_zh_TW.properties +17 -17
- package/src/sap/fe/core/services/TemplatedViewServiceFactory.js +28 -53
- package/src/sap/fe/core/services/TemplatedViewServiceFactory.ts +36 -67
- package/src/sap/fe/core/templating/PropertyHelper.js +23 -2
- package/src/sap/fe/core/templating/PropertyHelper.ts +17 -0
- package/src/sap/fe/core/templating/SemanticObjectHelper.js +56 -0
- package/src/sap/fe/core/templating/SemanticObjectHelper.ts +34 -0
|
@@ -9,7 +9,9 @@ import { generate } from "sap/fe/core/helpers/StableIdHelper";
|
|
|
9
9
|
import FELibrary from "sap/fe/core/library";
|
|
10
10
|
import Button from "sap/m/Button";
|
|
11
11
|
import Dialog from "sap/m/Dialog";
|
|
12
|
+
import type Label from "sap/m/Label";
|
|
12
13
|
import MessageBox from "sap/m/MessageBox";
|
|
14
|
+
import type Event from "sap/ui/base/Event";
|
|
13
15
|
import type Control from "sap/ui/core/Control";
|
|
14
16
|
import Core from "sap/ui/core/Core";
|
|
15
17
|
import Fragment from "sap/ui/core/Fragment";
|
|
@@ -17,9 +19,14 @@ import { MessageType } from "sap/ui/core/library";
|
|
|
17
19
|
import Message from "sap/ui/core/message/Message";
|
|
18
20
|
import XMLPreprocessor from "sap/ui/core/util/XMLPreprocessor";
|
|
19
21
|
import XMLTemplateProcessor from "sap/ui/core/XMLTemplateProcessor";
|
|
22
|
+
import type Field from "sap/ui/mdc/Field";
|
|
23
|
+
import type MultiValueFieldItem from "sap/ui/mdc/field/MultiValueFieldItem";
|
|
24
|
+
import type MultiValueField from "sap/ui/mdc/MultiValueField";
|
|
25
|
+
import type Context from "sap/ui/model/Context";
|
|
20
26
|
import JSONModel from "sap/ui/model/json/JSONModel";
|
|
27
|
+
import type AppComponent from "../../AppComponent";
|
|
21
28
|
import operationsHelper from "../../operationsHelper";
|
|
22
|
-
import MessageHandler from "../MessageHandler";
|
|
29
|
+
import type MessageHandler from "../MessageHandler";
|
|
23
30
|
|
|
24
31
|
const Constants = FELibrary.Constants,
|
|
25
32
|
InvocationGrouping = FELibrary.InvocationGrouping;
|
|
@@ -51,7 +58,7 @@ const Action = (MessageBox as any).Action;
|
|
|
51
58
|
* @private
|
|
52
59
|
* @ui5-restricted
|
|
53
60
|
*/
|
|
54
|
-
function callBoundAction(sActionName: string, contexts: any, oModel: any, oAppComponent:
|
|
61
|
+
function callBoundAction(sActionName: string, contexts: any, oModel: any, oAppComponent: AppComponent, mParameters: any) {
|
|
55
62
|
if (!contexts || contexts.length === 0) {
|
|
56
63
|
//In Freestyle apps bound actions can have no context
|
|
57
64
|
return Promise.reject("Bound actions always requires at least one context");
|
|
@@ -122,7 +129,7 @@ function callBoundAction(sActionName: string, contexts: any, oModel: any, oAppCo
|
|
|
122
129
|
* @private
|
|
123
130
|
* @ui5-restricted
|
|
124
131
|
*/
|
|
125
|
-
function callActionImport(sActionName: string, oModel: any, oAppComponent:
|
|
132
|
+
function callActionImport(sActionName: string, oModel: any, oAppComponent: AppComponent, mParameters: any) {
|
|
126
133
|
if (!oModel) {
|
|
127
134
|
return Promise.reject("Action expects a model/context for execution");
|
|
128
135
|
}
|
|
@@ -180,7 +187,7 @@ function _executeFunction(sFunctionName: any, oModel: any, oFunction: any, conte
|
|
|
180
187
|
return oFunction.getBoundContext();
|
|
181
188
|
});
|
|
182
189
|
}
|
|
183
|
-
function callAction(sActionName: any, oModel: any, oAction: any, oAppComponent:
|
|
190
|
+
function callAction(sActionName: any, oModel: any, oAction: any, oAppComponent: AppComponent, mParameters: any) {
|
|
184
191
|
return new Promise(async function (resolve: (value: any) => void, reject: (reason?: any) => void) {
|
|
185
192
|
let mActionExecutionParameters: any = {};
|
|
186
193
|
let fnDialog;
|
|
@@ -210,6 +217,7 @@ function callAction(sActionName: any, oModel: any, oAction: any, oAppComponent:
|
|
|
210
217
|
// The parameter ResultIsActiveEntity is always hidden in the dialog! Hence if
|
|
211
218
|
// this is the only parameter, this is treated as no parameter here because the
|
|
212
219
|
// dialog would be empty!
|
|
220
|
+
// FIXME: Should only ignore this if this is a 'create' action, otherwise it is just some normal parameter that happens to have this name
|
|
213
221
|
const bActionNeedsParameterDialog =
|
|
214
222
|
aActionParameters.length > 0 && !(aActionParameters.length === 1 && aActionParameters[0].$Name === "ResultIsActiveEntity");
|
|
215
223
|
|
|
@@ -352,10 +360,10 @@ function callAction(sActionName: any, oModel: any, oAction: any, oAppComponent:
|
|
|
352
360
|
(element: any) => element.name === mActionExecutionParameters.aActionParameters[i].$Name
|
|
353
361
|
)?.value;
|
|
354
362
|
}
|
|
355
|
-
} else
|
|
363
|
+
} else {
|
|
356
364
|
for (const i in mActionExecutionParameters.aActionParameters) {
|
|
357
365
|
mActionExecutionParameters.aActionParameters[i].value =
|
|
358
|
-
oStartupParameters[mActionExecutionParameters.aActionParameters[i].$Name][0];
|
|
366
|
+
oStartupParameters[mActionExecutionParameters.aActionParameters[i].$Name]?.[0];
|
|
359
367
|
}
|
|
360
368
|
}
|
|
361
369
|
let oOperationResult: any;
|
|
@@ -368,7 +376,7 @@ function callAction(sActionName: any, oModel: any, oAction: any, oAppComponent:
|
|
|
368
376
|
mParameters.messageHandler
|
|
369
377
|
);
|
|
370
378
|
|
|
371
|
-
const messages =
|
|
379
|
+
const messages = Core.getMessageManager().getMessageModel().getData();
|
|
372
380
|
if (
|
|
373
381
|
mActionExecutionParameters.internalModelContext &&
|
|
374
382
|
mActionExecutionParameters.internalModelContext.getProperty("412Executed") &&
|
|
@@ -418,7 +426,7 @@ function callAction(sActionName: any, oModel: any, oAction: any, oAppComponent:
|
|
|
418
426
|
}
|
|
419
427
|
function confirmCriticalAction(
|
|
420
428
|
sActionName: any,
|
|
421
|
-
oAppComponent:
|
|
429
|
+
oAppComponent: AppComponent,
|
|
422
430
|
sActionLabel: any,
|
|
423
431
|
mParameters: any,
|
|
424
432
|
aActionParameters: any,
|
|
@@ -464,7 +472,7 @@ function confirmCriticalAction(
|
|
|
464
472
|
}
|
|
465
473
|
|
|
466
474
|
async function executeAPMAction(
|
|
467
|
-
oAppComponent:
|
|
475
|
+
oAppComponent: AppComponent,
|
|
468
476
|
mParameters: any,
|
|
469
477
|
oParentControl: any,
|
|
470
478
|
messageHandler: MessageHandler,
|
|
@@ -481,7 +489,7 @@ async function executeAPMAction(
|
|
|
481
489
|
throw aResult;
|
|
482
490
|
}
|
|
483
491
|
|
|
484
|
-
const messages =
|
|
492
|
+
const messages = Core.getMessageManager().getMessageModel().getData();
|
|
485
493
|
if (
|
|
486
494
|
mParameters.internalModelContext &&
|
|
487
495
|
mParameters.internalModelContext.getProperty("412Executed") &&
|
|
@@ -638,12 +646,26 @@ function actionParameterShowMessageCallback(
|
|
|
638
646
|
*
|
|
639
647
|
*/
|
|
640
648
|
|
|
649
|
+
// this type is meant to describe the meta information for one ActionParameter (i.e. its object in metaModel)
|
|
650
|
+
type ActionParameter = {
|
|
651
|
+
$Name: string;
|
|
652
|
+
$isCollection: boolean;
|
|
653
|
+
// currently runtime information is written into the metamodel:
|
|
654
|
+
// - in the press handler of the action button on the parameter dialog, the value of each parameter is added
|
|
655
|
+
// - in setActionParameterDefaultValue, this information is used and transferred to the context (in ODataModel) created for the action execution
|
|
656
|
+
// this is quite odd, and it would make much more sense to take the value from actionParameterInfos
|
|
657
|
+
// - however, setActionParameterDefaultValue (or rather the surrounding _executeAction) is also called from other places
|
|
658
|
+
// => for the time being, adding value here to avoid ts errors, subject to refactoring
|
|
659
|
+
// in case of Field, the value is string, in case of MultiValueField, it's MultiValueFieldItem[]
|
|
660
|
+
value: string | MultiValueFieldItem[];
|
|
661
|
+
};
|
|
662
|
+
|
|
641
663
|
function showActionParameterDialog(
|
|
642
664
|
sActionName: any,
|
|
643
|
-
oAppComponent:
|
|
665
|
+
oAppComponent: AppComponent,
|
|
644
666
|
sActionLabel: any,
|
|
645
667
|
mParameters: any,
|
|
646
|
-
aActionParameters:
|
|
668
|
+
aActionParameters: ActionParameter[],
|
|
647
669
|
aParameterValues: any,
|
|
648
670
|
oActionContext: any,
|
|
649
671
|
oParentControl: any,
|
|
@@ -660,84 +682,112 @@ function showActionParameterDialog(
|
|
|
660
682
|
bIsCreateAction = mParameters.isCreateAction,
|
|
661
683
|
sFragmentName = "sap/fe/core/controls/ActionParameterDialog";
|
|
662
684
|
return new Promise(async function (resolve, reject) {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
+
type ActionParameterInfo = {
|
|
686
|
+
parameter: ActionParameter;
|
|
687
|
+
field: Field | MultiValueField;
|
|
688
|
+
isMultiValue: boolean;
|
|
689
|
+
value?: string | MultiValueFieldItem[];
|
|
690
|
+
validationPromise?: Promise<string | MultiValueFieldItem[]>;
|
|
691
|
+
};
|
|
692
|
+
let actionParameterInfos: ActionParameterInfo[]; // to be filled after fragment (for action parameter dialog) is loaded. Actually only needed during dialog processing, i.e. could be moved into the controller and directly initialized there, but only after moving all handlers (esp. press handler for action button) to controller.
|
|
693
|
+
|
|
694
|
+
const messageManager = Core.getMessageManager();
|
|
695
|
+
|
|
696
|
+
// in case of missing mandaotory parameter, message currently differs per parameter, as it superfluously contains the label as parameter. Possiblky this could be removed in future, in that case, interface could be simplified to ActionParameterInfo[], string
|
|
697
|
+
const _addMessageForActionParameter = (messageParameters: { actionParameterInfo: ActionParameterInfo; message: string }[]) => {
|
|
698
|
+
messageManager.addMessages(
|
|
699
|
+
messageParameters.map((messageParameter) => {
|
|
700
|
+
const binding = messageParameter.actionParameterInfo.field.getBinding(
|
|
701
|
+
messageParameter.actionParameterInfo.isMultiValue ? "items" : "value"
|
|
702
|
+
);
|
|
703
|
+
return new Message({
|
|
704
|
+
message: messageParameter.message,
|
|
705
|
+
type: "Error",
|
|
706
|
+
processor: binding?.getModel(),
|
|
707
|
+
persistent: true,
|
|
708
|
+
target: binding?.getResolvedPath()
|
|
709
|
+
});
|
|
710
|
+
})
|
|
685
711
|
);
|
|
686
|
-
return aResults.filter(function (result: any) {
|
|
687
|
-
return result !== undefined;
|
|
688
|
-
});
|
|
689
712
|
};
|
|
690
|
-
const _validateMessages = function (actionParameters: any, invalidFields: any, bClearTarget?: boolean) {
|
|
691
|
-
const oMessageManager = Core.getMessageManager();
|
|
692
|
-
const aMessages = oMessageManager.getMessageModel().getData();
|
|
693
713
|
|
|
694
|
-
|
|
714
|
+
const _removeMessagesForActionParamter = (parameter: ActionParameter) => {
|
|
715
|
+
const allMessages = messageManager.getMessageModel().getData();
|
|
716
|
+
const controlId = generate(["APD_", parameter.$Name]);
|
|
717
|
+
// also remove messages assigned to inner controls, but avoid removing messages for different paramters (with name being substring of another parameter name)
|
|
718
|
+
const relevantMessages = allMessages.filter((msg: Message) =>
|
|
719
|
+
msg.getControlIds().some((id: string) => controlId.split("-").includes(id))
|
|
720
|
+
);
|
|
721
|
+
messageManager.removeMessages(relevantMessages);
|
|
722
|
+
};
|
|
695
723
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
724
|
+
const _validateRequiredProperties = async function (oResourceBundle: ResourceBundle) {
|
|
725
|
+
const requiredParameterInfos = actionParameterInfos.filter((actionParameterInfo) => actionParameterInfo.field.getRequired());
|
|
726
|
+
// before validation of required fields is not complete, we cannot know the values and thus cannot validate they are provided
|
|
727
|
+
const validationResults = await Promise.allSettled(
|
|
728
|
+
requiredParameterInfos.map((actionParameterInfo) => actionParameterInfo.validationPromise)
|
|
729
|
+
);
|
|
730
|
+
|
|
731
|
+
const validRequiredFields = validationResults
|
|
732
|
+
.map((validationResult, index) => ({
|
|
733
|
+
validationResult: validationResult,
|
|
734
|
+
index: index
|
|
735
|
+
}))
|
|
736
|
+
.filter((validationResult) => validationResult.validationResult.status === "fulfilled")
|
|
737
|
+
.map((validationResult) => requiredParameterInfos[validationResult.index]);
|
|
738
|
+
|
|
739
|
+
const emptyRequiredFields = validRequiredFields.filter((actionParameterInfo) =>
|
|
740
|
+
actionParameterInfo.isMultiValue ? !(actionParameterInfo.value as MultiValueFieldItem[]).length : !actionParameterInfo.value
|
|
741
|
+
);
|
|
742
|
+
if (!emptyRequiredFields.length) return true;
|
|
743
|
+
|
|
744
|
+
// message contains label per field for historical reason (originally, it was shown in additional popup, now it's directly added to the field)
|
|
745
|
+
// if this was not the case (and hopefully, in future this might be subject to change), interface of _addMessageForActionParameter could be simplified to just pass emptyRequiredFields and a constant message here
|
|
746
|
+
_addMessageForActionParameter(
|
|
747
|
+
emptyRequiredFields.map((actionParameterInfo) => ({
|
|
748
|
+
actionParameterInfo: actionParameterInfo,
|
|
749
|
+
message: CommonUtils.getTranslatedText("C_OPERATIONS_ACTION_PARAMETER_DIALOG_MISSING_MANDATORY_MSG", oResourceBundle, [
|
|
750
|
+
(actionParameterInfo.field.getParent()?.getAggregation("label") as Label).getText()
|
|
751
|
+
])
|
|
752
|
+
}))
|
|
753
|
+
);
|
|
754
|
+
|
|
755
|
+
// Set the focus on the dialog's first erroneous required control
|
|
756
|
+
emptyRequiredFields[0].field.focus();
|
|
757
|
+
|
|
758
|
+
return false;
|
|
725
759
|
};
|
|
760
|
+
|
|
726
761
|
const oController = {
|
|
727
|
-
handleChange: function (oEvent:
|
|
728
|
-
|
|
729
|
-
const
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
762
|
+
handleChange: async function (oEvent: Event) {
|
|
763
|
+
const field = oEvent.getSource();
|
|
764
|
+
const actionParameterInfo = actionParameterInfos.find(
|
|
765
|
+
(actionParameterInfo) => actionParameterInfo.field === field
|
|
766
|
+
) as ActionParameterInfo;
|
|
767
|
+
// field value is being changed, thus existing messages related to that field are not valid anymore
|
|
768
|
+
_removeMessagesForActionParamter(actionParameterInfo.parameter);
|
|
769
|
+
// adapt info. Promise is resolved to value or rejected with exception containing message
|
|
770
|
+
actionParameterInfo.validationPromise = oEvent.getParameter("promise") as Promise<string>;
|
|
771
|
+
|
|
772
|
+
try {
|
|
773
|
+
actionParameterInfo.value = await actionParameterInfo.validationPromise;
|
|
774
|
+
} catch (error) {
|
|
775
|
+
delete actionParameterInfo.value;
|
|
776
|
+
_addMessageForActionParameter([
|
|
777
|
+
{
|
|
778
|
+
actionParameterInfo: actionParameterInfo,
|
|
779
|
+
message: (error as { message: string }).message
|
|
780
|
+
}
|
|
781
|
+
]);
|
|
736
782
|
}
|
|
737
|
-
_validateMessages(aActionParameters, aFieldInvalid);
|
|
738
783
|
}
|
|
739
784
|
};
|
|
740
785
|
|
|
786
|
+
const oFragment = XMLTemplateProcessor.loadTemplate(sFragmentName, "fragment");
|
|
787
|
+
const oParameterModel = new JSONModel({
|
|
788
|
+
$displayMode: {}
|
|
789
|
+
});
|
|
790
|
+
|
|
741
791
|
try {
|
|
742
792
|
const createdFragment = await XMLPreprocessor.process(
|
|
743
793
|
oFragment,
|
|
@@ -762,20 +812,38 @@ function showActionParameterDialog(
|
|
|
762
812
|
// eslint-disable-next-line prefer-const
|
|
763
813
|
let oOperationBinding: any;
|
|
764
814
|
await CommonUtils.setUserDefaults(oAppComponent, aActionParameters, oParameterModel, true);
|
|
765
|
-
const oDialogContent = (await Fragment.load({
|
|
815
|
+
const oDialogContent = (await Fragment.load({
|
|
816
|
+
definition: createdFragment,
|
|
817
|
+
controller: oController
|
|
818
|
+
})) as Control;
|
|
819
|
+
|
|
820
|
+
actionParameterInfos = aActionParameters.map((actionParameter) => {
|
|
821
|
+
const field = Core.byId(generate(["APD_", actionParameter.$Name])) as Field | MultiValueField;
|
|
822
|
+
const isMultiValue = field.isA("sap.ui.mdc.MultiValueField");
|
|
823
|
+
return {
|
|
824
|
+
parameter: actionParameter,
|
|
825
|
+
field: field,
|
|
826
|
+
isMultiValue: isMultiValue
|
|
827
|
+
};
|
|
828
|
+
});
|
|
829
|
+
|
|
766
830
|
const oResourceBundle = oParentControl.getController().oResourceBundle;
|
|
831
|
+
let actionResult = {
|
|
832
|
+
dialogCancelled: true, // to be set to false in case of successful action exection
|
|
833
|
+
result: undefined
|
|
834
|
+
};
|
|
767
835
|
const oDialog = new Dialog(undefined, {
|
|
768
836
|
title: sActionLabel || CommonUtils.getTranslatedText("C_OPERATIONS_ACTION_PARAMETER_DIALOG_TITLE", oResourceBundle),
|
|
769
837
|
content: [oDialogContent],
|
|
770
838
|
escapeHandler: function () {
|
|
771
839
|
// escape handler is meant to possibly suppress or postpone closing the dialog on escape (by calling "reject" on the provided object, or "resolve" only when
|
|
772
840
|
// done with all tasks to happen before dialog can be closed). It's not intended to explicetly close the dialog here (that happens automatically when no
|
|
773
|
-
// escapeHandler is provided or the resolve-
|
|
841
|
+
// escapeHandler is provided or the resolve-callback is called) or for own wrap up tasks (like removing validition messages - this should happen in the
|
|
774
842
|
// afterClose).
|
|
775
843
|
// TODO: Move wrap up tasks to afterClose, and remove this method completely. Take care to also adapt end button press handler accordingly.
|
|
844
|
+
// Currently only still needed to differentiate closing dialog after successful execution (uses resolve) from user cancellation (using reject)
|
|
776
845
|
oDialog.close();
|
|
777
|
-
|
|
778
|
-
reject(Constants.CancelActionDialog);
|
|
846
|
+
// reject(Constants.CancelActionDialog);
|
|
779
847
|
},
|
|
780
848
|
beginButton: new Button(generate(["fe", "APD_", sActionName, "Action", "Ok"]), {
|
|
781
849
|
text: bIsCreateAction
|
|
@@ -784,37 +852,13 @@ function showActionParameterDialog(
|
|
|
784
852
|
type: "Emphasized",
|
|
785
853
|
press: async function () {
|
|
786
854
|
try {
|
|
787
|
-
|
|
788
|
-
if (aEmptyMandatoryFields.length) {
|
|
789
|
-
for (let i = 0; i < aEmptyMandatoryFields.length; i++) {
|
|
790
|
-
aEmptyMandatoryFields[i].getFields()[0].setValueState("Error");
|
|
791
|
-
aEmptyMandatoryFields[i]
|
|
792
|
-
.getFields()[0]
|
|
793
|
-
.setValueStateText(
|
|
794
|
-
CommonUtils.getTranslatedText(
|
|
795
|
-
"C_OPERATIONS_ACTION_PARAMETER_DIALOG_MISSING_MANDATORY_MSG",
|
|
796
|
-
oResourceBundle,
|
|
797
|
-
aEmptyMandatoryFields[i].getLabel().getText()
|
|
798
|
-
)
|
|
799
|
-
);
|
|
800
|
-
}
|
|
855
|
+
if (!(await _validateRequiredProperties(oResourceBundle))) {
|
|
801
856
|
return;
|
|
802
857
|
}
|
|
803
858
|
|
|
804
|
-
aFieldInvalid = _validateMessages(aActionParameters, aFieldInvalid);
|
|
805
|
-
|
|
806
|
-
if (aFieldInvalid.length > 0) {
|
|
807
|
-
await messageHandling.showUnboundMessages();
|
|
808
|
-
return;
|
|
809
|
-
}
|
|
810
859
|
BusyLocker.lock(oDialog);
|
|
811
860
|
|
|
812
861
|
try {
|
|
813
|
-
await Promise.all(
|
|
814
|
-
Object.keys(mFieldValueMap).map(function (sKey: string) {
|
|
815
|
-
return mFieldValueMap[sKey];
|
|
816
|
-
})
|
|
817
|
-
);
|
|
818
862
|
// TODO: due to using the search and value helps on the action dialog transient messages could appear
|
|
819
863
|
// we need an UX design for those to show them to the user - for now remove them before continuing
|
|
820
864
|
messageHandler.removeTransitionMessages();
|
|
@@ -832,7 +876,7 @@ function showActionParameterDialog(
|
|
|
832
876
|
} else {
|
|
833
877
|
vParameterValue = oParameterContext.getProperty(aActionParameters[i].$Name);
|
|
834
878
|
}
|
|
835
|
-
aActionParameters[i].value = vParameterValue;
|
|
879
|
+
aActionParameters[i].value = vParameterValue; // writing the current value (ueser input!) into the metamodel => should be refactored to use ActionParameterInfos instead. Used in setActionParameterDefaultValue
|
|
836
880
|
vParameterValue = undefined;
|
|
837
881
|
}
|
|
838
882
|
mParameters.label = sActionLabel;
|
|
@@ -847,8 +891,11 @@ function showActionParameterDialog(
|
|
|
847
891
|
oDialog,
|
|
848
892
|
false
|
|
849
893
|
);
|
|
894
|
+
actionResult = {
|
|
895
|
+
dialogCancelled: false,
|
|
896
|
+
result: aResult
|
|
897
|
+
};
|
|
850
898
|
oDialog.close();
|
|
851
|
-
resolve(aResult);
|
|
852
899
|
} catch (oError: any) {
|
|
853
900
|
const messages = sap.ui.getCore().getMessageManager().getMessageModel().getData();
|
|
854
901
|
if (
|
|
@@ -887,7 +934,10 @@ function showActionParameterDialog(
|
|
|
887
934
|
|
|
888
935
|
mParameters.internalModelContext.setProperty("strictHandlingFails", []);
|
|
889
936
|
mParameters.internalModelContext.setProperty("processedMessageIds", []);
|
|
890
|
-
|
|
937
|
+
actionResult = {
|
|
938
|
+
dialogCancelled: false,
|
|
939
|
+
result: aResult
|
|
940
|
+
};
|
|
891
941
|
} catch {
|
|
892
942
|
if (
|
|
893
943
|
mParameters.internalModelContext &&
|
|
@@ -959,13 +1009,7 @@ function showActionParameterDialog(
|
|
|
959
1009
|
text: CommonUtils.getTranslatedText("C_COMMON_ACTION_PARAMETER_DIALOG_CANCEL", oResourceBundle),
|
|
960
1010
|
press: function () {
|
|
961
1011
|
// TODO: cancel button should just close the dialog (similar to using escape). All wrap up tasks should be moved to afterClose.
|
|
962
|
-
// Assumption: _validateMessages is only called to remove exisitng validation messages (is user first enters invalid parameter, and later cancels).
|
|
963
|
-
// If this assumption is correct, this needs also to be done when leaving the dialog with escape, i.e. should be moved to afterClose.
|
|
964
|
-
_validateMessages(aActionParameters, aFieldInvalid, true);
|
|
965
1012
|
oDialog.close();
|
|
966
|
-
// should not be done here, but after close, as the same should happen when leaving with escape
|
|
967
|
-
messageHandler.removeTransitionMessages();
|
|
968
|
-
reject(Constants.CancelActionDialog);
|
|
969
1013
|
}
|
|
970
1014
|
}),
|
|
971
1015
|
// TODO: beforeOpen is just an event, i.e. not waiting for the Promise to be resolved. Check if tasks of this function need to be done before opening the dialog
|
|
@@ -986,63 +1030,60 @@ function showActionParameterDialog(
|
|
|
986
1030
|
};
|
|
987
1031
|
const fnSetDefaultsAndOpenDialog = async function (sBindingParameter?: any) {
|
|
988
1032
|
const sBoundFunctionName = getDefaultValuesFunction();
|
|
989
|
-
const prefillParameter = function (sParamName: any, vParamDefaultValue: any) {
|
|
990
|
-
//
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1033
|
+
const prefillParameter = async function (sParamName: any, vParamDefaultValue: any) {
|
|
1034
|
+
// Case 1: There is a ParameterDefaultValue annotation
|
|
1035
|
+
if (vParamDefaultValue !== undefined) {
|
|
1036
|
+
if (aContexts.length > 0 && vParamDefaultValue.$Path) {
|
|
1037
|
+
try {
|
|
1038
|
+
let vParamValue = await CommonUtils.requestSingletonProperty(
|
|
1039
|
+
vParamDefaultValue.$Path,
|
|
1040
|
+
oOperationBinding.getModel()
|
|
1041
|
+
);
|
|
1042
|
+
if (vParamValue === null) {
|
|
1043
|
+
vParamValue = await oOperationBinding
|
|
1044
|
+
.getParameterContext()
|
|
1045
|
+
.requestProperty(vParamDefaultValue.$Path);
|
|
1046
|
+
}
|
|
1047
|
+
if (aContexts.length > 1) {
|
|
1048
|
+
// For multi select, need to loop over aContexts (as contexts cannot be retrieved via binding parameter of the operation binding)
|
|
1049
|
+
let sPathForContext = vParamDefaultValue.$Path;
|
|
1050
|
+
if (sPathForContext.indexOf(`${sBindingParameter}/`) === 0) {
|
|
1051
|
+
sPathForContext = sPathForContext.replace(`${sBindingParameter}/`, "");
|
|
1004
1052
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
// if the values from the contexts are not all the same, do not prefill
|
|
1014
|
-
inResolve({
|
|
1015
|
-
paramName: sParamName,
|
|
1016
|
-
value: undefined,
|
|
1017
|
-
bNoPossibleValue: true
|
|
1018
|
-
});
|
|
1019
|
-
}
|
|
1053
|
+
for (let i = 1; i < aContexts.length; i++) {
|
|
1054
|
+
if (aContexts[i].getProperty(sPathForContext) !== vParamValue) {
|
|
1055
|
+
// if the values from the contexts are not all the same, do not prefill
|
|
1056
|
+
return {
|
|
1057
|
+
paramName: sParamName,
|
|
1058
|
+
value: undefined,
|
|
1059
|
+
bNoPossibleValue: true
|
|
1060
|
+
};
|
|
1020
1061
|
}
|
|
1021
1062
|
}
|
|
1022
|
-
inResolve({ paramName: sParamName, value: vParamValue });
|
|
1023
|
-
} catch (oError) {
|
|
1024
|
-
Log.error("Error while reading default action parameter", sParamName, mParameters.actionName);
|
|
1025
|
-
inResolve({
|
|
1026
|
-
paramName: sParamName,
|
|
1027
|
-
value: undefined,
|
|
1028
|
-
bLatePropertyError: true
|
|
1029
|
-
});
|
|
1030
1063
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1064
|
+
return { paramName: sParamName, value: vParamValue };
|
|
1065
|
+
} catch (oError) {
|
|
1066
|
+
Log.error("Error while reading default action parameter", sParamName, mParameters.actionName);
|
|
1067
|
+
return {
|
|
1068
|
+
paramName: sParamName,
|
|
1069
|
+
value: undefined,
|
|
1070
|
+
bLatePropertyError: true
|
|
1071
|
+
};
|
|
1034
1072
|
}
|
|
1035
|
-
} else if (oParameterModel && (oParameterModel as any).oData[sParamName]) {
|
|
1036
|
-
// Case 2: There is no ParameterDefaultValue annotation (=> look into the FLP User Defaults)
|
|
1037
|
-
|
|
1038
|
-
inResolve({
|
|
1039
|
-
paramName: sParamName,
|
|
1040
|
-
value: (oParameterModel as any).oData[sParamName]
|
|
1041
|
-
});
|
|
1042
1073
|
} else {
|
|
1043
|
-
|
|
1074
|
+
// Case 1.2: ParameterDefaultValue defines a fixed string value (i.e. vParamDefaultValue = 'someString')
|
|
1075
|
+
return { paramName: sParamName, value: vParamDefaultValue };
|
|
1044
1076
|
}
|
|
1045
|
-
})
|
|
1077
|
+
} else if (oParameterModel && (oParameterModel as any).oData[sParamName]) {
|
|
1078
|
+
// Case 2: There is no ParameterDefaultValue annotation (=> look into the FLP User Defaults)
|
|
1079
|
+
|
|
1080
|
+
return {
|
|
1081
|
+
paramName: sParamName,
|
|
1082
|
+
value: (oParameterModel as any).oData[sParamName]
|
|
1083
|
+
};
|
|
1084
|
+
} else {
|
|
1085
|
+
return { paramName: sParamName, value: undefined };
|
|
1086
|
+
}
|
|
1046
1087
|
};
|
|
1047
1088
|
|
|
1048
1089
|
const getParameterDefaultValue = function (sParamName: any) {
|
|
@@ -1184,16 +1225,28 @@ function showActionParameterDialog(
|
|
|
1184
1225
|
};
|
|
1185
1226
|
|
|
1186
1227
|
await fnAsyncBeforeOpen();
|
|
1228
|
+
|
|
1229
|
+
// adding defaulted values only here after they are not set to the fields
|
|
1230
|
+
for (const actionParameterInfo of actionParameterInfos) {
|
|
1231
|
+
const value = actionParameterInfo.isMultiValue
|
|
1232
|
+
? (actionParameterInfo.field as MultiValueField).getItems()
|
|
1233
|
+
: (actionParameterInfo.field as Field).getValue();
|
|
1234
|
+
actionParameterInfo.value = value;
|
|
1235
|
+
actionParameterInfo.validationPromise = Promise.resolve(value);
|
|
1236
|
+
}
|
|
1187
1237
|
},
|
|
1188
1238
|
afterClose: function () {
|
|
1239
|
+
// when the dialog is cancelled, messages need to be removed in case the same action should be executed again
|
|
1240
|
+
aActionParameters.forEach(_removeMessagesForActionParamter);
|
|
1189
1241
|
oDialog.destroy();
|
|
1242
|
+
if (actionResult.dialogCancelled) {
|
|
1243
|
+
reject(Constants.CancelActionDialog);
|
|
1244
|
+
} else {
|
|
1245
|
+
resolve(actionResult.result);
|
|
1246
|
+
}
|
|
1190
1247
|
}
|
|
1191
1248
|
});
|
|
1192
1249
|
mParameters.oDialog = oDialog;
|
|
1193
|
-
aFormElements = (oDialogContent as any)
|
|
1194
|
-
.getAggregation("form")
|
|
1195
|
-
.getAggregation("formContainers")[0]
|
|
1196
|
-
.getAggregation("formElements");
|
|
1197
1250
|
oDialog.setModel(oActionContext.getModel().oModel);
|
|
1198
1251
|
oDialog.setModel(oParameterModel, "paramsModel");
|
|
1199
1252
|
oDialog.bindElement({
|
|
@@ -1411,6 +1464,7 @@ function executeDependingOnSelectedContexts(
|
|
|
1411
1464
|
messageHandler,
|
|
1412
1465
|
oResourceBundle
|
|
1413
1466
|
);
|
|
1467
|
+
|
|
1414
1468
|
return Promise.reject();
|
|
1415
1469
|
})
|
|
1416
1470
|
: oAction
|
|
@@ -1531,45 +1585,36 @@ function _executeAction(oAppComponent: any, mParameters: any, oParentControl?: a
|
|
|
1531
1585
|
fnRequestSideEffects(oAppComponent, oSideEffect, mParameters, sGroupId);
|
|
1532
1586
|
};
|
|
1533
1587
|
const fnExecuteSingleAction = function (actionContext: any, current_context_index: any, oSideEffect: any, iContextLength: any) {
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
oModel.submitBatch(sGroupId);
|
|
1562
|
-
Promise.all(aLocalPromise)
|
|
1563
|
-
.then(function () {
|
|
1564
|
-
return actionResolve();
|
|
1565
|
-
})
|
|
1566
|
-
.catch(function () {
|
|
1567
|
-
return actionResolve();
|
|
1568
|
-
});
|
|
1569
|
-
});
|
|
1588
|
+
const aLocalPromise: any = [];
|
|
1589
|
+
setActionParameterDefaultValue();
|
|
1590
|
+
// For invocation grouping "isolated" need batch group per action call
|
|
1591
|
+
sGroupId = `apiMode${current_context_index}`;
|
|
1592
|
+
mParameters.requestSideEffects = fnRequestSideEffects.bind(
|
|
1593
|
+
operations,
|
|
1594
|
+
oAppComponent,
|
|
1595
|
+
oSideEffect,
|
|
1596
|
+
mParameters,
|
|
1597
|
+
sGroupId,
|
|
1598
|
+
aLocalPromise
|
|
1599
|
+
);
|
|
1600
|
+
oActionPromise = executeDependingOnSelectedContexts(
|
|
1601
|
+
actionContext,
|
|
1602
|
+
mParameters,
|
|
1603
|
+
bGetBoundContext,
|
|
1604
|
+
sGroupId,
|
|
1605
|
+
oResourceBundle,
|
|
1606
|
+
messageHandler,
|
|
1607
|
+
iContextLength,
|
|
1608
|
+
current_context_index
|
|
1609
|
+
);
|
|
1610
|
+
aActionPromises.push(oActionPromise);
|
|
1611
|
+
aLocalPromise.push(oActionPromise);
|
|
1612
|
+
fnRequestSideEffects(oAppComponent, oSideEffect, mParameters, sGroupId, aLocalPromise);
|
|
1613
|
+
oModel.submitBatch(sGroupId);
|
|
1614
|
+
return Promise.allSettled(aLocalPromise);
|
|
1570
1615
|
};
|
|
1571
1616
|
|
|
1572
|
-
function fnExecuteSequentially(contextsToExecute:
|
|
1617
|
+
async function fnExecuteSequentially(contextsToExecute: Context[]) {
|
|
1573
1618
|
// One action and its side effects are completed before the next action is executed
|
|
1574
1619
|
(
|
|
1575
1620
|
fnOnSubmitted ||
|
|
@@ -1591,22 +1636,13 @@ function _executeAction(oAppComponent: any, mParameters: any, oParentControl?: a
|
|
|
1591
1636
|
);
|
|
1592
1637
|
}
|
|
1593
1638
|
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
return processOneAction(context, id, aContexts.length);
|
|
1600
|
-
});
|
|
1601
|
-
});
|
|
1639
|
+
// serialization: processOneAction to be called for each entry in contextsToExecute only after the promise returned from the one before has been resolved
|
|
1640
|
+
await contextsToExecute.reduce(async (promise: Promise<void>, context: Context, id: int): Promise<void> => {
|
|
1641
|
+
await promise;
|
|
1642
|
+
await processOneAction(context, id + 1, aContexts.length);
|
|
1643
|
+
}, Promise.resolve());
|
|
1602
1644
|
|
|
1603
|
-
|
|
1604
|
-
.then(function () {
|
|
1605
|
-
fnHandleResults();
|
|
1606
|
-
})
|
|
1607
|
-
.catch(function (oError: any) {
|
|
1608
|
-
Log.error(oError);
|
|
1609
|
-
});
|
|
1645
|
+
fnHandleResults();
|
|
1610
1646
|
}
|
|
1611
1647
|
|
|
1612
1648
|
if (!bGrouped) {
|