@gravitee/ui-components 3.28.8-codeowner-924135a → 3.29.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.
Files changed (38) hide show
  1. package/package.json +1 -1
  2. package/src/index.d.ts +1 -0
  3. package/src/index.js +1 -0
  4. package/src/index.js.map +1 -1
  5. package/src/lib/events.d.ts +4 -1
  6. package/src/lib/events.js +0 -1
  7. package/src/lib/events.js.map +1 -1
  8. package/src/organisms/gv-properties/gv-properties.d.ts +1 -1
  9. package/src/organisms/gv-properties/gv-properties.js +8 -5
  10. package/src/organisms/gv-properties/gv-properties.js.map +1 -1
  11. package/src/organisms/gv-resources/gv-resources.d.ts +2 -7
  12. package/src/organisms/gv-resources/gv-resources.js +9 -8
  13. package/src/organisms/gv-resources/gv-resources.js.map +1 -1
  14. package/src/organisms/gv-schema-form/gv-schema-form.d.ts +1 -1
  15. package/src/organisms/gv-schema-form/gv-schema-form.js +9 -4
  16. package/src/organisms/gv-schema-form/gv-schema-form.js.map +1 -1
  17. package/src/organisms/gv-schema-form/gv-schema-form.test.js +15 -0
  18. package/src/organisms/gv-schema-form/gv-schema-form.test.js.map +1 -1
  19. package/src/organisms/gv-schema-form-control/gv-schema-form-control.d.ts +1 -0
  20. package/src/organisms/gv-schema-form-control/gv-schema-form-control.js +9 -1
  21. package/src/organisms/gv-schema-form-control/gv-schema-form-control.js.map +1 -1
  22. package/src/policy-studio/gv-design/gv-design.d.ts +368 -0
  23. package/src/policy-studio/gv-design/gv-design.js +1491 -0
  24. package/src/policy-studio/gv-design/gv-design.js.map +1 -0
  25. package/src/policy-studio/gv-design/gv-design.stories.d.ts +203 -0
  26. package/src/policy-studio/gv-design/gv-design.stories.js +233 -0
  27. package/src/policy-studio/gv-design/gv-design.stories.js.map +1 -0
  28. package/src/policy-studio/gv-design/gv-design.test.d.ts +1 -0
  29. package/src/policy-studio/gv-design/gv-design.test.js +333 -0
  30. package/src/policy-studio/gv-design/gv-design.test.js.map +1 -0
  31. package/src/policy-studio/gv-design/index.d.ts +1 -0
  32. package/src/policy-studio/gv-design/index.js +17 -0
  33. package/src/policy-studio/gv-design/index.js.map +1 -0
  34. package/src/policy-studio/gv-policy-studio/gv-policy-studio.js +3 -0
  35. package/src/policy-studio/gv-policy-studio/gv-policy-studio.js.map +1 -1
  36. package/wc/gv-design.d.ts +1 -0
  37. package/wc/gv-design.js +2 -0
  38. package/wc/gv-design.js.map +1 -0
