@sapui5/sap.fe.test 1.101.0 → 1.103.0
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/test/.library +1 -1
- package/src/sap/fe/test/BaseActions.js +86 -97
- package/src/sap/fe/test/BaseArrangements.js +4 -15
- package/src/sap/fe/test/BaseAssertions.js +39 -46
- package/src/sap/fe/test/CollaborationClient.js +77 -0
- package/src/sap/fe/test/CollaborationClient.ts +105 -0
- package/src/sap/fe/test/FeMocks.js +1 -1
- package/src/sap/fe/test/FeMocks.ts +10 -5
- package/src/sap/fe/test/Flexibility.js +115 -162
- package/src/sap/fe/test/JestTemplatingHelper.js +54 -24
- package/src/sap/fe/test/JestTemplatingHelper.ts +59 -30
- package/src/sap/fe/test/JourneyRunner.js +31 -37
- package/src/sap/fe/test/ListReport.js +10 -22
- package/src/sap/fe/test/LocationUtil.js +12 -16
- package/src/sap/fe/test/ObjectPage.js +64 -38
- package/src/sap/fe/test/Shell.js +94 -40
- package/src/sap/fe/test/TemplatePage.js +14 -2
- package/src/sap/fe/test/TemplatingTestUtils.js +20 -20
- package/src/sap/fe/test/UI5MockHelper.js +101 -21
- package/src/sap/fe/test/UI5MockHelper.ts +92 -26
- package/src/sap/fe/test/Utils.js +19 -20
- package/src/sap/fe/test/api/BaseAPI.js +11 -26
- package/src/sap/fe/test/api/ChartActions.js +116 -119
- package/src/sap/fe/test/api/ChartAssertions.js +18 -22
- package/src/sap/fe/test/api/CollaborationAPI.js +215 -0
- package/src/sap/fe/test/api/CollaborationAPI.ts +238 -0
- package/src/sap/fe/test/api/DialogAPI.js +11 -13
- package/src/sap/fe/test/api/DialogActions.js +8 -8
- package/src/sap/fe/test/api/DialogAssertions.js +8 -9
- package/src/sap/fe/test/api/DialogHelper.js +63 -0
- package/src/sap/fe/test/api/DialogMassEditActions.js +115 -0
- package/src/sap/fe/test/api/DialogMassEditAssertions.js +174 -0
- package/src/sap/fe/test/api/DialogMessageActions.js +2 -1
- package/src/sap/fe/test/api/DialogType.js +11 -2
- package/src/sap/fe/test/api/DialogValueHelpActions.js +17 -39
- package/src/sap/fe/test/api/DialogValueHelpAssertions.js +11 -19
- package/src/sap/fe/test/api/FilterBarAPI.js +11 -12
- package/src/sap/fe/test/api/FilterBarActions.js +26 -40
- package/src/sap/fe/test/api/FilterBarAssertions.js +28 -47
- package/src/sap/fe/test/api/FooterActionsBase.js +3 -4
- package/src/sap/fe/test/api/FooterActionsOP.js +6 -10
- package/src/sap/fe/test/api/FooterAssertionsBase.js +5 -10
- package/src/sap/fe/test/api/FooterAssertionsOP.js +8 -13
- package/src/sap/fe/test/api/FormAPI.js +5 -6
- package/src/sap/fe/test/api/FormActions.js +11 -21
- package/src/sap/fe/test/api/FormAssertions.js +14 -20
- package/src/sap/fe/test/api/HeaderAPI.js +12 -27
- package/src/sap/fe/test/api/HeaderActions.js +10 -12
- package/src/sap/fe/test/api/HeaderActionsLR.js +76 -82
- package/src/sap/fe/test/api/HeaderAssertions.js +76 -59
- package/src/sap/fe/test/api/HeaderAssertionsLR.js +5 -8
- package/src/sap/fe/test/api/HeaderLR.js +7 -19
- package/src/sap/fe/test/api/KPICardAssertions.js +18 -37
- package/src/sap/fe/test/api/TableAPI.js +33 -47
- package/src/sap/fe/test/api/TableActions.js +3 -35
- package/src/sap/fe/test/api/TableAssertions.js +51 -69
- package/src/sap/fe/test/builder/FEBuilder.js +71 -75
- package/src/sap/fe/test/builder/MacroFieldBuilder.js +162 -156
- package/src/sap/fe/test/builder/MdcFieldBuilder.js +33 -29
- package/src/sap/fe/test/builder/MdcFilterFieldBuilder.js +9 -7
- package/src/sap/fe/test/builder/MdcTableBuilder.js +97 -16
- package/src/sap/fe/test/builder/VMBuilder.js +27 -43
- package/src/sap/fe/test/library.js +3 -2
- package/src/sap/fe/test/library.ts +1 -0
- package/src/sap/fe/test/massEdit.js +0 -62
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* SAP UI development toolkit for HTML5 (SAPUI5)
|
|
3
|
+
* (c) Copyright 2009-2021 SAP SE. All rights reserved
|
|
4
|
+
*/
|
|
5
|
+
sap.ui.define(["sap/base/Log", "sap/fe/core/controllerextensions/collaboration/ActivityBase", "sap/fe/core/controllerextensions/collaboration/CollaborationCommon", "sap/fe/core/controllerextensions/editFlow/draft", "sap/ui/model/json/JSONModel"], function (Log, ActivityBase, CollaborationCommon, draft, JSONModel) {
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
var Activity = CollaborationCommon.Activity;
|
|
9
|
+
var initializeCollaboration = ActivityBase.initializeCollaboration;
|
|
10
|
+
var endCollaboration = ActivityBase.endCollaboration;
|
|
11
|
+
var broadcastCollaborationMessage = ActivityBase.broadcastCollaborationMessage;
|
|
12
|
+
|
|
13
|
+
var CollaborationAPI = {
|
|
14
|
+
_lastReceivedMessage: undefined,
|
|
15
|
+
_rootPath: "",
|
|
16
|
+
_oModel: undefined,
|
|
17
|
+
_lockedPropertyPath: "",
|
|
18
|
+
_internalModel: undefined,
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Open an existing collaborative draft with a new user, and creates a 'ghost client' for this user.
|
|
22
|
+
*
|
|
23
|
+
* @param oContext The context of the collaborative draft
|
|
24
|
+
* @param userID The ID of the user
|
|
25
|
+
* @param userName The name of the user
|
|
26
|
+
*/
|
|
27
|
+
enterDraft: function (oContext, userID, userName) {
|
|
28
|
+
var webSocketBaseURL = oContext.getModel().getMetaModel().getObject("/@com.sap.vocabularies.Common.v1.WebSocketBaseURL");
|
|
29
|
+
|
|
30
|
+
if (!webSocketBaseURL) {
|
|
31
|
+
Log.error("Cannot find WebSocketBaseURL annotation");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
var sDraftUUID = oContext.getProperty("DraftAdministrativeData/DraftUUID");
|
|
36
|
+
this._internalModel = new JSONModel({});
|
|
37
|
+
initializeCollaboration({
|
|
38
|
+
id: userID,
|
|
39
|
+
name: userName,
|
|
40
|
+
initialName: userName
|
|
41
|
+
}, webSocketBaseURL, sDraftUUID, this._internalModel, this._onMessageReceived.bind(this), true);
|
|
42
|
+
this._rootPath = oContext.getPath();
|
|
43
|
+
this._oModel = oContext.getModel();
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Checks if the ghost client has revieved a given message.
|
|
48
|
+
*
|
|
49
|
+
* @param message The message content to be looked for
|
|
50
|
+
* @returns True if the last recieved message matches the content
|
|
51
|
+
*/
|
|
52
|
+
checkReceived: function (message) {
|
|
53
|
+
if (!this._lastReceivedMessage) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
var found = (!message.userID || message.userID === this._lastReceivedMessage.userID) && (!message.userAction || message.userAction === this._lastReceivedMessage.userAction) && (!message.clientContent || message.clientContent === this._lastReceivedMessage.clientContent);
|
|
58
|
+
this._lastReceivedMessage = undefined; // reset history to avoid finding the same message twice
|
|
59
|
+
|
|
60
|
+
return found;
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Closes the ghost client and removes the user from the collaborative draft.
|
|
65
|
+
*/
|
|
66
|
+
leaveDraft: function () {
|
|
67
|
+
if (this._internalModel) {
|
|
68
|
+
endCollaboration(this._internalModel);
|
|
69
|
+
|
|
70
|
+
this._internalModel.destroy();
|
|
71
|
+
|
|
72
|
+
this._internalModel = undefined;
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Simulates that the user starts typing in an input (live change).
|
|
78
|
+
*
|
|
79
|
+
* @param sPropertyPath The path of the property being modified
|
|
80
|
+
*/
|
|
81
|
+
startLiveChange: function (sPropertyPath) {
|
|
82
|
+
if (this._internalModel) {
|
|
83
|
+
if (this._lockedPropertyPath) {
|
|
84
|
+
// Unlock previous property path
|
|
85
|
+
this.undoChange();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this._lockedPropertyPath = sPropertyPath;
|
|
89
|
+
broadcastCollaborationMessage(Activity.LiveChange, "".concat(this._rootPath, "/").concat(sPropertyPath), this._internalModel);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Simulates that the user has modified a property.
|
|
95
|
+
*
|
|
96
|
+
* @param sPropertyPath The path of the property being modified
|
|
97
|
+
* @param value The new value of the property being modified
|
|
98
|
+
*/
|
|
99
|
+
updatePropertyValue: function (sPropertyPath, value) {
|
|
100
|
+
var _this = this;
|
|
101
|
+
|
|
102
|
+
if (this._internalModel) {
|
|
103
|
+
if (this._lockedPropertyPath !== sPropertyPath) {
|
|
104
|
+
this.startLiveChange(sPropertyPath);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
var oContextBinding = this._oModel.bindContext(this._rootPath, undefined, {
|
|
108
|
+
$$patchWithoutSideEffects: true,
|
|
109
|
+
$$groupId: "$auto",
|
|
110
|
+
$$updateGroupId: "$auto"
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
var oPropertyBinding = this._oModel.bindProperty(sPropertyPath, oContextBinding.getBoundContext());
|
|
114
|
+
|
|
115
|
+
oPropertyBinding.requestValue().then(function () {
|
|
116
|
+
oPropertyBinding.setValue(value);
|
|
117
|
+
oContextBinding.attachEventOnce("patchCompleted", function () {
|
|
118
|
+
broadcastCollaborationMessage(Activity.Change, "".concat(_this._rootPath, "/").concat(sPropertyPath), _this._internalModel);
|
|
119
|
+
_this._lockedPropertyPath = "";
|
|
120
|
+
});
|
|
121
|
+
}).catch(function (err) {
|
|
122
|
+
Log.error(err);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Simulates that the user did an 'undo' (to be called after startLiveChange).
|
|
129
|
+
*/
|
|
130
|
+
undoChange: function () {
|
|
131
|
+
if (this._lockedPropertyPath) {
|
|
132
|
+
broadcastCollaborationMessage(Activity.Undo, "".concat(this._rootPath, "/").concat(this._lockedPropertyPath), this._internalModel);
|
|
133
|
+
this._lockedPropertyPath = "";
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Simulates that the user has discarded the draft.
|
|
139
|
+
*/
|
|
140
|
+
discardDraft: function () {
|
|
141
|
+
var _this2 = this;
|
|
142
|
+
|
|
143
|
+
if (this._internalModel) {
|
|
144
|
+
var draftContext = this._getDraftContext();
|
|
145
|
+
|
|
146
|
+
draftContext.requestProperty("IsActiveEntity").then(function () {
|
|
147
|
+
draft.deleteDraft(draftContext);
|
|
148
|
+
}).then(function () {
|
|
149
|
+
broadcastCollaborationMessage(Activity.Discard, _this2._rootPath.replace("IsActiveEntity=false", "IsActiveEntity=true"), _this2._internalModel);
|
|
150
|
+
|
|
151
|
+
_this2._internalModel.destroy();
|
|
152
|
+
|
|
153
|
+
_this2._internalModel = undefined;
|
|
154
|
+
}).catch(function (err) {
|
|
155
|
+
Log.error(err);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Simulates that the user has deleted the draft.
|
|
162
|
+
*/
|
|
163
|
+
deleteDraft: function () {
|
|
164
|
+
var _this3 = this;
|
|
165
|
+
|
|
166
|
+
if (this._internalModel) {
|
|
167
|
+
var draftContext = this._getDraftContext();
|
|
168
|
+
|
|
169
|
+
var activeContext;
|
|
170
|
+
draftContext.requestProperty("IsActiveEntity").then(function () {
|
|
171
|
+
return draftContext.getModel().bindContext("".concat(_this3._rootPath, "/SiblingEntity")).getBoundContext();
|
|
172
|
+
}).then(function (context) {
|
|
173
|
+
activeContext = context;
|
|
174
|
+
return context.requestCanonicalPath();
|
|
175
|
+
}).then(function () {
|
|
176
|
+
return draft.deleteDraft(draftContext);
|
|
177
|
+
}).then(function () {
|
|
178
|
+
activeContext.delete();
|
|
179
|
+
broadcastCollaborationMessage(Activity.Delete, _this3._rootPath, _this3._internalModel);
|
|
180
|
+
|
|
181
|
+
_this3._internalModel.destroy();
|
|
182
|
+
|
|
183
|
+
_this3._internalModel = undefined;
|
|
184
|
+
}).catch(function (err) {
|
|
185
|
+
Log.error(err);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
// /////////////////////////////
|
|
190
|
+
// Private methods
|
|
191
|
+
_getDraftContext: function () {
|
|
192
|
+
return this._oModel.bindContext(this._rootPath, undefined, {
|
|
193
|
+
$$patchWithoutSideEffects: true,
|
|
194
|
+
$$groupId: "$auto",
|
|
195
|
+
$$updateGroupId: "$auto"
|
|
196
|
+
}).getBoundContext();
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Callback of the ghost client when receiving a message on the web socket.
|
|
201
|
+
*
|
|
202
|
+
* @param oMessage The message
|
|
203
|
+
*/
|
|
204
|
+
_onMessageReceived: function (oMessage) {
|
|
205
|
+
oMessage.userAction = oMessage.userAction || oMessage.clientAction;
|
|
206
|
+
this._lastReceivedMessage = oMessage;
|
|
207
|
+
|
|
208
|
+
if (oMessage.userAction === Activity.Join) {
|
|
209
|
+
broadcastCollaborationMessage(Activity.JoinEcho, this._lockedPropertyPath ? "".concat(this._rootPath, "/").concat(this._lockedPropertyPath) : undefined, this._internalModel);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
return CollaborationAPI;
|
|
214
|
+
}, false);
|
|
215
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkNvbGxhYm9yYXRpb25BUEkudHMiXSwibmFtZXMiOlsiQ29sbGFib3JhdGlvbkFQSSIsIl9sYXN0UmVjZWl2ZWRNZXNzYWdlIiwidW5kZWZpbmVkIiwiX3Jvb3RQYXRoIiwiX29Nb2RlbCIsIl9sb2NrZWRQcm9wZXJ0eVBhdGgiLCJfaW50ZXJuYWxNb2RlbCIsImVudGVyRHJhZnQiLCJvQ29udGV4dCIsInVzZXJJRCIsInVzZXJOYW1lIiwid2ViU29ja2V0QmFzZVVSTCIsImdldE1vZGVsIiwiZ2V0TWV0YU1vZGVsIiwiZ2V0T2JqZWN0IiwiTG9nIiwiZXJyb3IiLCJzRHJhZnRVVUlEIiwiZ2V0UHJvcGVydHkiLCJKU09OTW9kZWwiLCJpbml0aWFsaXplQ29sbGFib3JhdGlvbiIsImlkIiwibmFtZSIsImluaXRpYWxOYW1lIiwiX29uTWVzc2FnZVJlY2VpdmVkIiwiYmluZCIsImdldFBhdGgiLCJjaGVja1JlY2VpdmVkIiwibWVzc2FnZSIsImZvdW5kIiwidXNlckFjdGlvbiIsImNsaWVudENvbnRlbnQiLCJsZWF2ZURyYWZ0IiwiZW5kQ29sbGFib3JhdGlvbiIsImRlc3Ryb3kiLCJzdGFydExpdmVDaGFuZ2UiLCJzUHJvcGVydHlQYXRoIiwidW5kb0NoYW5nZSIsImJyb2FkY2FzdENvbGxhYm9yYXRpb25NZXNzYWdlIiwiQWN0aXZpdHkiLCJMaXZlQ2hhbmdlIiwidXBkYXRlUHJvcGVydHlWYWx1ZSIsInZhbHVlIiwib0NvbnRleHRCaW5kaW5nIiwiYmluZENvbnRleHQiLCIkJHBhdGNoV2l0aG91dFNpZGVFZmZlY3RzIiwiJCRncm91cElkIiwiJCR1cGRhdGVHcm91cElkIiwib1Byb3BlcnR5QmluZGluZyIsImJpbmRQcm9wZXJ0eSIsImdldEJvdW5kQ29udGV4dCIsInJlcXVlc3RWYWx1ZSIsInRoZW4iLCJzZXRWYWx1ZSIsImF0dGFjaEV2ZW50T25jZSIsIkNoYW5nZSIsImNhdGNoIiwiZXJyIiwiVW5kbyIsImRpc2NhcmREcmFmdCIsImRyYWZ0Q29udGV4dCIsIl9nZXREcmFmdENvbnRleHQiLCJyZXF1ZXN0UHJvcGVydHkiLCJkcmFmdCIsImRlbGV0ZURyYWZ0IiwiRGlzY2FyZCIsInJlcGxhY2UiLCJhY3RpdmVDb250ZXh0IiwiY29udGV4dCIsInJlcXVlc3RDYW5vbmljYWxQYXRoIiwiZGVsZXRlIiwiRGVsZXRlIiwib01lc3NhZ2UiLCJjbGllbnRBY3Rpb24iLCJKb2luIiwiSm9pbkVjaG8iXSwibWFwcGluZ3MiOiI7QUFBQTtBQUNBO0FBQ0E7Ozs7Ozs7OztBQVdBLE1BQU1BLGdCQUFnQixHQUFHO0FBQ3hCQyxJQUFBQSxvQkFBb0IsRUFBRUMsU0FERTtBQUV4QkMsSUFBQUEsU0FBUyxFQUFFLEVBRmE7QUFHeEJDLElBQUFBLE9BQU8sRUFBRUYsU0FIZTtBQUl4QkcsSUFBQUEsbUJBQW1CLEVBQUUsRUFKRztBQUt4QkMsSUFBQUEsY0FBYyxFQUFFSixTQUxROztBQU94QjtBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNDSyxJQUFBQSxVQUFVLEVBQUUsVUFBVUMsUUFBVixFQUE2QkMsTUFBN0IsRUFBNkNDLFFBQTdDLEVBQStEO0FBQzFFLFVBQU1DLGdCQUF3QixHQUFHSCxRQUFRLENBQUNJLFFBQVQsR0FBb0JDLFlBQXBCLEdBQW1DQyxTQUFuQyxDQUE2QyxtREFBN0MsQ0FBakM7O0FBRUEsVUFBSSxDQUFDSCxnQkFBTCxFQUF1QjtBQUN0QkksUUFBQUEsR0FBRyxDQUFDQyxLQUFKLENBQVUseUNBQVY7QUFDQTtBQUNBOztBQUVELFVBQU1DLFVBQWtCLEdBQUdULFFBQVEsQ0FBQ1UsV0FBVCxDQUFxQixtQ0FBckIsQ0FBM0I7QUFDQSxXQUFLWixjQUFMLEdBQXNCLElBQUlhLFNBQUosQ0FBYyxFQUFkLENBQXRCO0FBRUFDLE1BQUFBLHVCQUF1QixDQUN0QjtBQUNDQyxRQUFBQSxFQUFFLEVBQUVaLE1BREw7QUFFQ2EsUUFBQUEsSUFBSSxFQUFFWixRQUZQO0FBR0NhLFFBQUFBLFdBQVcsRUFBRWI7QUFIZCxPQURzQixFQU10QkMs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LE1BQUksQ0FBQzVCLGNBQUwsR0FBc0JKLFNBQXRCO0FBQ0EsU0FqQkYsRUFrQkVzRCxLQWxCRixDQWtCUSxVQUFVQyxHQUFWLEVBQW9CO0FBQzFCMUMsVUFBQUEsR0FBRyxDQUFDQyxLQUFKLENBQVV5QyxHQUFWO0FBQ0EsU0FwQkY7QUFxQkE7QUFDRCxLQWhNdUI7QUFrTXhCO0FBQ0E7QUFFQUksSUFBQUEsZ0JBQWdCLEVBQUUsWUFBaUI7QUFDbEMsYUFBTyxLQUFLekQsT0FBTCxDQUFjd0MsV0FBZCxDQUEwQixLQUFLekMsU0FBL0IsRUFBMENELFNBQTFDLEVBQXFEO0FBQzNEMkMsUUFBQUEseUJBQXlCLEVBQUUsSUFEZ0M7QUFFM0RDLFFBQUFBLFNBQVMsRUFBRSxPQUZnRDtBQUczREMsUUFBQUEsZUFBZSxFQUFFO0FBSDBDLE9BQXJELEVBSUpHLGVBSkksRUFBUDtBQUtBLEtBM011Qjs7QUE2TXhCO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQzFCLElBQUFBLGtCQUFrQixFQUFFLFVBQVVnRCxRQUFWLEVBQTZCO0FBQ2hEQSxNQUFBQSxRQUFRLENBQUMxQyxVQUFULEdBQXNCMEMsUUFBUSxDQUFDMUMsVUFBVCxJQUF1QjBDLFFBQVEsQ0FBQ0MsWUFBdEQ7QUFDQSxXQUFLeEUsb0JBQUwsR0FBNEJ1RSxRQUE1Qjs7QUFFQSxVQUFJQSxRQUFRLENBQUMxQyxVQUFULEtBQXdCUyxRQUFRLENBQUNtQyxJQUFyQyxFQUEyQztBQUMxQ3BDLFFBQUFBLDZCQUE2QixDQUM1QkMsUUFBUSxDQUFDb0MsUUFEbUIsRUFFNUIsS0FBS3RFLG1CQUFMLGFBQThCLEtBQUtGLFNBQW5DLGNBQWdELEtBQUtFLG1CQUFyRCxJQUE2RUgsU0FGakQsRUFHNUIsS0FBS0ksY0FIdUIsQ0FBN0I7QUFLQTtBQUNEO0FBN051QixHQUF6QjtTQWdPZU4sZ0IiLCJzb3VyY2VSb290IjoiLiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBMb2cgZnJvbSBcInNhcC9iYXNlL0xvZ1wiO1xuaW1wb3J0IHtcblx0YnJvYWRjYXN0Q29sbGFib3JhdGlvbk1lc3NhZ2UsXG5cdGVuZENvbGxhYm9yYXRpb24sXG5cdGluaXRpYWxpemVDb2xsYWJvcmF0aW9uXG59IGZyb20gXCJzYXAvZmUvY29yZS9jb250cm9sbGVyZXh0ZW5zaW9ucy9jb2xsYWJvcmF0aW9uL0FjdGl2aXR5QmFzZVwiO1xuaW1wb3J0IHR5cGUgeyBNZXNzYWdlIH0gZnJvbSBcInNhcC9mZS9jb3JlL2NvbnRyb2xsZXJleHRlbnNpb25zL2NvbGxhYm9yYXRpb24vQ29sbGFib3JhdGlvbkNvbW1vblwiO1xuaW1wb3J0IHsgQWN0aXZpdHkgfSBmcm9tIFwic2FwL2ZlL2NvcmUvY29udHJvbGxlcmV4dGVuc2lvbnMvY29sbGFib3JhdGlvbi9Db2xsYWJvcmF0aW9uQ29tbW9uXCI7XG5pbXBvcnQgZHJhZnQgZnJvbSBcInNhcC9mZS9jb3JlL2NvbnRyb2xsZXJleHRlbnNpb25zL2VkaXRGbG93L2RyYWZ0XCI7XG5pbXBvcnQgdHlwZSBDb250ZXh0IGZyb20gXCJzYXAvdWkvbW9kZWwvQ29udGV4dFwiO1xuaW1wb3J0IEpTT05Nb2RlbCBmcm9tIFwic2FwL3VpL21vZGVsL2pzb24vSlNPTk1vZGVsXCI7XG5pbXBvcnQgdHlwZSBPRGF0YU1vZGVsIGZyb20gXCJzYXAvdWkvbW9kZWwvb2RhdGEvdjQvT0RhdGFNb2RlbFwiO1xuXG5jb25zdCBDb2xsYWJvcmF0aW9uQVBJID0ge1xuXHRfbGFzdFJlY2VpdmVkTWVzc2FnZTogdW5kZWZpbmVkIGFzIE1lc3NhZ2UgfCB1bmRlZmluZWQsXG5cdF9yb290UGF0aDogXCJcIixcblx0X29Nb2RlbDogdW5kZWZpbmVkIGFzIE9EYXRhTW9kZWwgfCB1bmRlZmluZWQsXG5cdF9sb2NrZWRQcm9wZXJ0eVBhdGg6IFwiXCIsXG5cdF9pbnRlcm5hbE1vZGVsOiB1bmRlZmluZWQgYXMgSlNPTk1vZGVsIHwgdW5kZWZpbmVkLFxuXG5cdC8qKlxuXHQgKiBPcGVuIGFuIGV4aXN0aW5nIGNvbGxhYm9yYXRpdmUgZHJhZnQgd2l0aCBhIG5ldyB1c2VyLCBhbmQgY3JlYXRlcyBhICdnaG9zdCBjbGllbnQnIGZvciB0aGlzIHVzZXIuXG5cdCAqXG5cdCAqIEBwYXJhbSBvQ29udGV4dCBUaGUgY29udGV4dCBvZiB0aGUgY29sbGFib3JhdGl2ZSBkcmFmdFxuXHQgKiBAcGFyYW0gdXNlcklEIFRoZSBJRCBvZiB0aGUgdXNlclxuXHQgKiBAcGFyYW0gdXNlck5hbWUgVGhlIG5hbWUgb2YgdGhlIHVzZXJcblx0ICovXG5cdGVudGVyRHJhZnQ6IGZ1bmN0aW9uIChvQ29udGV4dDogQ29udGV4dCwgdXNlcklEOiBzdHJpbmcsIHVzZXJOYW1lOiBzdHJpbmcpIHtcblx0XHRjb25zdCB3ZWJTb2NrZXRCYXNlVVJMOiBzdHJpbmcgPSBvQ29udGV4dC5nZXRNb2RlbCgpLmdldE1ldGFNb2RlbCgpLmdldE9iamVjdChcIi9AY29tLnNhcC52b2NhYnVsYXJpZXMuQ29tbW9uLnYxLldlYlNvY2tldEJhc2VVUkxcIik7XG5cblx0XHRpZiAoIXdlYlNvY2tldEJhc2VVUkwpIHtcblx0XHRcdExvZy5lcnJvcihcIkNhbm5vdCBmaW5kIFdlYlNvY2tldEJhc2VVUkwgYW5ub3RhdGlvblwiKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRjb25zdCBzRHJhZnRVVUlEOiBzdHJpbmcgPSBvQ29udGV4dC5nZXRQcm9wZXJ0eShcIkRyYWZ0QWRtaW5pc3RyYXRpdmVEYXRhL0RyYWZ0VVVJRFwiKTtcblx0XHR0aGlzLl9pbnRlcm5hbE1vZGVsID0gbmV3IEpTT05Nb2RlbCh7fSk7XG5cblx0XHRpbml0aWFsaXplQ29sbGFib3JhdGlvbihcblx0XHRcdHtcblx0XHRcdFx0aWQ6IHVzZXJJRCxcblx0XHRcdFx0bmFtZTogdXNlck5hbWUsXG5cdFx0XHRcdGluaXRpYWxOYW1lOiB1c2VyTmFtZVxuXHRcdFx0fSxcblx0XHRcdHdlYlNvY2tldEJhc2VVUkwsXG5cdFx0XHRzRHJhZnRVVUlELFxuXHRcdFx0dGhpcy5faW50ZXJuYWxNb2RlbCxcblx0XHRcdHRoaXMuX29uTWVzc2FnZVJlY2VpdmVkLmJpbmQodGhpcyksXG5cdFx0XHR0cnVlXG5cdFx0KTtcblxuXHRcdHRoaXMuX3Jvb3RQYXRoID0gb0NvbnRleHQuZ2V0UGF0aCgpO1xuXHRcdHRoaXMuX29Nb2RlbCA9IG9Db250ZXh0LmdldE1vZGVsKCkgYXMgT0RhdGFNb2RlbDtcblx0fSxcblxuXHQvKipcblx0ICogQ2hlY2tzIGlmIHRoZSBnaG9zdCBjbGllbnQgaGFzIHJldmlldmVkIGEgZ2l2ZW4gbWVzc2FnZS5cblx0ICpcblx0ICogQHBhcmFtIG1lc3NhZ2UgVGhlIG1lc3NhZ2UgY29udGVudCB0byBiZSBsb29rZWQgZm9yXG5cdCAqIEByZXR1cm5zIFRydWUgaWYgdGhlIGxhc3QgcmVjaWV2ZWQgbWVzc2FnZSBtYXRjaGVzIHRoZSBjb250ZW50XG5cdCAqL1xuXHRjaGVja1JlY2VpdmVkOiBmdW5jdGlvbiAobWVzc2FnZTogUGFydGlhbDxNZXNzYWdlPik6IGJvb2xlYW4ge1xuXHRcdGlmICghdGhpcy5fbGFzdFJlY2VpdmVkTWVzc2FnZSkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdGNvbnN0IGZvdW5kID1cblx0XHRcdCghbWVzc2FnZS51c2VySUQgfHwgbWVzc2FnZS51c2VySUQgPT09IHRoaXMuX2xhc3RSZWNlaXZlZE1lc3NhZ2UudXNlcklEKSAmJlxuXHRcdFx0KCFtZXNzYWdlLnVzZXJBY3Rpb24gfHwgbWVzc2FnZS51c2VyQWN0aW9uID09PSB0aGlzLl9sYXN0UmVjZWl2ZWRNZXNzYWdlLnVzZXJBY3Rpb24pICYmXG5cdFx0XHQoIW1lc3NhZ2UuY2xpZW50Q29udGVudCB8fCBtZXNzYWdlLmNsaWVudENvbnRlbnQgPT09IHRoaXMuX2xhc3RSZWNlaXZlZE1lc3NhZ2UuY2xpZW50Q29udGVudCk7XG5cblx0XHR0aGlzLl9sYXN0UmVjZWl2ZWRNZXNzYWdlID0gdW5kZWZpbmVkOyAvLyByZXNldCBoaXN0b3J5IHRvIGF2b2lkIGZpbmRpbmcgdGhlIHNhbWUgbWVzc2FnZSB0d2ljZVxuXG5cdFx0cmV0dXJuIGZvdW5kO1xuXHR9LFxuXG5cdC8qKlxuXHQgKiBDbG9zZXMgdGhlIGdob3N0IGNsaWVudCBhbmQgcmVtb3ZlcyB0aGUgdXNlciBmcm9tIHRoZSBjb2xsYWJvcmF0aXZlIGRyYWZ0LlxuXHQgKi9cblx0bGVhdmVEcmFmdDogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl9pbnRlcm5hbE1vZGVsKSB7XG5cdFx0XHRlbmRDb2xsYWJvcmF0aW9uKHRoaXMuX2ludGVybmFsTW9kZWwpO1xuXHRcdFx0dGhpcy5faW50ZXJuYWxNb2RlbC5kZXN0cm95KCk7XG5cdFx0XHR0aGlzLl9pbnRlcm5hbE1vZGVsID0gdW5kZWZpbmVkO1xuXHRcdH1cblx0fSxcblxuXHQvKipcblx0ICogU2ltdWxhdGVzIHRoYXQgdGhlIHVzZXIgc3RhcnRzIHR5cGluZyBpbiBhbiBpbnB1dCAobGl2ZSBjaGFuZ2UpLlxuXHQgKlxuXHQgKiBAcGFyYW0gc1Byb3BlcnR5UGF0aCBUaGUgcGF0aCBvZiB0aGUgcHJvcGVydHkgYmVpbmcgbW9kaWZpZWRcblx0ICovXG5cdHN0YXJ0TGl2ZUNoYW5nZTogZnVuY3Rpb24gKHNQcm9wZXJ0eVBhdGg6IHN0cmluZykge1xuXHRcdGlmICh0aGlzLl9pbnRlcm5hbE1vZGVsKSB7XG5cdFx0XHRpZiAodGhpcy5fbG9ja2VkUHJvcGVydHlQYXRoKSB7XG5cdFx0XHRcdC8vIFVubG9jayBwcmV2aW91cyBwcm9wZXJ0eSBwYXRoXG5cdFx0XHRcdHRoaXMudW5kb0NoYW5nZSgpO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5fbG9ja2VkUHJvcGVydHlQYXRoID0gc1Byb3BlcnR5UGF0aDtcblx0XHRcdGJyb2FkY2FzdENvbGxhYm9yYXRpb25NZXNzYWdlKEFjdGl2aXR5LkxpdmVDaGFuZ2UsIGAke3RoaXMuX3Jvb3RQYXRofS8ke3NQcm9wZXJ0eVBhdGh9YCwgdGhpcy5faW50ZXJuYWxNb2RlbCk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qKlxuXHQgKiBTaW11bGF0ZXMgdGhhdCB0aGUgdXNlciBoYXMgbW9kaWZpZWQgYSBwcm9wZXJ0eS5cblx0ICpcblx0ICogQHBhcmFtIHNQcm9wZXJ0eVBhdGggVGhlIHBhdGggb2YgdGhlIHByb3BlcnR5IGJlaW5nIG1vZGlmaWVkXG5cdCAqIEBwYXJhbSB2YWx1ZSBUaGUgbmV3IHZhbHVlIG9mIHRoZSBwcm9wZXJ0eSBiZWluZyBtb2RpZmllZFxuXHQgKi9cblx0dXBkYXRlUHJvcGVydHlWYWx1ZTogZnVuY3Rpb24gKHNQcm9wZXJ0eVBhdGg6IHN0cmluZywgdmFsdWU6IGFueSkge1xuXHRcdGlmICh0aGlzLl9pbnRlcm5hbE1vZGVsKSB7XG5cdFx0XHRpZiAodGhpcy5fbG9ja2VkUHJvcGVydHlQYXRoICE9PSBzUHJvcGVydHlQYXRoKSB7XG5cdFx0XHRcdHRoaXMuc3RhcnRMaXZlQ2hhbmdlKHNQcm9wZXJ0eVBhdGgpO1xuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBvQ29udGV4dEJpbmRpbmcgPSB0aGlzLl9vTW9kZWwhLmJpbmRDb250ZXh0KHRoaXMuX3Jvb3RQYXRoLCB1bmRlZmluZWQsIHtcblx0XHRcdFx0JCRwYXRjaFdpdGhvdXRTaWRlRWZmZWN0czogdHJ1ZSxcblx0XHRcdFx0JCRncm91cElkOiBcIiRhdXRvXCIsXG5cdFx0XHRcdCQkdXBkYXRlR3JvdXBJZDogXCIkYXV0b1wiXG5cdFx0XHR9KTtcblxuXHRcdFx0Y29uc3Qgb1Byb3BlcnR5QmluZGluZyA9IHRoaXMuX29Nb2RlbCEuYmluZFByb3BlcnR5KHNQcm9wZXJ0eVBhdGgsIG9Db250ZXh0QmluZGluZy5nZXRCb3VuZENvbnRleHQoKSk7XG5cblx0XHRcdG9Qcm9wZXJ0eUJpbmRpbmdcblx0XHRcdFx0LnJlcXVlc3RWYWx1ZSgpXG5cdFx0XHRcdC50aGVuKCgpID0+IHtcblx0XHRcdFx0XHRvUHJvcGVydHlCaW5kaW5nLnNldFZhbHVlKHZhbHVlKTtcblx0XHRcdFx0XHRvQ29udGV4dEJpbmRpbmcuYXR0YWNoRXZlbnRPbmNlKFwicGF0Y2hDb21wbGV0ZWRcIiwgKCkgPT4ge1xuXHRcdFx0XHRcdFx0YnJvYWRjYXN0Q29sbGFib3JhdGlvbk1lc3NhZ2UoQWN0aXZpdHkuQ2hhbmdlLCBgJHt0aGlzLl9yb290UGF0aH0vJHtzUHJvcGVydHlQYXRofWAsIHRoaXMuX2ludGVybmFsTW9kZWwhKTtcblx0XHRcdFx0XHRcdHRoaXMuX2xvY2tlZFByb3BlcnR5UGF0aCA9IFwiXCI7XG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH0pXG5cdFx0XHRcdC5jYXRjaChmdW5jdGlvbiAoZXJyKSB7XG5cdFx0XHRcdFx0TG9nLmVycm9yKGVycik7XG5cdFx0XHRcdH0pO1xuXHRcdH1cblx0fSxcblxuXHQvKipcblx0ICogU2ltdWxhdGVzIHRoYXQgdGhlIHVzZXIgZGlkIGFuICd1bmRvJyAodG8gYmUgY2FsbGVkIGFmdGVyIHN0YXJ0TGl2ZUNoYW5nZSkuXG5cdCAqL1xuXHR1bmRvQ2hhbmdlOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX2xvY2tlZFByb3BlcnR5UGF0aCkge1xuXHRcdFx0YnJvYWRjYXN0Q29sbGFib3JhdGlvbk1lc3NhZ2UoQWN0aXZpdHkuVW5kbywgYCR7dGhpcy5fcm9vdFBhdGh9LyR7dGhpcy5fbG9ja2VkUHJvcGVydHlQYXRofWAsIHRoaXMuX2ludGVybmFsTW9kZWwhKTtcblx0XHRcdHRoaXMuX2xvY2tlZFByb3BlcnR5UGF0aCA9IFwiXCI7XG5cdFx0fVxuXHR9LFxuXG5cdC8qKlxuXHQgKiBTaW11bGF0ZXMgdGhhdCB0aGUgdXNlciBoYXMgZGlzY2FyZGVkIHRoZSBkcmFmdC5cblx0ICovXG5cdGRpc2NhcmREcmFmdDogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl9pbnRlcm5hbE1vZGVsKSB7XG5cdFx0XHRjb25zdCBkcmFmdENvbnRleHQgPSB0aGlzLl9nZXREcmFmdENvbnRleHQoKTtcblxuXHRcdFx0ZHJhZnRDb250ZXh0XG5cdFx0XHRcdC5yZXF1ZXN0UHJvcGVydHkoXCJJc0FjdGl2ZUVudGl0eVwiKVxuXHRcdFx0XHQudGhlbigoKSA9PiB7XG5cdFx0XHRcdFx0ZHJhZnQuZGVsZXRlRHJhZnQoZHJhZnRDb250ZXh0KTtcblx0XHRcdFx0fSlcblx0XHRcdFx0LnRoZW4oKCkgPT4ge1xuXHRcdFx0XHRcdGJyb2FkY2FzdENvbGxhYm9yYXRpb25NZXNzYWdlKFxuXHRcdFx0XHRcdFx0QWN0aXZpdHkuRGlzY2FyZCxcblx0XHRcdFx0XHRcdHRoaXMuX3Jvb3RQYXRoLnJlcGxhY2UoXCJJc0FjdGl2ZUVudGl0eT1mYWxzZVwiLCBcIklzQWN0aXZlRW50aXR5PXRydWVcIiksXG5cdFx0XHRcdFx0XHR0aGlzLl9pbnRlcm5hbE1vZGVsIVxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0dGhpcy5faW50ZXJuYWxNb2RlbCEuZGVzdHJveSgpO1xuXHRcdFx0XHRcdHRoaXMuX2ludGVybmFsTW9kZWwgPSB1bmRlZmluZWQ7XG5cdFx0XHRcdH0pXG5cdFx0XHRcdC5jYXRjaChmdW5jdGlvbiAoZXJyOiBhbnkpIHtcblx0XHRcdFx0XHRMb2cuZXJyb3IoZXJyKTtcblx0XHRcdFx0fSk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qKlxuXHQgKiBTaW11bGF0ZXMgdGhhdCB0aGUgdXNlciBoYXMgZGVsZXRlZCB0aGUgZHJhZnQuXG5cdCAqL1xuXHRkZWxldGVEcmFmdDogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl9pbnRlcm5hbE1vZGVsKSB7XG5cdFx0XHRjb25zdCBkcmFmdENvbnRleHQgPSB0aGlzLl9nZXREcmFmdENvbnRleHQoKTtcblx0XHRcdGxldCBhY3RpdmVDb250ZXh0OiBDb250ZXh0O1xuXG5cdFx0XHRkcmFmdENvbnRleHRcblx0XHRcdFx0LnJlcXVlc3RQcm9wZXJ0eShcIklzQWN0aXZlRW50aXR5XCIpXG5cdFx0XHRcdC50aGVuKCgpID0+IHtcblx0XHRcdFx0XHRyZXR1cm4gZHJhZnRDb250ZXh0LmdldE1vZGVsKCkuYmluZENvbnRleHQoYCR7dGhpcy5fcm9vdFBhdGh9L1NpYmxpbmdFbnRpdHlgKS5nZXRCb3VuZENvbnRleHQoKTtcblx0XHRcdFx0fSlcblx0XHRcdFx0LnRoZW4oKGNvbnRleHQ6IGFueSkgPT4ge1xuXHRcdFx0XHRcdGFjdGl2ZUNvbnRleHQgPSBjb250ZXh0O1xuXHRcdFx0XHRcdHJldHVybiBjb250ZXh0LnJlcXVlc3RDYW5vbmljYWxQYXRoKCk7XG5cdFx0XHRcdH0pXG5cdFx0XHRcdC50aGVuKCgpID0+IHtcblx0XHRcdFx0XHRyZXR1cm4gZHJhZnQuZGVsZXRlRHJhZnQoZHJhZnRDb250ZXh0KTtcblx0XHRcdFx0fSlcblx0XHRcdFx0LnRoZW4oKCkgPT4ge1xuXHRcdFx0XHRcdChhY3RpdmVDb250ZXh0IGFzIGFueSkuZGVsZXRlKCk7XG5cdFx0XHRcdFx0YnJvYWRjYXN0Q29sbGFib3JhdGlvbk1lc3NhZ2UoQWN0aXZpdHkuRGVsZXRlLCB0aGlzLl9yb290UGF0aCwgdGhpcy5faW50ZXJuYWxNb2RlbCEpO1xuXHRcdFx0XHRcdHRoaXMuX2ludGVybmFsTW9kZWwhLmRlc3Ryb3koKTtcblx0XHRcdFx0XHR0aGlzLl9pbnRlcm5hbE1vZGVsID0gdW5kZWZpbmVkO1xuXHRcdFx0XHR9KVxuXHRcdFx0XHQuY2F0Y2goZnVuY3Rpb24gKGVycjogYW55KSB7XG5cdFx0XHRcdFx0TG9nLmVycm9yKGVycik7XG5cdFx0XHRcdH0pO1xuXHRcdH1cblx0fSxcblxuXHQvLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXHQvLyBQcml2YXRlIG1ldGhvZHNcblxuXHRfZ2V0RHJhZnRDb250ZXh0OiBmdW5jdGlvbiAoKTogYW55IHtcblx0XHRyZXR1cm4gdGhpcy5fb01vZGVsIS5iaW5kQ29udGV4dCh0aGlzLl9yb290UGF0aCwgdW5kZWZpbmVkLCB7XG5cdFx0XHQkJHBhdGNoV2l0aG91dFNpZGVFZmZlY3RzOiB0cnVlLFxuXHRcdFx0JCRncm91cElkOiBcIiRhdXRvXCIsXG5cdFx0XHQkJHVwZGF0ZUdyb3VwSWQ6IFwiJGF1dG9cIlxuXHRcdH0pLmdldEJvdW5kQ29udGV4dCgpO1xuXHR9LFxuXG5cdC8qKlxuXHQgKiBDYWxsYmFjayBvZiB0aGUgZ2hvc3QgY2xpZW50IHdoZW4gcmVjZWl2aW5nIGEgbWVzc2FnZSBvbiB0aGUgd2ViIHNvY2tldC5cblx0ICpcblx0ICogQHBhcmFtIG9NZXNzYWdlIFRoZSBtZXNzYWdlXG5cdCAqL1xuXHRfb25NZXNzYWdlUmVjZWl2ZWQ6IGZ1bmN0aW9uIChvTWVzc2FnZTogTWVzc2FnZSkge1xuXHRcdG9NZXNzYWdlLnVzZXJBY3Rpb24gPSBvTWVzc2FnZS51c2VyQWN0aW9uIHx8IG9NZXNzYWdlLmNsaWVudEFjdGlvbjtcblx0XHR0aGlzLl9sYXN0UmVjZWl2ZWRNZXNzYWdlID0gb01lc3NhZ2U7XG5cblx0XHRpZiAob01lc3NhZ2UudXNlckFjdGlvbiA9PT0gQWN0aXZpdHkuSm9pbikge1xuXHRcdFx0YnJvYWRjYXN0Q29sbGFib3JhdGlvbk1lc3NhZ2UoXG5cdFx0XHRcdEFjdGl2aXR5LkpvaW5FY2hvLFxuXHRcdFx0XHR0aGlzLl9sb2NrZWRQcm9wZXJ0eVBhdGggPyBgJHt0aGlzLl9yb290UGF0aH0vJHt0aGlzLl9sb2NrZWRQcm9wZXJ0eVBhdGh9YCA6IHVuZGVmaW5lZCxcblx0XHRcdFx0dGhpcy5faW50ZXJuYWxNb2RlbCFcblx0XHRcdCk7XG5cdFx0fVxuXHR9XG59O1xuXG5leHBvcnQgZGVmYXVsdCBDb2xsYWJvcmF0aW9uQVBJO1xuIl19
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import Log from "sap/base/Log";
|
|
2
|
+
import {
|
|
3
|
+
broadcastCollaborationMessage,
|
|
4
|
+
endCollaboration,
|
|
5
|
+
initializeCollaboration
|
|
6
|
+
} from "sap/fe/core/controllerextensions/collaboration/ActivityBase";
|
|
7
|
+
import type { Message } from "sap/fe/core/controllerextensions/collaboration/CollaborationCommon";
|
|
8
|
+
import { Activity } from "sap/fe/core/controllerextensions/collaboration/CollaborationCommon";
|
|
9
|
+
import draft from "sap/fe/core/controllerextensions/editFlow/draft";
|
|
10
|
+
import type Context from "sap/ui/model/Context";
|
|
11
|
+
import JSONModel from "sap/ui/model/json/JSONModel";
|
|
12
|
+
import type ODataModel from "sap/ui/model/odata/v4/ODataModel";
|
|
13
|
+
|
|
14
|
+
const CollaborationAPI = {
|
|
15
|
+
_lastReceivedMessage: undefined as Message | undefined,
|
|
16
|
+
_rootPath: "",
|
|
17
|
+
_oModel: undefined as ODataModel | undefined,
|
|
18
|
+
_lockedPropertyPath: "",
|
|
19
|
+
_internalModel: undefined as JSONModel | undefined,
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Open an existing collaborative draft with a new user, and creates a 'ghost client' for this user.
|
|
23
|
+
*
|
|
24
|
+
* @param oContext The context of the collaborative draft
|
|
25
|
+
* @param userID The ID of the user
|
|
26
|
+
* @param userName The name of the user
|
|
27
|
+
*/
|
|
28
|
+
enterDraft: function (oContext: Context, userID: string, userName: string) {
|
|
29
|
+
const webSocketBaseURL: string = oContext.getModel().getMetaModel().getObject("/@com.sap.vocabularies.Common.v1.WebSocketBaseURL");
|
|
30
|
+
|
|
31
|
+
if (!webSocketBaseURL) {
|
|
32
|
+
Log.error("Cannot find WebSocketBaseURL annotation");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const sDraftUUID: string = oContext.getProperty("DraftAdministrativeData/DraftUUID");
|
|
37
|
+
this._internalModel = new JSONModel({});
|
|
38
|
+
|
|
39
|
+
initializeCollaboration(
|
|
40
|
+
{
|
|
41
|
+
id: userID,
|
|
42
|
+
name: userName,
|
|
43
|
+
initialName: userName
|
|
44
|
+
},
|
|
45
|
+
webSocketBaseURL,
|
|
46
|
+
sDraftUUID,
|
|
47
|
+
this._internalModel,
|
|
48
|
+
this._onMessageReceived.bind(this),
|
|
49
|
+
true
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
this._rootPath = oContext.getPath();
|
|
53
|
+
this._oModel = oContext.getModel() as ODataModel;
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Checks if the ghost client has revieved a given message.
|
|
58
|
+
*
|
|
59
|
+
* @param message The message content to be looked for
|
|
60
|
+
* @returns True if the last recieved message matches the content
|
|
61
|
+
*/
|
|
62
|
+
checkReceived: function (message: Partial<Message>): boolean {
|
|
63
|
+
if (!this._lastReceivedMessage) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const found =
|
|
68
|
+
(!message.userID || message.userID === this._lastReceivedMessage.userID) &&
|
|
69
|
+
(!message.userAction || message.userAction === this._lastReceivedMessage.userAction) &&
|
|
70
|
+
(!message.clientContent || message.clientContent === this._lastReceivedMessage.clientContent);
|
|
71
|
+
|
|
72
|
+
this._lastReceivedMessage = undefined; // reset history to avoid finding the same message twice
|
|
73
|
+
|
|
74
|
+
return found;
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Closes the ghost client and removes the user from the collaborative draft.
|
|
79
|
+
*/
|
|
80
|
+
leaveDraft: function () {
|
|
81
|
+
if (this._internalModel) {
|
|
82
|
+
endCollaboration(this._internalModel);
|
|
83
|
+
this._internalModel.destroy();
|
|
84
|
+
this._internalModel = undefined;
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Simulates that the user starts typing in an input (live change).
|
|
90
|
+
*
|
|
91
|
+
* @param sPropertyPath The path of the property being modified
|
|
92
|
+
*/
|
|
93
|
+
startLiveChange: function (sPropertyPath: string) {
|
|
94
|
+
if (this._internalModel) {
|
|
95
|
+
if (this._lockedPropertyPath) {
|
|
96
|
+
// Unlock previous property path
|
|
97
|
+
this.undoChange();
|
|
98
|
+
}
|
|
99
|
+
this._lockedPropertyPath = sPropertyPath;
|
|
100
|
+
broadcastCollaborationMessage(Activity.LiveChange, `${this._rootPath}/${sPropertyPath}`, this._internalModel);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Simulates that the user has modified a property.
|
|
106
|
+
*
|
|
107
|
+
* @param sPropertyPath The path of the property being modified
|
|
108
|
+
* @param value The new value of the property being modified
|
|
109
|
+
*/
|
|
110
|
+
updatePropertyValue: function (sPropertyPath: string, value: any) {
|
|
111
|
+
if (this._internalModel) {
|
|
112
|
+
if (this._lockedPropertyPath !== sPropertyPath) {
|
|
113
|
+
this.startLiveChange(sPropertyPath);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const oContextBinding = this._oModel!.bindContext(this._rootPath, undefined, {
|
|
117
|
+
$$patchWithoutSideEffects: true,
|
|
118
|
+
$$groupId: "$auto",
|
|
119
|
+
$$updateGroupId: "$auto"
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const oPropertyBinding = this._oModel!.bindProperty(sPropertyPath, oContextBinding.getBoundContext());
|
|
123
|
+
|
|
124
|
+
oPropertyBinding
|
|
125
|
+
.requestValue()
|
|
126
|
+
.then(() => {
|
|
127
|
+
oPropertyBinding.setValue(value);
|
|
128
|
+
oContextBinding.attachEventOnce("patchCompleted", () => {
|
|
129
|
+
broadcastCollaborationMessage(Activity.Change, `${this._rootPath}/${sPropertyPath}`, this._internalModel!);
|
|
130
|
+
this._lockedPropertyPath = "";
|
|
131
|
+
});
|
|
132
|
+
})
|
|
133
|
+
.catch(function (err) {
|
|
134
|
+
Log.error(err);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Simulates that the user did an 'undo' (to be called after startLiveChange).
|
|
141
|
+
*/
|
|
142
|
+
undoChange: function () {
|
|
143
|
+
if (this._lockedPropertyPath) {
|
|
144
|
+
broadcastCollaborationMessage(Activity.Undo, `${this._rootPath}/${this._lockedPropertyPath}`, this._internalModel!);
|
|
145
|
+
this._lockedPropertyPath = "";
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Simulates that the user has discarded the draft.
|
|
151
|
+
*/
|
|
152
|
+
discardDraft: function () {
|
|
153
|
+
if (this._internalModel) {
|
|
154
|
+
const draftContext = this._getDraftContext();
|
|
155
|
+
|
|
156
|
+
draftContext
|
|
157
|
+
.requestProperty("IsActiveEntity")
|
|
158
|
+
.then(() => {
|
|
159
|
+
draft.deleteDraft(draftContext);
|
|
160
|
+
})
|
|
161
|
+
.then(() => {
|
|
162
|
+
broadcastCollaborationMessage(
|
|
163
|
+
Activity.Discard,
|
|
164
|
+
this._rootPath.replace("IsActiveEntity=false", "IsActiveEntity=true"),
|
|
165
|
+
this._internalModel!
|
|
166
|
+
);
|
|
167
|
+
this._internalModel!.destroy();
|
|
168
|
+
this._internalModel = undefined;
|
|
169
|
+
})
|
|
170
|
+
.catch(function (err: any) {
|
|
171
|
+
Log.error(err);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Simulates that the user has deleted the draft.
|
|
178
|
+
*/
|
|
179
|
+
deleteDraft: function () {
|
|
180
|
+
if (this._internalModel) {
|
|
181
|
+
const draftContext = this._getDraftContext();
|
|
182
|
+
let activeContext: Context;
|
|
183
|
+
|
|
184
|
+
draftContext
|
|
185
|
+
.requestProperty("IsActiveEntity")
|
|
186
|
+
.then(() => {
|
|
187
|
+
return draftContext.getModel().bindContext(`${this._rootPath}/SiblingEntity`).getBoundContext();
|
|
188
|
+
})
|
|
189
|
+
.then((context: any) => {
|
|
190
|
+
activeContext = context;
|
|
191
|
+
return context.requestCanonicalPath();
|
|
192
|
+
})
|
|
193
|
+
.then(() => {
|
|
194
|
+
return draft.deleteDraft(draftContext);
|
|
195
|
+
})
|
|
196
|
+
.then(() => {
|
|
197
|
+
(activeContext as any).delete();
|
|
198
|
+
broadcastCollaborationMessage(Activity.Delete, this._rootPath, this._internalModel!);
|
|
199
|
+
this._internalModel!.destroy();
|
|
200
|
+
this._internalModel = undefined;
|
|
201
|
+
})
|
|
202
|
+
.catch(function (err: any) {
|
|
203
|
+
Log.error(err);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
// /////////////////////////////
|
|
209
|
+
// Private methods
|
|
210
|
+
|
|
211
|
+
_getDraftContext: function (): any {
|
|
212
|
+
return this._oModel!.bindContext(this._rootPath, undefined, {
|
|
213
|
+
$$patchWithoutSideEffects: true,
|
|
214
|
+
$$groupId: "$auto",
|
|
215
|
+
$$updateGroupId: "$auto"
|
|
216
|
+
}).getBoundContext();
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Callback of the ghost client when receiving a message on the web socket.
|
|
221
|
+
*
|
|
222
|
+
* @param oMessage The message
|
|
223
|
+
*/
|
|
224
|
+
_onMessageReceived: function (oMessage: Message) {
|
|
225
|
+
oMessage.userAction = oMessage.userAction || oMessage.clientAction;
|
|
226
|
+
this._lastReceivedMessage = oMessage;
|
|
227
|
+
|
|
228
|
+
if (oMessage.userAction === Activity.Join) {
|
|
229
|
+
broadcastCollaborationMessage(
|
|
230
|
+
Activity.JoinEcho,
|
|
231
|
+
this._lockedPropertyPath ? `${this._rootPath}/${this._lockedPropertyPath}` : undefined,
|
|
232
|
+
this._internalModel!
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
export default CollaborationAPI;
|
|
@@ -11,7 +11,7 @@ sap.ui.define(
|
|
|
11
11
|
"sap/fe/test/builder/MdcFieldBuilder",
|
|
12
12
|
"sap/fe/test/builder/DialogBuilder"
|
|
13
13
|
],
|
|
14
|
-
function(BaseAPI, Utils, FEBuilder, MdcFieldBuilder, DialogBuilder) {
|
|
14
|
+
function (BaseAPI, Utils, FEBuilder, MdcFieldBuilder, DialogBuilder) {
|
|
15
15
|
"use strict";
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -19,12 +19,12 @@ sap.ui.define(
|
|
|
19
19
|
*
|
|
20
20
|
* @param {sap.fe.test.builder.DialogBuilder} oDialogBuilder The {@link sap.fe.test.builder.DialogBuilder} instance used to interact with the UI
|
|
21
21
|
* @param {string} [vDialogDescription] Description (optional) of the dialog to be used for logging messages
|
|
22
|
-
* @param {
|
|
22
|
+
* @param {number} [iConfirmButtonIndex] Index of the 'confirm' button in the button aggregation; the default setting is 0 (first button from the left)
|
|
23
23
|
* @returns {sap.fe.test.api.DialogAPI} The new instance
|
|
24
24
|
* @class
|
|
25
25
|
* @private
|
|
26
26
|
*/
|
|
27
|
-
var DialogAPI = function(oDialogBuilder, vDialogDescription, iConfirmButtonIndex) {
|
|
27
|
+
var DialogAPI = function (oDialogBuilder, vDialogDescription, iConfirmButtonIndex) {
|
|
28
28
|
if (!Utils.isOfType(oDialogBuilder, DialogBuilder)) {
|
|
29
29
|
throw new Error("oDialogBuilder parameter must be a DialogBuilder instance");
|
|
30
30
|
}
|
|
@@ -40,12 +40,10 @@ sap.ui.define(
|
|
|
40
40
|
*
|
|
41
41
|
* @param {sap.fe.test.api.FieldIdentifier | string} vFieldIdentifier Identifier to be used for the matcher
|
|
42
42
|
* @param {object} oDialogIdentifier Identifier for the dialog (create/action)
|
|
43
|
-
*
|
|
44
43
|
* @returns {object} A matcher
|
|
45
|
-
*
|
|
46
44
|
* @private
|
|
47
45
|
*/
|
|
48
|
-
DialogAPI.prototype._createFieldMatcher = function(vFieldIdentifier, oDialogIdentifier) {
|
|
46
|
+
DialogAPI.prototype._createFieldMatcher = function (vFieldIdentifier, oDialogIdentifier) {
|
|
49
47
|
var vMatcher, sFieldId;
|
|
50
48
|
if (!Utils.isOfType(vFieldIdentifier, String)) {
|
|
51
49
|
if (typeof vFieldIdentifier.property === "string") {
|
|
@@ -67,7 +65,7 @@ sap.ui.define(
|
|
|
67
65
|
return vMatcher;
|
|
68
66
|
};
|
|
69
67
|
|
|
70
|
-
DialogAPI.prototype._createFieldBuilder = function(vFieldIdentifier, oDialogIdentifier) {
|
|
68
|
+
DialogAPI.prototype._createFieldBuilder = function (vFieldIdentifier, oDialogIdentifier) {
|
|
71
69
|
var oMdcFieldBuilder = new MdcFieldBuilder(this.getOpaInstance());
|
|
72
70
|
return oMdcFieldBuilder
|
|
73
71
|
.isDialogElement()
|
|
@@ -75,18 +73,18 @@ sap.ui.define(
|
|
|
75
73
|
.has(this._createFieldMatcher(vFieldIdentifier, oDialogIdentifier));
|
|
76
74
|
};
|
|
77
75
|
|
|
78
|
-
DialogAPI.prototype._getConfirmButtonMatcher = function() {
|
|
76
|
+
DialogAPI.prototype._getConfirmButtonMatcher = function () {
|
|
79
77
|
var iConfirmButtonIndex = this._iConfirmButtonIndex;
|
|
80
|
-
return function(oButton) {
|
|
78
|
+
return function (oButton) {
|
|
81
79
|
var aButtons = oButton.getParent().getButtons();
|
|
82
80
|
// Confirm is (usually) the first button
|
|
83
81
|
return aButtons.indexOf(oButton) === Math.min(aButtons.length - 1, iConfirmButtonIndex);
|
|
84
82
|
};
|
|
85
83
|
};
|
|
86
84
|
|
|
87
|
-
DialogAPI.prototype._getCancelButtonMatcher = function() {
|
|
85
|
+
DialogAPI.prototype._getCancelButtonMatcher = function () {
|
|
88
86
|
var iConfirmButtonIndex = this._iConfirmButtonIndex;
|
|
89
|
-
return function(oButton) {
|
|
87
|
+
return function (oButton) {
|
|
90
88
|
var aButtons = oButton.getParent().getButtons();
|
|
91
89
|
// Cancel is (usually) right next to the first (confirm) button and (usually) the last one in the list
|
|
92
90
|
return aButtons.length > 2
|
|
@@ -95,9 +93,9 @@ sap.ui.define(
|
|
|
95
93
|
};
|
|
96
94
|
};
|
|
97
95
|
|
|
98
|
-
DialogAPI.prototype._getConfirmDiscardDraftButtonMatcher = function() {
|
|
96
|
+
DialogAPI.prototype._getConfirmDiscardDraftButtonMatcher = function () {
|
|
99
97
|
var iConfirmDiscardDraftButtonIndex = this._iConfirmDiscardDraftButtonIndex;
|
|
100
|
-
return function(oButton) {
|
|
98
|
+
return function (oButton) {
|
|
101
99
|
var aButtons = oButton.getParent().getButtons();
|
|
102
100
|
// for the KeepDraft/DiscardDraft message, the DiscardDraft button is the second in the list
|
|
103
101
|
return aButtons.indexOf(oButton) === iConfirmDiscardDraftButtonIndex;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
(c) Copyright 2009-2021 SAP SE. All rights reserved
|
|
4
4
|
|
|
5
5
|
*/
|
|
6
|
-
sap.ui.define(["./DialogAPI", "sap/fe/test/Utils", "sap/ui/test/OpaBuilder"], function(DialogAPI, Utils, OpaBuilder) {
|
|
6
|
+
sap.ui.define(["./DialogAPI", "sap/fe/test/Utils", "sap/ui/test/OpaBuilder"], function (DialogAPI, Utils, OpaBuilder) {
|
|
7
7
|
"use strict";
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -11,14 +11,14 @@ sap.ui.define(["./DialogAPI", "sap/fe/test/Utils", "sap/ui/test/OpaBuilder"], fu
|
|
|
11
11
|
*
|
|
12
12
|
* @param {sap.fe.test.builder.DialogBuilder} oDialogBuilder The {@link sap.fe.test.builder.DialogBuilder} instance used to interact with the UI
|
|
13
13
|
* @param {string} [vDialogDescription] Description (optional) of the dialog to be used for logging messages
|
|
14
|
-
* @param {
|
|
14
|
+
* @param {number} [iConfirmButtonIndex] Index of the 'confirm' button in the button aggregation; the default setting is 0 (first button from the left)
|
|
15
15
|
* @returns {sap.fe.test.api.DialogActions} The new DialogActions instance
|
|
16
16
|
* @alias sap.fe.test.api.DialogActions
|
|
17
17
|
* @class
|
|
18
18
|
* @hideconstructor
|
|
19
19
|
* @public
|
|
20
20
|
*/
|
|
21
|
-
var DialogActions = function(oDialogBuilder, vDialogDescription, iConfirmButtonIndex) {
|
|
21
|
+
var DialogActions = function (oDialogBuilder, vDialogDescription, iConfirmButtonIndex) {
|
|
22
22
|
return DialogAPI.call(this, oDialogBuilder, vDialogDescription, iConfirmButtonIndex);
|
|
23
23
|
};
|
|
24
24
|
DialogActions.prototype = Object.create(DialogAPI.prototype);
|
|
@@ -31,7 +31,7 @@ sap.ui.define(["./DialogAPI", "sap/fe/test/Utils", "sap/ui/test/OpaBuilder"], fu
|
|
|
31
31
|
* @returns {object} The result of the {@link sap.ui.test.Opa5#waitFor} function, to be used for chained statements
|
|
32
32
|
* @public
|
|
33
33
|
*/
|
|
34
|
-
DialogActions.prototype.iConfirm = function() {
|
|
34
|
+
DialogActions.prototype.iConfirm = function () {
|
|
35
35
|
return this.prepareResult(
|
|
36
36
|
this.getBuilder()
|
|
37
37
|
.doPressFooterButton(this._getConfirmButtonMatcher())
|
|
@@ -46,7 +46,7 @@ sap.ui.define(["./DialogAPI", "sap/fe/test/Utils", "sap/ui/test/OpaBuilder"], fu
|
|
|
46
46
|
* @returns {object} The result of the {@link sap.ui.test.Opa5#waitFor} function, to be used for chained statements
|
|
47
47
|
* @public
|
|
48
48
|
*/
|
|
49
|
-
DialogActions.prototype.iCancel = function() {
|
|
49
|
+
DialogActions.prototype.iCancel = function () {
|
|
50
50
|
return this.prepareResult(
|
|
51
51
|
this.getBuilder()
|
|
52
52
|
.doPressFooterButton(this._getCancelButtonMatcher())
|
|
@@ -61,7 +61,7 @@ sap.ui.define(["./DialogAPI", "sap/fe/test/Utils", "sap/ui/test/OpaBuilder"], fu
|
|
|
61
61
|
* @returns {object} The result of the {@link sap.ui.test.Opa5#waitFor} function, to be used for chained statements
|
|
62
62
|
* @public
|
|
63
63
|
*/
|
|
64
|
-
DialogActions.prototype.iClose = function() {
|
|
64
|
+
DialogActions.prototype.iClose = function () {
|
|
65
65
|
return this.prepareResult(
|
|
66
66
|
this.getBuilder()
|
|
67
67
|
.doPressKeyboardShortcut("Escape")
|
|
@@ -79,7 +79,7 @@ sap.ui.define(["./DialogAPI", "sap/fe/test/Utils", "sap/ui/test/OpaBuilder"], fu
|
|
|
79
79
|
* @returns {object} The result of the {@link sap.ui.test.Opa5#waitFor} function, that can be used for chaining statements
|
|
80
80
|
* @public
|
|
81
81
|
*/
|
|
82
|
-
DialogActions.prototype.iChangeDialogField = function(vFieldIdentifier, vValue, bClearFirst) {
|
|
82
|
+
DialogActions.prototype.iChangeDialogField = function (vFieldIdentifier, vValue, bClearFirst) {
|
|
83
83
|
var aArguments = Utils.parseArguments([Object, String, Boolean], arguments);
|
|
84
84
|
return this.prepareResult(
|
|
85
85
|
this._createFieldBuilder(vFieldIdentifier, this.getIdentifier())
|
|
@@ -108,7 +108,7 @@ sap.ui.define(["./DialogAPI", "sap/fe/test/Utils", "sap/ui/test/OpaBuilder"], fu
|
|
|
108
108
|
* @returns {object} The result of the {@link sap.ui.test.Opa5#waitFor} function, that can be used for chaining statements
|
|
109
109
|
* @ui5-restricted
|
|
110
110
|
*/
|
|
111
|
-
DialogActions.prototype.iChangeActionParameterDialogField = function(vFieldIdentifier, vValue, bClearFirst) {
|
|
111
|
+
DialogActions.prototype.iChangeActionParameterDialogField = function (vFieldIdentifier, vValue, bClearFirst) {
|
|
112
112
|
return this.iChangeDialogField(vFieldIdentifier, vValue, bClearFirst);
|
|
113
113
|
};
|
|
114
114
|
|