@@ -0,0 +1,1491 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __rest = (this && this.__rest) || function (s, e) {
11
+ var t = {};
12
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
13
+ t[p] = s[p];
14
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
15
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
16
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
17
+ t[p[i]] = s[p[i]];
18
+ }
19
+ return t;
20
+ };
21
+ /*
22
+ * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
23
+ *
24
+ * Licensed under the Apache License, Version 2.0 (the "License");
25
+ * you may not use this file except in compliance with the License.
26
+ * You may obtain a copy of the License at
27
+ *
28
+ * http://www.apache.org/licenses/LICENSE-2.0
29
+ *
30
+ * Unless required by applicable law or agreed to in writing, software
31
+ * distributed under the License is distributed on an "AS IS" BASIS,
32
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33
+ * See the License for the specific language governing permissions and
34
+ * limitations under the License.
35
+ */
36
+ import { css, html, LitElement } from 'lit';
37
+ import { methods } from '../../lib/studio';
38
+ import { dispatchCustomEvent } from '../../lib/events';
39
+ import { i18n } from '../../lib/i18n';
40
+ import '../../atoms/gv-button';
41
+ import '../../atoms/gv-icon';
42
+ import '../../molecules/gv-option';
43
+ import '../../organisms/gv-documentation';
44
+ import '../../organisms/gv-resizable-views';
45
+ import '../../organisms/gv-schema-form';
46
+ import '../../molecules/gv-row';
47
+ import '../gv-flow';
48
+ import '../gv-flow-step';
49
+ import '../gv-policy-studio-menu';
50
+ import { empty } from '../../styles/empty';
51
+ import { cache } from 'lit/directives/cache.js';
52
+ import { deepClone, deepEqual } from '../../lib/utils';
53
+ import { KeyboardElement, KEYS } from '../../mixins/keyboard-element';
54
+ const FLOW_STEP_FORM_ID = 'flow-step-form';
55
+ /**
56
+ * Design component
57
+ *
58
+ * ⚠️ This component is based on `asciidoctor`, `highlight.js` and `asciidoctor-highlight.js`.
59
+ * To use this component in your project be sure the dependencies are installed or
60
+ * install them with: `npm install asciidoctor highlight.js asciidoctor-highlight.js --save`
61
+ *
62
+ * @fires gv-design:select-policy - Select policy event
63
+ * @fires gv-design:change - Design change event
64
+ *
65
+ * @attr {Array} policies - Policies available
66
+ * @attr {Array} services - Services available
67
+ * @attr {Array} resourceTypes - Resources types available
68
+ * @attr {Object} definition - The definition of flows
69
+ * @attr {Object} documentation - The documentation to display
70
+ * @attr {Object} flowSchema - The flow form configuration to display in gv-schema-form component
71
+ * @attr {Boolean} isDirty - true if component is dirty
72
+ * @attr {Array} selectedFlowsId - The selected flows id
73
+ * @attr {Boolean} sortable - true if flows are sortable
74
+ * @attr {Boolean} readonly - true if readonly
75
+ * @attr {Boolean} readonly-plans - true if plans' flows can't be modified
76
+ * @attr {Boolean} can-add - true if user can add flow
77
+ * @attr {String} flowsTitle - flows menu title
78
+ * @attr {Boolean} has-policy-filter - true if policies have onRequest/onResponse properties
79
+ * @attr {Boolean} has-conditional-steps - true if steps can be conditioned
80
+ */
81
+ export class GvDesign extends KeyboardElement(LitElement) {
82
+ static get properties() {
83
+ return {
84
+ policies: { type: Array },
85
+ services: { type: Object },
86
+ resourceTypes: { type: Array, attribute: 'resource-types' },
87
+ definition: { type: Object },
88
+ _definition: { type: Object, attribute: false },
89
+ documentation: { type: Object },
90
+ flowSchema: { type: Object, attribute: 'flow-schema' },
91
+ isDirty: { type: Boolean, attribute: 'dirty', reflect: true },
92
+ _dragPolicy: { type: Object, attribute: false },
93
+ _dropPolicy: { type: Object, attribute: false },
94
+ selectedFlowsId: { type: Array, attribute: 'selected-flows-id' },
95
+ _selectedFlowsId: { type: Array, attribute: false },
96
+ _currentPolicyId: { type: String, attribute: false },
97
+ _searchPolicyQuery: { type: String, attribute: false },
98
+ _searchFlowQuery: { type: String, attribute: false },
99
+ _flowStepSchema: { type: Object, attribute: false },
100
+ _currentFlowStep: { type: Object, attribute: false },
101
+ _policyFilter: { type: Array, attribute: false },
102
+ _flowFilter: { type: Array, attribute: false },
103
+ _currentAskConfirmation: { type: Boolean, attribute: false },
104
+ hasPolicyFilter: { type: Boolean, attribute: 'has-policy-filter' },
105
+ flowsTitle: { type: String, attribute: 'flows-title' },
106
+ sortable: { type: Boolean },
107
+ canAdd: { type: Boolean, attribute: 'can-add' },
108
+ readonly: { type: Boolean },
109
+ readonlyPlans: { type: Boolean, attribute: 'readonly-plans' },
110
+ hasConditionalSteps: { type: Boolean, attribute: 'has-conditional-steps' },
111
+ };
112
+ }
113
+ static get styles() {
114
+ return [
115
+ empty,
116
+ methods,
117
+ // language=CSS
118
+ css `
119
+ :host {
120
+ box-sizing: border-box;
121
+ --height: var(--gv-policy-studio--h, calc(100vh - 32px));
122
+ height: var(--height);
123
+ --height-in-tabs: calc(var(--height) - 25px);
124
+ }
125
+
126
+ .box {
127
+ height: var(--height);
128
+ display: flex;
129
+ }
130
+
131
+ .design {
132
+ display: flex;
133
+ width: 100%;
134
+ }
135
+
136
+ gv-resizable-views {
137
+ width: 100%;
138
+ }
139
+
140
+ .editable-name {
141
+ padding: 0.5rem 1rem;
142
+ font-size: 16px;
143
+ }
144
+
145
+ .editable-name span {
146
+ color: #bfbfbf;
147
+ font-size: 12px;
148
+ }
149
+
150
+ .form__control {
151
+ margin: 0.5rem;
152
+ }
153
+
154
+ gv-input {
155
+ width: 100%;
156
+ }
157
+
158
+ .flow-name {
159
+ display: flex;
160
+ align-items: center;
161
+ }
162
+
163
+ .flow-name.dirty {
164
+ font-style: italic;
165
+ opacity: 0.8;
166
+ }
167
+
168
+ .flow-name gv-icon {
169
+ --gv-icon--s: 24px;
170
+ margin-right: 0.2rem;
171
+ }
172
+
173
+ .flow-path {
174
+ margin-left: 0.2rem;
175
+ }
176
+
177
+ .title_methods {
178
+ margin-left: 0.5rem;
179
+ }
180
+
181
+ .two-cols {
182
+ display: flex;
183
+ width: 100%;
184
+ height: 100%;
185
+ }
186
+
187
+ .two-cols > * {
188
+ flex: 1;
189
+ }
190
+
191
+ .left-menu {
192
+ border-left: 1px solid #d9d9d9;
193
+ height: var(--height-in-tabs);
194
+ }
195
+
196
+ .right-menu {
197
+ border-right: 1px solid #d9d9d9;
198
+ height: var(--height-in-tabs);
199
+ }
200
+
201
+ .two-cols > *:first-child {
202
+ border-right: 1px solid #d9d9d9;
203
+ }
204
+
205
+ .flow-step__container {
206
+ overflow: hidden;
207
+ position: relative;
208
+ overflow: hidden;
209
+ height: 99%;
210
+ }
211
+
212
+ .flow-step__form {
213
+ padding: 0 0.5rem;
214
+ overflow: auto;
215
+ }
216
+
217
+ .flow-step__form-title {
218
+ text-transform: uppercase;
219
+ letter-spacing: 0.2rem;
220
+ }
221
+
222
+ gv-resizable-views {
223
+ height: var(--height-in-tabs);
224
+ }
225
+
226
+ .flow-settings gv-schema-form {
227
+ flex: 1;
228
+ padding: 0.5rem;
229
+ }
230
+
231
+ .search {
232
+ display: flex;
233
+ justify-content: stretch;
234
+ }
235
+
236
+ gv-input {
237
+ margin: 0.2rem 0;
238
+ width: 100%;
239
+ }
240
+
241
+ .header-actions,
242
+ .search-policies {
243
+ display: flex;
244
+ flex-direction: column;
245
+ align-items: center;
246
+ margin: 0.5rem;
247
+ }
248
+
249
+ .footer-actions > gv-button.btn-large,
250
+ .footer-actions > gv-option {
251
+ width: 100%;
252
+ }
253
+
254
+ .footer-actions {
255
+ display: flex;
256
+ flex-direction: column;
257
+ align-items: center;
258
+ padding: 0.5rem 0;
259
+ margin: 0.5rem 15px;
260
+ border-top: 1px solid #bfbfbf;
261
+ }
262
+
263
+ .header-actions .title {
264
+ text-transform: uppercase;
265
+ text-align: center;
266
+ letter-spacing: 0.3rem;
267
+ color: #bfbfbf;
268
+ font-size: 18px;
269
+ white-space: nowrap;
270
+ overflow: hidden;
271
+ text-overflow: ellipsis;
272
+ width: 240px;
273
+ min-height: 25px;
274
+ }
275
+
276
+ .header-actions > *,
277
+ .search-policies > * {
278
+ margin-bottom: 1rem;
279
+ }
280
+ `,
281
+ ];
282
+ }
283
+ constructor() {
284
+ super();
285
+ this.isDirty = false;
286
+ this.policies = [];
287
+ this.resourceTypes = [];
288
+ this.selectedFlowsId = [];
289
+ this.flowsTitle = 'Flows';
290
+ this.sortable = false;
291
+ this.services = {};
292
+ this._definition = {
293
+ flows: [],
294
+ };
295
+ this._policyFilter = [];
296
+ this._flowFilter = [];
297
+ }
298
+ willUpdate(changedProperties) {
299
+ return __awaiter(this, void 0, void 0, function* () {
300
+ if (changedProperties.has('hasPolicyFilter') && this.hasPolicyFilter === true) {
301
+ this._policyFilterOptions = [
302
+ { id: 'onRequest', title: 'Request', icon: 'navigation:arrow-from-left' },
303
+ { id: 'onResponse', title: 'Response', icon: 'navigation:arrow-from-right' },
304
+ ];
305
+ }
306
+ });
307
+ }
308
+ get _flowFilterOptions() {
309
+ if (this.definedPlans.length > 0) {
310
+ return [
311
+ { id: 'api', title: 'Api', icon: 'shopping:box#3' },
312
+ { id: 'plan', title: 'Plans', icon: 'shopping:sale#2' },
313
+ ];
314
+ }
315
+ }
316
+ get keyboardTarget() {
317
+ return window;
318
+ }
319
+ onKeyboard(controller, event) {
320
+ if (this._currentAskConfirmation == null) {
321
+ if (this.isPressed(KEYS.Shift, KEYS.Alt, KEYS.Space)) {
322
+ const search = this.shadowRoot.querySelector('#search-policy');
323
+ if (search) {
324
+ search.focus();
325
+ event.preventDefault();
326
+ }
327
+ }
328
+ else if (this.isPressed(KEYS.Alt, KEYS.Space)) {
329
+ const search = this.shadowRoot.querySelector('#search-flow');
330
+ if (search) {
331
+ search.focus();
332
+ event.preventDefault();
333
+ }
334
+ }
335
+ }
336
+ }
337
+ set definition(definition) {
338
+ if (definition) {
339
+ definition.flows = definition.flows || [];
340
+ const flows = this._generateFlowsId(definition.flows);
341
+ const resources = this._generateId('resource-', definition.resources);
342
+ const plans = definition.plans == null
343
+ ? []
344
+ : definition.plans.map((plan) => {
345
+ return Object.assign(Object.assign({}, plan), { flows: this._generatePlanFlowsId(plan) });
346
+ });
347
+ this._initialDefinition = Object.assign(Object.assign({}, definition), { flows, resources, plans });
348
+ this._definition = deepClone(this._initialDefinition);
349
+ this.isDirty = false;
350
+ this._selectFirstFlow();
351
+ }
352
+ }
353
+ get definition() {
354
+ return this._definition;
355
+ }
356
+ set selectedFlowsId(selectedFlowsId) {
357
+ if (selectedFlowsId != null && Array.isArray(selectedFlowsId)) {
358
+ this._selectedFlowsId = selectedFlowsId.filter((id) => this._findFlowById(id) != null);
359
+ if (selectedFlowsId.length !== this._selectedFlowsId.length) {
360
+ this._selectFirstFlow(true);
361
+ }
362
+ }
363
+ }
364
+ get selectedFlowsId() {
365
+ return this._selectedFlowsId.filter((id) => this._findFlowById(id) != null);
366
+ }
367
+ _updateSelectedFlows(selectedFlowsId) {
368
+ this.selectedFlowsId = selectedFlowsId;
369
+ dispatchCustomEvent(this, 'select-flows', { flows: this.selectedFlowsId });
370
+ }
371
+ _selectFirstFlow(dispatch = false) {
372
+ if (this.selectedFlowsId.length === 0) {
373
+ let candidate = null;
374
+ if (this.definedFlows.length > 0 && this.definedFlows[0]._id != null) {
375
+ candidate = this.definedFlows[0];
376
+ }
377
+ else if (this.definedPlans.length > 0) {
378
+ const plan = this.definedPlans.find((p) => p.flows != null && p.flows.length > 0 && p.flows[0]._id != null);
379
+ if (plan) {
380
+ candidate = plan.flows[0];
381
+ }
382
+ }
383
+ if (candidate != null) {
384
+ if (dispatch) {
385
+ this._updateSelectedFlows([candidate._id]);
386
+ }
387
+ else {
388
+ this.selectedFlowsId = [candidate._id];
389
+ }
390
+ }
391
+ }
392
+ }
393
+ _getFlowElement(flowId) {
394
+ return this.shadowRoot.querySelector(`[id="${flowId}"]`);
395
+ }
396
+ _onDragEndPolicy() {
397
+ this.shadowRoot.querySelectorAll('gv-flow').forEach((e) => e.onDragEnd());
398
+ }
399
+ _onDropPolicy({ detail }) {
400
+ return __awaiter(this, void 0, void 0, function* () {
401
+ try {
402
+ yield this._askToValidateForms();
403
+ const policy = detail.policy;
404
+ const targetFlow = this._findFlowById(detail.flowId);
405
+ let name = policy.name;
406
+ let description = '';
407
+ let condition = '';
408
+ let configuration = {};
409
+ let _id;
410
+ let _new = false;
411
+ if (detail.flowStep) {
412
+ _id = detail.flowStep._id;
413
+ name = detail.flowStep.name;
414
+ description = detail.flowStep.description || '';
415
+ condition = detail.flowStep.condition || '';
416
+ configuration = detail.flowStep.configuration;
417
+ }
418
+ else {
419
+ _id = this._generateFlowStepId(targetFlow._id, detail.flowKey, detail.position);
420
+ _new = true;
421
+ }
422
+ const flowStep = { _id, _new, name, policy: policy.id, description, condition, enabled: true, configuration };
423
+ const sourceFlow = detail.sourceFlowId != null ? this._findFlowById(detail.sourceFlowId) : targetFlow;
424
+ if (detail.sourcePosition != null) {
425
+ if (detail.sourceFlowKey && detail.sourceFlowKey !== detail.flowKey) {
426
+ sourceFlow[detail.sourceFlowKey].splice(detail.sourcePosition, 1);
427
+ targetFlow[detail.flowKey].splice(detail.position, 0, flowStep);
428
+ if (this._currentFlowStep != null && this._currentFlowStep.step._id === _id) {
429
+ this._currentFlowStep.group = detail.flowKey;
430
+ // Special case for update schema after change request to response or inverse
431
+ const schema = this.buildSchema(this._currentFlowStep.policy);
432
+ yield this._setCurrentFlowStep(this._currentFlowStep, schema, true);
433
+ this._getFlowElement(targetFlow._id).requestUpdate();
434
+ }
435
+ }
436
+ else {
437
+ if (detail.position > detail.sourcePosition) {
438
+ targetFlow[detail.flowKey].splice(detail.position, 0, flowStep);
439
+ sourceFlow[detail.flowKey].splice(detail.sourcePosition, 1);
440
+ }
441
+ else {
442
+ sourceFlow[detail.flowKey].splice(detail.sourcePosition, 1);
443
+ targetFlow[detail.flowKey].splice(detail.position, 0, flowStep);
444
+ }
445
+ }
446
+ // Force Refresh source flow element when move to other flow
447
+ if (targetFlow._id !== sourceFlow._id) {
448
+ this._getFlowElement(targetFlow._id).requestUpdate();
449
+ }
450
+ }
451
+ else {
452
+ targetFlow[detail.flowKey].splice(detail.position, 0, flowStep);
453
+ const currentFlowForm = this._getFlowStepForm();
454
+ if (currentFlowForm == null || currentFlowForm.dirty !== true) {
455
+ let step = targetFlow[detail.flowKey][detail.position];
456
+ if (step == null) {
457
+ // When confirm lose change after drop policy
458
+ step = targetFlow[detail.flowKey][detail.position - 1];
459
+ }
460
+ if (detail.cancelEdit !== true) {
461
+ setTimeout(() => __awaiter(this, void 0, void 0, function* () {
462
+ yield this._editFlowStep({ step, policy, flow: targetFlow, group: detail.flowKey });
463
+ this.updateComplete.then(() => {
464
+ const flowElement = this._getFlowElement(targetFlow._id);
465
+ flowElement.selectedStepId = step._id;
466
+ flowElement.requestUpdate();
467
+ });
468
+ }));
469
+ }
470
+ }
471
+ }
472
+ targetFlow._dirty = true;
473
+ sourceFlow._dirty = true;
474
+ this.isDirty = true;
475
+ this.shadowRoot.querySelectorAll('gv-flow').forEach((gvFlow) => gvFlow.removeCandidate());
476
+ setTimeout(() => {
477
+ this._dragPolicy = null;
478
+ this._dropPolicy = null;
479
+ this.dispatchChange();
480
+ }, 0);
481
+ }
482
+ catch (e) {
483
+ this._currentAskConfirmation = null;
484
+ }
485
+ });
486
+ }
487
+ _onDeletePolicy({ detail }) {
488
+ const targetFlow = this._findFlowById(detail.flowId);
489
+ targetFlow[detail.flowKey].splice(detail.position, 1);
490
+ targetFlow._dirty = true;
491
+ this.isDirty = true;
492
+ if (detail.target.editing) {
493
+ this._closeFlowStepForm(true);
494
+ }
495
+ this._getFlowElement(detail.flowId).requestUpdate();
496
+ this.dispatchChange();
497
+ }
498
+ _onDesign() {
499
+ this._splitMainViews();
500
+ }
501
+ buildSchema({ schema }) {
502
+ const commonDescription = {
503
+ title: 'Description',
504
+ description: 'Description of flow step',
505
+ type: 'string',
506
+ };
507
+ const commonCondition = {
508
+ title: 'Condition',
509
+ description: 'Condition the execution of the flow step (support EL)',
510
+ type: 'string',
511
+ 'x-schema-form': {
512
+ 'expression-language': true,
513
+ },
514
+ };
515
+ if (schema) {
516
+ const jsonSchema = typeof schema === 'string' ? JSON.parse(schema) : schema;
517
+ const properties = Object.assign(Object.assign({ commonDescription }, (this.hasConditionalSteps ? { commonCondition } : {})), jsonSchema.properties);
518
+ return Object.assign(Object.assign({}, jsonSchema), { properties });
519
+ }
520
+ return { properties: Object.assign({ commonDescription }, (this.hasConditionalSteps ? { commonCondition } : {})) };
521
+ }
522
+ _editFlowStep({ step, flow, policy, group }) {
523
+ return __awaiter(this, void 0, void 0, function* () {
524
+ if (step) {
525
+ this._currentPolicyId = policy.id;
526
+ const currentFlowStep = { flow, step, policy, group };
527
+ const schema = this.buildSchema(policy);
528
+ try {
529
+ yield this._setCurrentFlowStep(currentFlowStep, schema);
530
+ this._updateSelectedFlows([flow._id]);
531
+ this._splitMainViews();
532
+ if (localStorage.getItem('gv-policy-studio:keep-documentation-close') == null) {
533
+ this._onOpenDocumentation();
534
+ }
535
+ }
536
+ catch (e) {
537
+ this._currentAskConfirmation = null;
538
+ }
539
+ }
540
+ else {
541
+ yield this._closeFlowStepForm();
542
+ this._maximizeTopView();
543
+ }
544
+ });
545
+ }
546
+ _onEditFlowStep({ detail: { step, flow, policy, group } }) {
547
+ return __awaiter(this, void 0, void 0, function* () {
548
+ return this._editFlowStep({ step, flow, policy, group });
549
+ });
550
+ }
551
+ _getResizableViews() {
552
+ return this.shadowRoot.querySelector('gv-resizable-views');
553
+ }
554
+ _maximizeTopView() {
555
+ if (this.selectedFlowsId.length <= 1) {
556
+ this._getResizableViews().maximizeTop();
557
+ }
558
+ }
559
+ _maximizeBottomView() {
560
+ this._getResizableViews().maximizeBottom();
561
+ }
562
+ _splitMainViews() {
563
+ this._getResizableViews().split();
564
+ }
565
+ _onChangeFlowStepState({ detail }) {
566
+ const targetFlow = this._findFlowById(detail.flowId);
567
+ const step = targetFlow[detail.flowKey][detail.position];
568
+ step.enabled = detail.enabled;
569
+ targetFlow._dirty = true;
570
+ this.isDirty = true;
571
+ this.dispatchChange();
572
+ }
573
+ dispatchChange() {
574
+ const invalidForms = [...this.shadowRoot.querySelectorAll('gv-schema-form')].filter((form) => {
575
+ form.validate();
576
+ return !form.isValid();
577
+ });
578
+ const errors = invalidForms.length;
579
+ const definition = errors === 0 ? this._buildDefinitionToSend(this._buildDefinitionToSave()) : null;
580
+ dispatchCustomEvent(this, 'change', {
581
+ isDirty: this.isDirty,
582
+ errors,
583
+ definition,
584
+ });
585
+ }
586
+ _onCloseFlowStepForm() {
587
+ return __awaiter(this, void 0, void 0, function* () {
588
+ try {
589
+ yield this._closeFlowStepForm();
590
+ }
591
+ catch (err) {
592
+ this._currentAskConfirmation = null;
593
+ }
594
+ });
595
+ }
596
+ _closeFlowStepForm(force = false) {
597
+ return __awaiter(this, void 0, void 0, function* () {
598
+ yield this._setCurrentFlowStep(null, null, force);
599
+ });
600
+ }
601
+ _askToValidateForms() {
602
+ return __awaiter(this, void 0, void 0, function* () {
603
+ if (this._currentAskConfirmation == null) {
604
+ this._currentAskConfirmation = true;
605
+ return Promise.all(this._submitOrConfirmForms()).then((forms) => {
606
+ if (forms.filter((r) => r != null).length > 0) {
607
+ this._definition = this._buildDefinitionToSave();
608
+ this.getChildren().forEach((e) => e.requestUpdate());
609
+ // Refresh if lose changes lost current step selection
610
+ return this._checkCurrentFlowStep().then(() => {
611
+ this.getChildren().forEach((e) => e.requestUpdate());
612
+ return this.updateComplete.then(() => {
613
+ this._currentAskConfirmation = null;
614
+ return forms;
615
+ });
616
+ });
617
+ }
618
+ else {
619
+ this._currentAskConfirmation = null;
620
+ return forms;
621
+ }
622
+ });
623
+ }
624
+ throw new Error('ask already waiting');
625
+ });
626
+ }
627
+ _setCurrentFlowStep(currentFlowStep, flowStepSchema, force = false) {
628
+ return __awaiter(this, void 0, void 0, function* () {
629
+ if (!force) {
630
+ yield this._askToValidateForms();
631
+ }
632
+ const schema = deepClone(flowStepSchema);
633
+ if (currentFlowStep != null) {
634
+ const configuration = typeof currentFlowStep.step.configuration === 'string'
635
+ ? JSON.parse(currentFlowStep.step.configuration)
636
+ : currentFlowStep.step.configuration;
637
+ const step = Object.assign(Object.assign({}, currentFlowStep.step), { configuration });
638
+ const _initialValues = Object.assign(Object.assign({}, step.configuration), { commonDescription: step.description, commonCondition: step.condition });
639
+ this._currentFlowStep = Object.assign(Object.assign({}, currentFlowStep), { step, _initialValues });
640
+ if (flowStepSchema && flowStepSchema.properties.scope) {
641
+ const _enum = schema.properties.scope.enum;
642
+ if (_enum.find((s) => ['REQUEST', 'REQUEST_CONTENT', 'RESPONSE', 'RESPONSE_CONTENT'].includes(s)) != null) {
643
+ const filtered = this._currentFlowStep.group === 'pre' ? ['REQUEST', 'REQUEST_CONTENT'] : ['RESPONSE', 'RESPONSE_CONTENT'];
644
+ schema.properties.scope.enum = _enum.filter((s) => filtered.includes(s));
645
+ const scope = this._currentFlowStep.step.configuration.scope;
646
+ if (scope == null || !schema.properties.scope.enum.includes(scope)) {
647
+ schema.properties.scope.default = schema.properties.scope.enum[0];
648
+ this._currentFlowStep.step.configuration.scope = schema.properties.scope.enum[0];
649
+ this._currentFlowStep._initialValues.scope = schema.properties.scope.enum[0];
650
+ if (this._currentFlowStep._values) {
651
+ this._currentFlowStep._values.scope = schema.properties.scope.enum[0];
652
+ }
653
+ }
654
+ }
655
+ }
656
+ }
657
+ else {
658
+ this._currentFlowStep = null;
659
+ }
660
+ this._flowStepSchema = schema;
661
+ });
662
+ }
663
+ _refresh(closeStepForm = true) {
664
+ if (closeStepForm) {
665
+ this._closeFlowStepForm(true);
666
+ }
667
+ this._definition = deepClone(this._definition);
668
+ }
669
+ _onSelectFlows({ detail }) {
670
+ return __awaiter(this, void 0, void 0, function* () {
671
+ try {
672
+ yield this._closeFlowStepForm();
673
+ this._onCloseDocumentation();
674
+ this._updateSelectedFlows(detail.flows);
675
+ this._onDesign();
676
+ }
677
+ catch (e) {
678
+ this._currentAskConfirmation = null;
679
+ }
680
+ });
681
+ }
682
+ _onOpenDocumentationFromMenu({ detail: { policy } }) {
683
+ return __awaiter(this, void 0, void 0, function* () {
684
+ try {
685
+ if (this.documentation == null || this.documentation.id !== policy.id) {
686
+ yield this._closeFlowStepForm();
687
+ this._currentPolicyId = policy.id;
688
+ if (this.getSelectedFlow()) {
689
+ this._splitMainViews();
690
+ }
691
+ else {
692
+ this._maximizeBottomView();
693
+ }
694
+ dispatchCustomEvent(this, 'fetch-documentation', { policy });
695
+ }
696
+ }
697
+ catch (e) { }
698
+ });
699
+ }
700
+ _fetchDocumentation(policy) {
701
+ if (this.documentation == null || this.documentation.id !== policy.id) {
702
+ dispatchCustomEvent(this, 'fetch-documentation', { policy });
703
+ }
704
+ }
705
+ _onOpenDocumentation() {
706
+ if (this._currentFlowStep && this._currentFlowStep.policy) {
707
+ this._fetchDocumentation(this._currentFlowStep.policy);
708
+ }
709
+ }
710
+ _onOpenDocumentationFromForm() {
711
+ localStorage.removeItem('gv-policy-studio:keep-documentation-close');
712
+ this._onOpenDocumentation();
713
+ }
714
+ _findFlowCollection(flowId) {
715
+ const plan = this.definedPlans.find((p) => p.flows.find((flow) => flow._id === flowId) != null);
716
+ return { plan, flows: plan != null ? plan.flows : this.definedFlows };
717
+ }
718
+ _findFlowById(flowId) {
719
+ let flow = this.definedFlows.find((f) => f._id === flowId);
720
+ if (flow == null) {
721
+ const plansFlows = this.definedPlans.map((p) => p.flows).reduce((acc, val) => acc.concat(val), []);
722
+ flow = plansFlows.find((f) => f._id === flowId);
723
+ }
724
+ return flow;
725
+ }
726
+ getSelectedFlow(index = 0) {
727
+ const selectedFlowId = this.selectedFlowsId[index];
728
+ return this._findFlowById(selectedFlowId);
729
+ }
730
+ _onTargetPolicy({ detail }) {
731
+ if (this._currentAskConfirmation == null) {
732
+ this._dragPolicy = detail;
733
+ }
734
+ }
735
+ _onChangeFlowStep({ detail }) {
736
+ this._currentFlowStep._values = detail.values;
737
+ }
738
+ _writeFlowStep(values) {
739
+ const { commonDescription, commonCondition } = values, configuration = __rest(values, ["commonDescription", "commonCondition"]);
740
+ if (this._currentFlowStep.step._new ||
741
+ this._currentFlowStep.step.description !== commonDescription ||
742
+ this._currentFlowStep.step.condition !== commonCondition ||
743
+ !deepEqual(this._currentFlowStep.step.configuration, configuration)) {
744
+ const flow = this._findFlowById(this._currentFlowStep.flow._id);
745
+ const position = flow[this._currentFlowStep.group].findIndex((step) => step._id === this._currentFlowStep.step._id);
746
+ flow[this._currentFlowStep.group][position].description = commonDescription;
747
+ flow[this._currentFlowStep.group][position].condition = commonCondition;
748
+ flow[this._currentFlowStep.group][position].configuration = deepClone(configuration);
749
+ delete flow[this._currentFlowStep.group][position]._new;
750
+ flow[this._currentFlowStep.group][position]._dirty = true;
751
+ flow._dirty = true;
752
+ this.isDirty = true;
753
+ this._currentFlowStep.flow = flow;
754
+ this._currentFlowStep.step = flow[this._currentFlowStep.group][position];
755
+ this.dispatchChange();
756
+ }
757
+ }
758
+ _onSubmitFlowStep({ detail }) {
759
+ return __awaiter(this, void 0, void 0, function* () {
760
+ this._writeFlowStep(detail.values);
761
+ yield this.requestUpdate('_definition');
762
+ this.getChildren().forEach((c) => c.requestUpdate());
763
+ });
764
+ }
765
+ _onCancelFlow() {
766
+ this._onDesign();
767
+ }
768
+ _onSubmitFlow({ detail: { values } }) {
769
+ const selectedFlow = this.getSelectedFlow();
770
+ const _values = Object.assign({}, this._createFlowFromSchema(), values);
771
+ const selectedFlowUpdated = Object.assign({}, selectedFlow, _values);
772
+ if (!deepEqual(selectedFlow, selectedFlowUpdated)) {
773
+ Object.assign(selectedFlow, selectedFlowUpdated, { _dirty: true });
774
+ this.isDirty = true;
775
+ this.dispatchChange();
776
+ this._refresh();
777
+ }
778
+ }
779
+ _onCancelFlowMode() {
780
+ this._onDesign();
781
+ }
782
+ _onSubmitFlowMode({ detail: { values } }) {
783
+ this._definition['flow-mode'] = values['flow-mode'] || 'DEFAULT';
784
+ this.isDirty = true;
785
+ this.dispatchChange();
786
+ this._refresh();
787
+ }
788
+ _onDragStartFlowStep(flow, { detail }) {
789
+ if (this._currentAskConfirmation == null) {
790
+ this._dropPolicy = detail;
791
+ this._dragPolicy = detail;
792
+ }
793
+ }
794
+ _renderFlowEmptyState(readonlyMode) {
795
+ return html `<div slot="content" class="empty">
796
+ <div>
797
+ Select a flow
798
+ ${readonlyMode !== true
799
+ ? html `or <gv-button @gv-button:click="${this._onAddFlow}" outlined icon="code:plus" large>design new one </gv-button>`
800
+ : ''}
801
+ </div>
802
+ </div>`;
803
+ }
804
+ _renderFlow(index = 0, hasEmptyState = true, readonlyMode = false) {
805
+ const flow = this.getSelectedFlow(index);
806
+ if (flow) {
807
+ const { plan } = this._findFlowCollection(flow._id);
808
+ const selectedStepId = this._currentFlowStep ? this._currentFlowStep.step._id : null;
809
+ return html `<gv-flow
810
+ style="height: 100%"
811
+ .id="${flow._id}"
812
+ .flow="${flow}"
813
+ .plan="${plan}"
814
+ .policies="${this.policies}"
815
+ slot="content"
816
+ ?disabled="${this._currentAskConfirmation}"
817
+ .dragPolicy="${this._dragPolicy}"
818
+ .dropPolicy="${this._dropPolicy}"
819
+ .selectedStepId="${selectedStepId}"
820
+ ?readonly="${readonlyMode}"
821
+ ?has-policy-filter="${this._policyFilterOptions != null}"
822
+ flows-title="${this.flowsTitle}"
823
+ @gv-flow:drag-start="${this._onDragStartFlowStep.bind(this, flow)}"
824
+ @gv-flow:edit="${this._onEditFlowStep}"
825
+ @gv-flow:change-state="${this._onChangeFlowStepState}"
826
+ @gv-flow:drop="${this._onDropPolicy}"
827
+ @gv-flow:delete="${this._onDeletePolicy}"
828
+ ></gv-flow>`;
829
+ }
830
+ else if (hasEmptyState) {
831
+ return this._renderFlowEmptyState(readonlyMode);
832
+ }
833
+ return html ``;
834
+ }
835
+ _onFetchResources(event) {
836
+ const { currentTarget, regexTypes } = event.detail;
837
+ const options = this.definedResources
838
+ .filter((resource) => regexTypes == null || new RegExp(regexTypes).test(resource.type))
839
+ .map((resource, index) => {
840
+ const resourceType = this.resourceTypes.find((type) => type.id === resource.type);
841
+ const row = document.createElement('gv-row');
842
+ const picture = resourceType.icon ? resourceType.icon : null;
843
+ row.item = { picture, name: resource.name };
844
+ return {
845
+ element: row,
846
+ value: resource.name,
847
+ id: resource.type,
848
+ };
849
+ });
850
+ currentTarget.options = options;
851
+ }
852
+ _renderPolicy(readonlyMode) {
853
+ if (this._flowStepSchema && this.documentation) {
854
+ return html `<gv-resizable-views direction="horizontal" no-overflow>
855
+ <div slot="top">${this._renderFlowStepForm(readonlyMode)}</div>
856
+ <div slot="bottom">
857
+ <gv-documentation
858
+ .text="${this.documentation.content}"
859
+ .image="${this.documentation.image}"
860
+ ?disabled="${this._currentAskConfirmation}"
861
+ @gv-documentation:close="${this._onCloseDocumentation}"
862
+ ></gv-documentation>
863
+ </div>
864
+ </gv-resizable-views>`;
865
+ }
866
+ else if (this.documentation) {
867
+ return html `<gv-documentation
868
+ .text="${this.documentation.content}"
869
+ .image="${this.documentation.image}"
870
+ ?disabled="${this._currentAskConfirmation}"
871
+ @gv-documentation:close="${this._onCloseDocumentation}"
872
+ ></gv-documentation>`;
873
+ }
874
+ else if (this._flowStepSchema) {
875
+ return this._renderFlowStepForm(readonlyMode);
876
+ }
877
+ return html ``;
878
+ }
879
+ _getFlowStepForm() {
880
+ return this.shadowRoot.querySelector(`#${FLOW_STEP_FORM_ID}`);
881
+ }
882
+ _onResetFlowStep() {
883
+ if (this._currentFlowStep) {
884
+ delete this._currentFlowStep._values;
885
+ this._getFlowStepForm().reset();
886
+ }
887
+ }
888
+ _generateFlowsId(list, force = false) {
889
+ return this._generateId('f', list, force, true);
890
+ }
891
+ _generatePlanFlowsId(plan, force = false) {
892
+ return this._generateId(plan.id, plan.flows, force, true);
893
+ }
894
+ _generateFlowStepId(flowId, flowKey, position) {
895
+ return `${flowId}_${flowKey}_${position}`;
896
+ }
897
+ _generateId(prefix, list, force = false, isFlow = false) {
898
+ if (list == null) {
899
+ return list;
900
+ }
901
+ return deepClone(list).map((e, index) => {
902
+ const _id = `${prefix}_${index}`;
903
+ if (isFlow) {
904
+ if (e.pre) {
905
+ e.pre.forEach((step, stepIndex) => (step._id = this._generateFlowStepId(_id, 'pre', stepIndex)));
906
+ }
907
+ if (e.post) {
908
+ e.post.forEach((step, stepIndex) => (step._id = this._generateFlowStepId(_id, 'post', stepIndex)));
909
+ }
910
+ }
911
+ if (force || e._id == null) {
912
+ return Object.assign(Object.assign({}, e), { _id });
913
+ }
914
+ return e;
915
+ });
916
+ }
917
+ getChildren() {
918
+ return [
919
+ ...Array.from(this.shadowRoot.querySelectorAll('gv-flow')),
920
+ ...Array.from(this.shadowRoot.querySelectorAll('gv-resizable-views')),
921
+ ];
922
+ }
923
+ getUpdateComplete() {
924
+ const _super = Object.create(null, {
925
+ getUpdateComplete: { get: () => super.getUpdateComplete }
926
+ });
927
+ return __awaiter(this, void 0, void 0, function* () {
928
+ yield _super.getUpdateComplete.call(this);
929
+ yield Promise.all(this.getChildren().map((e) => e.updateComplete));
930
+ });
931
+ }
932
+ shouldUpdate(changedProperties) {
933
+ // Just refresh gv-flow components
934
+ if (changedProperties.has('_dragPolicy')) {
935
+ this.shadowRoot.querySelectorAll('gv-flow').forEach((flow) => (flow.dragPolicy = this._dragPolicy));
936
+ return false;
937
+ }
938
+ if (changedProperties.has('_dropPolicy')) {
939
+ this.shadowRoot.querySelectorAll('gv-flow').forEach((flow) => (flow.dropPolicy = this._dropPolicy));
940
+ return false;
941
+ }
942
+ return super.shouldUpdate(changedProperties);
943
+ }
944
+ updated(props) {
945
+ if (props.has('documentation') && this.documentation != null && this.selectedFlowsId.length > 1) {
946
+ this._updateSelectedFlows([this.selectedFlowsId[0]]);
947
+ }
948
+ }
949
+ _renderFlowStepForm(readonlyMode) {
950
+ const values = this._currentFlowStep._values || this._currentFlowStep._initialValues;
951
+ const groups = [
952
+ { items: ['commonDescription', 'commonCondition'] },
953
+ {
954
+ name: i18n('gv-policy-studio.policy-settings'),
955
+ default: true,
956
+ },
957
+ ];
958
+ return html `${cache(this._flowStepSchema && this._currentFlowStep
959
+ ? html `<div class="flow-step__container">
960
+ <div class="flow-step__form">
961
+ <gv-schema-form
962
+ .id="${FLOW_STEP_FORM_ID}"
963
+ .schema="${this._flowStepSchema}"
964
+ .icon="design:edit"
965
+ has-header
966
+ validate-on-render
967
+ .values="${values}"
968
+ .dirty="${this._currentFlowStep._values != null}"
969
+ ?readonly="${readonlyMode}"
970
+ scrollable
971
+ .groups="${groups}"
972
+ @gv-schema-form:change="${this._onChangeFlowStep}"
973
+ @gv-schema-form:reset="${this._onResetFlowStep}"
974
+ @gv-schema-form:fetch-resources="${this._onFetchResources}"
975
+ @gv-schema-form:submit="${this._onSubmitFlowStep}"
976
+ >
977
+ <div slot="title" class="flow-step__form-title">${this._currentFlowStep.step.name}</div>
978
+ <gv-button
979
+ slot="header-left"
980
+ icon="general:close"
981
+ outlined
982
+ small
983
+ @gv-button:click="${this._onCloseFlowStepForm}"
984
+ title="Close"
985
+ ></gv-button>
986
+ <gv-button
987
+ slot="header-left"
988
+ icon="home:book"
989
+ ?disabled="${this.documentation != null}"
990
+ outlined
991
+ small
992
+ @gv-button:click="${this._onOpenDocumentationFromForm}"
993
+ title="Open documentation"
994
+ ></gv-button>
995
+ </gv-schema-form>
996
+ </div>
997
+ </div>`
998
+ : '')}`;
999
+ }
1000
+ _onCloseDocumentation() {
1001
+ this.documentation = null;
1002
+ if (this._currentFlowStep == null) {
1003
+ this._maximizeTopView();
1004
+ }
1005
+ else {
1006
+ localStorage.setItem('gv-policy-studio:keep-documentation-close', true);
1007
+ }
1008
+ }
1009
+ _onDeleteFlow({ detail }) {
1010
+ const flowId = detail.content._id;
1011
+ const { flows } = this._findFlowCollection(flowId);
1012
+ const flow = flows.find((f) => f._id === flowId);
1013
+ this._deleteFlow(flows, flow);
1014
+ }
1015
+ get definedFlows() {
1016
+ return this._definition && this._definition.flows ? this._definition.flows : [];
1017
+ }
1018
+ get definedPlans() {
1019
+ return this._definition && this._definition.plans ? this._definition.plans : [];
1020
+ }
1021
+ get definedResources() {
1022
+ return this._definition && this._definition.resources ? this._definition.resources : [];
1023
+ }
1024
+ get definedProperties() {
1025
+ return this._definition && this._definition.properties ? this._definition.properties : [];
1026
+ }
1027
+ _onDuplicateFlow({ detail }) {
1028
+ return __awaiter(this, void 0, void 0, function* () {
1029
+ try {
1030
+ yield this._askToValidateForms();
1031
+ const flowId = detail.content._id;
1032
+ const { plan, flows } = this._findFlowCollection(flowId);
1033
+ this._addFlow(flows, this._findFlowById(flowId));
1034
+ if (plan != null) {
1035
+ let planIndex = null;
1036
+ this.definedPlans.find((p, i) => {
1037
+ if (p.id === plan.id) {
1038
+ planIndex = i;
1039
+ return true;
1040
+ }
1041
+ return false;
1042
+ });
1043
+ plan.flows = flows;
1044
+ this.definedPlans[planIndex].flows = this._generatePlanFlowsId(plan, true);
1045
+ this._updateSelectedFlows([this.definedPlans[planIndex].flows[flows.length - 1]._id]);
1046
+ }
1047
+ else {
1048
+ this._definition.flows = this._generateFlowsId(this._definition.flows);
1049
+ this._updateSelectedFlows([this._definition.flows[this._definition.flows.length - 1]._id]);
1050
+ }
1051
+ }
1052
+ catch (err) {
1053
+ this._currentAskConfirmation = null;
1054
+ }
1055
+ });
1056
+ }
1057
+ _onChangeFlowState({ detail }) {
1058
+ const flow = this._findFlowById(detail.content._id);
1059
+ flow.enabled = detail.enabled;
1060
+ flow._dirty = true;
1061
+ this.isDirty = true;
1062
+ this.dispatchChange();
1063
+ }
1064
+ _onAddFlowPlan({ detail }) {
1065
+ return __awaiter(this, void 0, void 0, function* () {
1066
+ try {
1067
+ yield this._askToValidateForms();
1068
+ this._addFlow(this.definedPlans[detail.planIndex].flows);
1069
+ this.definedPlans[detail.planIndex].flows = this._generatePlanFlowsId(this.definedPlans[detail.planIndex]);
1070
+ this._updateSelectedFlows([this.definedPlans[detail.planIndex].flows[this.definedPlans[detail.planIndex].flows.length - 1]._id]);
1071
+ }
1072
+ catch (err) {
1073
+ this._currentAskConfirmation = null;
1074
+ }
1075
+ });
1076
+ }
1077
+ _onAddFlow() {
1078
+ return __awaiter(this, void 0, void 0, function* () {
1079
+ try {
1080
+ yield this._askToValidateForms();
1081
+ this._addFlow(this._definition.flows);
1082
+ this._definition.flows = this._generateFlowsId(this._definition.flows);
1083
+ this._updateSelectedFlows([this._definition.flows[this._definition.flows.length - 1]._id]);
1084
+ }
1085
+ catch (err) {
1086
+ this._currentAskConfirmation = null;
1087
+ }
1088
+ });
1089
+ }
1090
+ _addFlow(collection, duplicate = null) {
1091
+ const flow = duplicate == null
1092
+ ? this._createFlowFromSchema()
1093
+ : Object.assign(Object.assign({}, duplicate), { _id: null,
1094
+ // reset the id to avoid issue with AM that persists the ID
1095
+ id: null, _dirty: true });
1096
+ collection.push(flow);
1097
+ this.isDirty = true;
1098
+ this.dispatchChange();
1099
+ return collection;
1100
+ }
1101
+ _createFlowFromSchema() {
1102
+ const newFlow = {
1103
+ name: '',
1104
+ pre: [],
1105
+ post: [],
1106
+ _dirty: true,
1107
+ };
1108
+ return this._instantiate(this.flowSchema.properties, newFlow);
1109
+ }
1110
+ _instantiate(propertiesDefinition, initiator = {}) {
1111
+ const property = Object.assign({}, initiator);
1112
+ if (propertiesDefinition) {
1113
+ for (const key of Object.keys(propertiesDefinition)) {
1114
+ const entry = propertiesDefinition[key];
1115
+ if (entry.type === 'object') {
1116
+ property[key] = this._instantiate(entry.properties);
1117
+ }
1118
+ if (entry.default !== undefined) {
1119
+ property[key] = entry.default;
1120
+ }
1121
+ else if (entry.type === 'string') {
1122
+ property[key] = '';
1123
+ }
1124
+ }
1125
+ }
1126
+ return property;
1127
+ }
1128
+ _deleteFlow(collection, flow) {
1129
+ const index = collection.indexOf(flow);
1130
+ collection.splice(index, 1);
1131
+ const selectedFlows = this.selectedFlowsId.filter((flowId) => flowId !== flow._id);
1132
+ if (selectedFlows.length === 1) {
1133
+ this._updateSelectedFlows(selectedFlows);
1134
+ }
1135
+ else {
1136
+ this._selectFirstFlow(true);
1137
+ }
1138
+ this._refresh();
1139
+ this.isDirty = true;
1140
+ this.dispatchChange();
1141
+ }
1142
+ _findFlowIndex(list, id) {
1143
+ let index = null;
1144
+ list.find((f, i) => {
1145
+ if (f._id === id) {
1146
+ index = i;
1147
+ return true;
1148
+ }
1149
+ return false;
1150
+ });
1151
+ return index;
1152
+ }
1153
+ _onReorderFlows({ detail: { plan } }) {
1154
+ return __awaiter(this, void 0, void 0, function* () {
1155
+ try {
1156
+ yield this._askToValidateForms();
1157
+ this.isDirty = true;
1158
+ this.dispatchChange();
1159
+ if (plan != null) {
1160
+ const newOrder = this._generatePlanFlowsId(plan, true);
1161
+ if (this.selectedFlowsId) {
1162
+ this._updateSelectedFlows(this.selectedFlowsId.map((flowId) => {
1163
+ const index = this._findFlowIndex(plan.flows, flowId);
1164
+ return index != null ? newOrder[index]._id : flowId;
1165
+ }));
1166
+ }
1167
+ plan.flows = newOrder;
1168
+ }
1169
+ else {
1170
+ const newOrder = this._generateFlowsId(this._definition.flows, true);
1171
+ if (this.selectedFlowsId) {
1172
+ this._updateSelectedFlows(this.selectedFlowsId.map((flowId) => {
1173
+ const index = this._findFlowIndex(this._definition.flows, flowId);
1174
+ return index != null ? newOrder[index]._id : flowId;
1175
+ }));
1176
+ }
1177
+ this._definition.flows = newOrder;
1178
+ }
1179
+ }
1180
+ catch (err) {
1181
+ this._currentAskConfirmation = false;
1182
+ }
1183
+ });
1184
+ }
1185
+ _onSearchPolicy({ detail }) {
1186
+ this._searchPolicyQuery = detail;
1187
+ }
1188
+ _onClearPolicy() {
1189
+ this._searchPolicyQuery = null;
1190
+ }
1191
+ _onSearchFlows({ detail }) {
1192
+ this._searchFlowQuery = detail;
1193
+ }
1194
+ _onClearFlows() {
1195
+ this._searchFlowQuery = null;
1196
+ }
1197
+ _filterNotValidStep(step) {
1198
+ return step._new !== true;
1199
+ }
1200
+ _removePrivateProperties(o) {
1201
+ const copy = Object.assign({}, o);
1202
+ Object.keys(o)
1203
+ .filter((key) => key.startsWith('_'))
1204
+ .forEach((key) => {
1205
+ delete copy[key];
1206
+ });
1207
+ return copy;
1208
+ }
1209
+ _submitOrConfirmForms() {
1210
+ return [...this.shadowRoot.querySelectorAll('gv-schema-form')]
1211
+ .filter((form) => {
1212
+ const isValid = form.isValid();
1213
+ if (isValid) {
1214
+ form.submit();
1215
+ }
1216
+ else {
1217
+ form.dirty = true;
1218
+ }
1219
+ return !isValid;
1220
+ })
1221
+ .map((form) => form.confirm());
1222
+ }
1223
+ getPropertiesElement() {
1224
+ return this.shadowRoot.querySelector('gv-properties');
1225
+ }
1226
+ _checkCurrentFlowStep() {
1227
+ return __awaiter(this, void 0, void 0, function* () {
1228
+ if (this._currentFlowStep && this.selectedFlowsId) {
1229
+ const closePromises = this.selectedFlowsId
1230
+ .map((flowId) => {
1231
+ const flow = this._findFlowById(flowId);
1232
+ const currentStep = [...flow.pre, ...flow.post].find((step) => step._id === this._currentFlowStep.step._id);
1233
+ if (currentStep == null) {
1234
+ return this._closeFlowStepForm(true);
1235
+ }
1236
+ return null;
1237
+ })
1238
+ .filter((p) => p !== null);
1239
+ return Promise.all(closePromises);
1240
+ }
1241
+ return Promise.resolve();
1242
+ });
1243
+ }
1244
+ saved() {
1245
+ if (this.isDirty) {
1246
+ this._initialDefinition = deepClone(this._definitionSaved);
1247
+ this._definition = deepClone(this._definitionSaved);
1248
+ this._definitionSaved = null;
1249
+ this.isDirty = false;
1250
+ this._checkCurrentFlowStep();
1251
+ this.definedPlans.forEach((plan) => {
1252
+ plan.flows.forEach((flow) => (flow._dirty = false));
1253
+ });
1254
+ this.definedFlows.forEach((flow) => (flow._dirty = false));
1255
+ this.getChildren().forEach((e) => e.requestUpdate());
1256
+ }
1257
+ }
1258
+ _mapFlowsWithValidStep(flows) {
1259
+ return flows.map((flow) => {
1260
+ flow.pre = flow.pre.filter(this._filterNotValidStep);
1261
+ flow.post = flow.post.filter(this._filterNotValidStep);
1262
+ return flow;
1263
+ });
1264
+ }
1265
+ _buildDefinitionToSave() {
1266
+ // Copy definition and remove invalid step
1267
+ // Keep private properties like _id and others stuff useful for render
1268
+ const flows = this._mapFlowsWithValidStep(this._definition.flows || []);
1269
+ const definition = Object.assign(Object.assign({}, this._definition), { flows });
1270
+ if (this._definition.plans != null) {
1271
+ const plans = this._definition.plans.map((plan) => (Object.assign(Object.assign({}, plan), { flows: this._mapFlowsWithValidStep(plan.flows) })));
1272
+ return Object.assign(Object.assign({}, definition), { plans });
1273
+ }
1274
+ return definition;
1275
+ }
1276
+ _mapFlowsWithValidProperty(flows) {
1277
+ return flows.map((f) => {
1278
+ const flow = this._removePrivateProperties(f);
1279
+ flow.pre = flow.pre.map(this._removePrivateProperties);
1280
+ flow.post = flow.post.map(this._removePrivateProperties);
1281
+ return flow;
1282
+ });
1283
+ }
1284
+ _buildDefinitionToSend(definitionToSave) {
1285
+ // Copy definition and remove all private properties
1286
+ const flows = this._mapFlowsWithValidProperty(definitionToSave.flows);
1287
+ let definition = Object.assign(Object.assign({}, this._definition), { flows });
1288
+ if (this._definition.plans != null) {
1289
+ const plans = definitionToSave.plans.map((plan) => (Object.assign(Object.assign({}, plan), { flows: this._mapFlowsWithValidProperty(plan.flows) })));
1290
+ definition = Object.assign(Object.assign({}, definition), { plans });
1291
+ }
1292
+ if (this._definition.properties != null) {
1293
+ const properties = this._definition.properties.map(this._removePrivateProperties);
1294
+ definition = Object.assign(Object.assign({}, definition), { properties });
1295
+ }
1296
+ if (this._definition.resources != null) {
1297
+ const resources = this._definition.resources.map(this._removePrivateProperties);
1298
+ definition = Object.assign(Object.assign({}, definition), { resources });
1299
+ }
1300
+ return definition;
1301
+ }
1302
+ get filteredFlows() {
1303
+ if (this._flowFilter.length === 0 || this._flowFilter.includes('api')) {
1304
+ return this.definedFlows;
1305
+ }
1306
+ return null;
1307
+ }
1308
+ get filteredPlans() {
1309
+ if (this._flowFilter.length === 0 || this._flowFilter.includes('plan')) {
1310
+ return this.definedPlans;
1311
+ }
1312
+ return null;
1313
+ }
1314
+ _onFilterFlows({ detail }) {
1315
+ if (this._flowFilter.includes(detail.id)) {
1316
+ this._flowFilter = [];
1317
+ }
1318
+ else {
1319
+ this._flowFilter = [detail.id];
1320
+ }
1321
+ }
1322
+ _getFilteredPolicies() {
1323
+ if (this._policyFilter.length > 0) {
1324
+ return this.policies.filter((policy) => {
1325
+ return ((policy.onRequest && this._policyFilter.includes('onRequest')) || (policy.onResponse && this._policyFilter.includes('onResponse')));
1326
+ });
1327
+ }
1328
+ return this.policies;
1329
+ }
1330
+ _onFilterPolicies({ detail }) {
1331
+ if (this._policyFilter.includes(detail.id)) {
1332
+ this._policyFilter = [];
1333
+ }
1334
+ else {
1335
+ this._policyFilter = [detail.id];
1336
+ }
1337
+ }
1338
+ _renderContent(readonlyMode) {
1339
+ return html `<div id="design" slot="content" class="design">
1340
+ <gv-resizable-views no-overflow>
1341
+ <div slot="top">${this._renderFlow(0, true, readonlyMode)}</div>
1342
+
1343
+ <div slot="bottom">
1344
+ ${this._renderFlow(1, false, readonlyMode)} ${this._renderPolicy(readonlyMode)} ${this._renderFlowForm(readonlyMode)}
1345
+ </div>
1346
+ </gv-resizable-views>
1347
+ ${readonlyMode !== true
1348
+ ? html `<gv-policy-studio-menu
1349
+ class="right-menu"
1350
+ ?disabled="${this._currentAskConfirmation}"
1351
+ .policies="${this._getFilteredPolicies()}"
1352
+ .selectedIds="${[this._currentPolicyId]}"
1353
+ .query="${this._searchPolicyQuery}"
1354
+ ?has-policy-filter="${this._policyFilterOptions != null}"
1355
+ ?readonly="${readonlyMode}"
1356
+ @gv-policy-studio-menu:target-policy="${this._onTargetPolicy}"
1357
+ @gv-policy-studio-menu:fetch-documentation="${this._onOpenDocumentationFromMenu}"
1358
+ @gv-policy-studio-menu:dragend-policy="${this._onDragEndPolicy}"
1359
+ >
1360
+ <div slot="header" class="search-policies">
1361
+ ${this._policyFilterOptions != null
1362
+ ? html `<gv-option
1363
+ ?disabled="${this._currentAskConfirmation}"
1364
+ .options="${this._policyFilterOptions}"
1365
+ multiple
1366
+ outlined
1367
+ .value="${this._policyFilter}"
1368
+ small
1369
+ @gv-option:select="${this._onFilterPolicies}"
1370
+ ></gv-option>`
1371
+ : ''}
1372
+ <gv-input
1373
+ id="search-policy"
1374
+ ?disabled="${this._currentAskConfirmation}"
1375
+ placeholder="Filter policies (Shift + Alt + Space)"
1376
+ type="search"
1377
+ small
1378
+ @gv-input:input="${this._onSearchPolicy}"
1379
+ @gv-input:clear="${this._onClearPolicy}"
1380
+ ></gv-input>
1381
+ </div>
1382
+ </gv-policy-studio-menu>`
1383
+ : ''}
1384
+ </div>`;
1385
+ }
1386
+ _renderFlowForm(readonlyMode) {
1387
+ if (this.flowSchema && this._flowStepSchema == null && this.documentation == null && this.selectedFlowsId.length === 1) {
1388
+ const flow = this.getSelectedFlow();
1389
+ if (flow) {
1390
+ const values = deepClone(flow);
1391
+ return html `<div slot="content" class="flow-settings">
1392
+ <gv-schema-form
1393
+ .schema="${this.flowSchema}"
1394
+ id="settings-form"
1395
+ .values="${values}"
1396
+ has-header
1397
+ scrollable
1398
+ ?readonly="${readonlyMode}"
1399
+ @gv-schema-form:cancel="${this._onCancelFlow}"
1400
+ @gv-schema-form:submit="${this._onSubmitFlow}"
1401
+ >
1402
+ <div slot="title" class="flow-step__form-title">Flow configuration</div>
1403
+ </gv-schema-form>
1404
+ </div>`;
1405
+ }
1406
+ }
1407
+ }
1408
+ render() {
1409
+ const readonlyMode = this._getReadonlyModeForDesign();
1410
+ return html `<div class="box">
1411
+ <gv-policy-studio-menu
1412
+ class="left-menu"
1413
+ .api-name="${this._definition.name}"
1414
+ .flows="${this.filteredFlows}"
1415
+ .plans="${this.filteredPlans}"
1416
+ .selectedIds="${this.selectedFlowsId}"
1417
+ ?disabled="${this._currentAskConfirmation}"
1418
+ ?sortable="${this.sortable && this.readonly !== true}"
1419
+ ?readonly="${this.readonly}"
1420
+ ?readonlyPlans="${this.readonlyPlans}"
1421
+ flows-title="${this.flowsTitle}"
1422
+ .query="${this._searchFlowQuery}"
1423
+ ?can-add="${this.canAdd && !this.readonly}"
1424
+ @gv-policy-studio-menu:reorder-flows="${this._onReorderFlows}"
1425
+ @gv-policy-studio-menu:change-flow-state="${this._onChangeFlowState}"
1426
+ @gv-policy-studio-menu:add-flow="${this._onAddFlow}"
1427
+ @gv-policy-studio-menu:add-flow-plan="${this._onAddFlowPlan}"
1428
+ @gv-policy-studio-menu:delete-flow="${this._onDeleteFlow}"
1429
+ @gv-policy-studio-menu:duplicate-flow="${this._onDuplicateFlow}"
1430
+ @gv-policy-studio-menu:select-flows="${this._onSelectFlows}"
1431
+ >
1432
+ <div slot="header" class="header-actions">
1433
+ ${this._flowFilterOptions != null
1434
+ ? html `<gv-option
1435
+ ?disabled="${this._currentAskConfirmation}"
1436
+ .options="${this._flowFilterOptions}"
1437
+ multiple
1438
+ outlined
1439
+ .value="${this._flowFilter}"
1440
+ small
1441
+ @gv-option:select="${this._onFilterFlows}"
1442
+ ></gv-option>`
1443
+ : ''}
1444
+ <gv-input
1445
+ ?disabled="${this._currentAskConfirmation}"
1446
+ id="search-flow"
1447
+ placeholder="Filter flows (Alt + Space)"
1448
+ type="search"
1449
+ small
1450
+ @gv-input:input="${this._onSearchFlows}"
1451
+ @gv-input:clear="${this._onClearFlows}"
1452
+ ></gv-input>
1453
+ </div>
1454
+ </gv-policy-studio-menu>
1455
+ ${this._renderContent(readonlyMode)}
1456
+ </div>`;
1457
+ }
1458
+ /**
1459
+ * Determine if the design view should be in readonly mode or not
1460
+ * It is in readonly mode if:
1461
+ * the readonly attribute is set to true
1462
+ * OR
1463
+ * the main selected flow belongs to a plan and the readonly-plans attribute is set to true
1464
+ * OR
1465
+ * the second flow for comparison belongs to a plan and the readonly-plans attribute is set to true
1466
+ * @returns {boolean|*|{type: BooleanConstructor}|{attribute: string, type: BooleanConstructor}|{type: *}|{attribute: string, type: *}}
1467
+ * @private
1468
+ */
1469
+ _getReadonlyModeForDesign() {
1470
+ if (this.readonly) {
1471
+ return true;
1472
+ }
1473
+ const flow = this.getSelectedFlow(0);
1474
+ if (!flow) {
1475
+ return false;
1476
+ }
1477
+ const { plan: flowPlan } = this._findFlowCollection(flow._id);
1478
+ const readonlyMode = flowPlan && this.readonlyPlans;
1479
+ if (readonlyMode) {
1480
+ return true;
1481
+ }
1482
+ const comparedFlow = this.getSelectedFlow(1);
1483
+ if (!comparedFlow) {
1484
+ return false;
1485
+ }
1486
+ const { plan: comparedFlowPlan } = this._findFlowCollection(comparedFlow._id);
1487
+ return comparedFlowPlan && this.readonlyPlans;
1488
+ }
1489
+ }
1490
+ window.customElements.define('gv-design', GvDesign);
1491
+ //# sourceMappingURL=gv-design.js.map