@microsoft/vscode-ui 1.0.1-alpha.0028ae747.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/build/ui.js ADDED
@@ -0,0 +1,938 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation.
3
+ // Licensed under the MIT license.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.VSCodeUI = exports.sleep = void 0;
6
+ const tslib_1 = require("tslib");
7
+ const lodash_1 = require("lodash");
8
+ const path = tslib_1.__importStar(require("path"));
9
+ const vscode_1 = require("vscode");
10
+ const teamsfx_api_1 = require("@microsoft/teamsfx-api");
11
+ const progressHandler_1 = require("./progressHandler");
12
+ const error_1 = require("./error");
13
+ const localize_1 = require("./localize");
14
+ async function sleep(ms) {
15
+ await new Promise((resolve) => setTimeout(resolve, ms));
16
+ await new Promise((resolve) => setTimeout(resolve, 0));
17
+ }
18
+ exports.sleep = sleep;
19
+ function getOptionItem(item) {
20
+ return {
21
+ id: item.id,
22
+ label: item.label,
23
+ description: item.description,
24
+ detail: item.detail,
25
+ data: item.data,
26
+ };
27
+ }
28
+ function convertToFxQuickPickItems(options) {
29
+ if (options && options.length > 0 && typeof options[0] === "string") {
30
+ return options.map((option) => {
31
+ return { id: option, label: option };
32
+ });
33
+ }
34
+ else {
35
+ const result = [];
36
+ const candidates = [...options];
37
+ while (candidates.length > 0) {
38
+ const groupName = candidates[0].groupName;
39
+ const group = lodash_1.remove(candidates, (option) => option.groupName === groupName);
40
+ if (groupName) {
41
+ result.push({
42
+ id: groupName,
43
+ label: groupName,
44
+ kind: vscode_1.QuickPickItemKind.Separator,
45
+ });
46
+ }
47
+ result.push(...group.map((option) => {
48
+ var _a;
49
+ return {
50
+ id: option.id,
51
+ label: option.label,
52
+ description: option.description,
53
+ detail: option.detail,
54
+ data: option.data,
55
+ buttons: (_a = option.buttons) === null || _a === void 0 ? void 0 : _a.map((button) => {
56
+ return { iconPath: new vscode_1.ThemeIcon(button.iconPath), tooltip: button.tooltip };
57
+ }),
58
+ };
59
+ }));
60
+ }
61
+ return result;
62
+ }
63
+ }
64
+ function cloneSet(set) {
65
+ const res = new Set();
66
+ for (const e of set)
67
+ res.add(e);
68
+ return res;
69
+ }
70
+ function isSame(set1, set2) {
71
+ for (const i of set1) {
72
+ if (!set2.has(i))
73
+ return false;
74
+ }
75
+ for (const i of set2) {
76
+ if (!set1.has(i))
77
+ return false;
78
+ }
79
+ return true;
80
+ }
81
+ /***
82
+ * This is the default implementation of UserInteraction in vscode.
83
+ */
84
+ class VSCodeUI {
85
+ constructor(terminalName, assembleError, localizer) {
86
+ this.terminalName = terminalName;
87
+ this.assembleError = assembleError;
88
+ this.localizer = localizer || new localize_1.DefaultLocalizer();
89
+ }
90
+ async selectOption(config) {
91
+ if (typeof config.options === "object" && config.options.length === 0) {
92
+ return teamsfx_api_1.err(new error_1.EmptyOptionsError(this.localizer.emptyOptionErrorMessage(), this.localizer.emptyOptionErrorDisplayMessage()));
93
+ }
94
+ const disposables = [];
95
+ try {
96
+ const quickPick = vscode_1.window.createQuickPick();
97
+ quickPick.title = config.title;
98
+ const buttons = config.buttons
99
+ ? config.buttons.map((button) => {
100
+ return {
101
+ iconPath: new vscode_1.ThemeIcon(button.icon),
102
+ tooltip: button.tooltip,
103
+ };
104
+ })
105
+ : [];
106
+ if (config.step && config.step > 1) {
107
+ quickPick.buttons = [vscode_1.QuickInputButtons.Back, ...buttons];
108
+ }
109
+ else {
110
+ quickPick.buttons = buttons;
111
+ }
112
+ quickPick.placeholder = config.placeholder;
113
+ quickPick.ignoreFocusOut = true;
114
+ quickPick.matchOnDescription = true;
115
+ quickPick.matchOnDetail = true;
116
+ quickPick.canSelectMany = false;
117
+ return await new Promise((resolve) => {
118
+ let options = [];
119
+ let defaultValue = undefined;
120
+ let isSkip = false;
121
+ const onDidAccept = async () => {
122
+ const selectedItems = quickPick.selectedItems;
123
+ if (selectedItems && selectedItems.length > 0) {
124
+ const item = selectedItems[0];
125
+ let result;
126
+ if (typeof options[0] === "string" ||
127
+ config.returnObject === undefined ||
128
+ config.returnObject === false) {
129
+ result = item.id;
130
+ if (config.validation) {
131
+ try {
132
+ const validateRes = await config.validation(result);
133
+ if (validateRes) {
134
+ return;
135
+ }
136
+ }
137
+ catch (e) {
138
+ resolve(teamsfx_api_1.err(this.assembleError(e)));
139
+ }
140
+ }
141
+ }
142
+ else
143
+ result = getOptionItem(item);
144
+ resolve(teamsfx_api_1.ok({ type: isSkip ? "skip" : "success", result: result }));
145
+ }
146
+ };
147
+ const loadDynamicData = async () => {
148
+ quickPick.busy = true;
149
+ quickPick.placeholder = this.localizer.loadingOptionsPlaceholder();
150
+ try {
151
+ if (typeof config.options === "function") {
152
+ options = await config.options();
153
+ }
154
+ else {
155
+ options = config.options;
156
+ }
157
+ if (typeof config.default === "function") {
158
+ defaultValue = await config.default();
159
+ }
160
+ else {
161
+ defaultValue = config.default;
162
+ }
163
+ }
164
+ catch (e) {
165
+ resolve(teamsfx_api_1.err(this.assembleError(e)));
166
+ }
167
+ };
168
+ const onDataLoaded = () => {
169
+ quickPick.busy = false;
170
+ quickPick.placeholder = config.placeholder;
171
+ quickPick.items = convertToFxQuickPickItems(options);
172
+ if (config.skipSingleOption && options.length === 1) {
173
+ quickPick.selectedItems = [quickPick.items[0]];
174
+ isSkip = true;
175
+ void onDidAccept();
176
+ return;
177
+ }
178
+ if (defaultValue) {
179
+ if (options && options.length > 0 && typeof options[0] === "string") {
180
+ const defaultOption = options.find((o) => o == defaultValue);
181
+ if (defaultOption) {
182
+ const newItems = options.filter((o) => o != defaultValue);
183
+ newItems.unshift(defaultOption);
184
+ quickPick.items = convertToFxQuickPickItems(newItems);
185
+ }
186
+ }
187
+ else {
188
+ const defaultOption = options.find((o) => o.id == defaultValue);
189
+ if (defaultOption) {
190
+ const newItems = options.filter((o) => o.id != defaultValue);
191
+ newItems.unshift(defaultOption);
192
+ quickPick.items = convertToFxQuickPickItems(newItems);
193
+ }
194
+ }
195
+ }
196
+ };
197
+ disposables.push(quickPick.onDidAccept(onDidAccept), quickPick.onDidHide(() => {
198
+ resolve(teamsfx_api_1.err(new error_1.UserCancelError(this.localizer.cancelErrorMessage(), this.localizer.cancelErrorDisplayMessage())));
199
+ }), quickPick.onDidTriggerButton(async (button) => {
200
+ var _a;
201
+ if (button === vscode_1.QuickInputButtons.Back)
202
+ resolve(teamsfx_api_1.ok({ type: "back" }));
203
+ else if (config.buttons && buttons.indexOf(button) !== -1) {
204
+ const curButton = (_a = config.buttons) === null || _a === void 0 ? void 0 : _a.find((btn) => {
205
+ return (btn.icon === button.iconPath.id && btn.tooltip === button.tooltip);
206
+ });
207
+ if (curButton) {
208
+ await vscode_1.commands.executeCommand(curButton.command);
209
+ }
210
+ }
211
+ else {
212
+ quickPick.selectedItems = quickPick.activeItems;
213
+ await onDidAccept();
214
+ }
215
+ }), quickPick.onDidTriggerItemButton(async (event) => {
216
+ var _a;
217
+ const itemOptions = options;
218
+ if (itemOptions.length > 0 && typeof itemOptions[0] === "string") {
219
+ return;
220
+ }
221
+ const triggerItem = itemOptions.find((singleOption) => {
222
+ if (typeof singleOption !== "string") {
223
+ return singleOption.id === event.item.id;
224
+ }
225
+ });
226
+ if (triggerItem) {
227
+ const triggerButton = (_a = triggerItem.buttons) === null || _a === void 0 ? void 0 : _a.find((button) => {
228
+ return button.iconPath === event.button.iconPath.id;
229
+ });
230
+ if (triggerButton) {
231
+ await vscode_1.commands.executeCommand(triggerButton.command, event.item);
232
+ }
233
+ }
234
+ }));
235
+ disposables.push(quickPick);
236
+ if (typeof config.options === "function" || typeof config.default === "function") {
237
+ // try to load dynamic data in a very short time
238
+ const timeoutPromise = new Promise((resolve) => {
239
+ setTimeout(resolve, 500, this.localizer.loadingOptionsTimeoutMessage());
240
+ });
241
+ Promise.race([loadDynamicData(), timeoutPromise])
242
+ .then((value) => {
243
+ if (value != this.localizer.loadingOptionsTimeoutMessage()) {
244
+ if (config.skipSingleOption && options.length === 1) {
245
+ quickPick.items = convertToFxQuickPickItems(options);
246
+ quickPick.selectedItems = [quickPick.items[0]];
247
+ isSkip = true;
248
+ void onDidAccept();
249
+ return;
250
+ }
251
+ else {
252
+ onDataLoaded();
253
+ quickPick.show();
254
+ }
255
+ }
256
+ else {
257
+ quickPick.show();
258
+ loadDynamicData()
259
+ .then(onDataLoaded)
260
+ .catch((e) => resolve(teamsfx_api_1.err(this.assembleError(e))));
261
+ }
262
+ })
263
+ .catch((e) => resolve(teamsfx_api_1.err(this.assembleError(e))));
264
+ }
265
+ else {
266
+ options = config.options;
267
+ defaultValue = config.default;
268
+ onDataLoaded();
269
+ quickPick.show();
270
+ }
271
+ });
272
+ }
273
+ finally {
274
+ disposables.forEach((d) => {
275
+ d.dispose();
276
+ });
277
+ }
278
+ }
279
+ async selectOptions(config) {
280
+ if (typeof config.options === "object" && config.options.length === 0) {
281
+ return teamsfx_api_1.err(new error_1.EmptyOptionsError(this.localizer.emptyOptionErrorMessage(), this.localizer.emptyOptionErrorDisplayMessage()));
282
+ }
283
+ const disposables = [];
284
+ try {
285
+ const quickPick = vscode_1.window.createQuickPick();
286
+ quickPick.title = config.title;
287
+ if (config.step && config.step > 1) {
288
+ quickPick.buttons = [vscode_1.QuickInputButtons.Back];
289
+ }
290
+ quickPick.placeholder = config.placeholder
291
+ ? config.placeholder + this.localizer.multiSelectKeyboardPlaceholder()
292
+ : this.localizer.multiSelectKeyboardPlaceholder();
293
+ quickPick.ignoreFocusOut = true;
294
+ quickPick.matchOnDescription = true;
295
+ quickPick.matchOnDetail = true;
296
+ quickPick.canSelectMany = true;
297
+ const preIds = new Set();
298
+ return await new Promise((resolve) => {
299
+ let options = [];
300
+ let isSkip = false;
301
+ let defaultValue = [];
302
+ const optionMap = new Map();
303
+ const loadDynamicData = async () => {
304
+ quickPick.busy = true;
305
+ quickPick.placeholder = this.localizer.loadingOptionsPlaceholder();
306
+ try {
307
+ if (typeof config.options === "function") {
308
+ options = await config.options();
309
+ }
310
+ else {
311
+ options = config.options;
312
+ }
313
+ if (typeof config.default === "function") {
314
+ defaultValue = await config.default();
315
+ }
316
+ else {
317
+ defaultValue = config.default || [];
318
+ }
319
+ }
320
+ catch (e) {
321
+ resolve(teamsfx_api_1.err(this.assembleError(e)));
322
+ }
323
+ };
324
+ const onDidAccept = async () => {
325
+ const strArray = Array.from(quickPick.selectedItems.map((i) => i.id));
326
+ if (config.validation) {
327
+ const validateRes = await config.validation(strArray);
328
+ if (validateRes) {
329
+ void this.showMessage("error", validateRes, false);
330
+ return;
331
+ }
332
+ }
333
+ let result = strArray;
334
+ if (typeof options[0] === "string" ||
335
+ config.returnObject === undefined ||
336
+ config.returnObject === false)
337
+ result = strArray;
338
+ else
339
+ result = quickPick.selectedItems.map((i) => getOptionItem(i));
340
+ resolve(teamsfx_api_1.ok({ type: isSkip ? "skip" : "success", result: result }));
341
+ };
342
+ const onDataLoaded = () => {
343
+ quickPick.busy = false;
344
+ quickPick.placeholder = config.placeholder;
345
+ quickPick.items = convertToFxQuickPickItems(options);
346
+ for (const item of quickPick.items) {
347
+ optionMap.set(item.id, item);
348
+ }
349
+ if (config.skipSingleOption && options.length === 1) {
350
+ quickPick.selectedItems = [quickPick.items[0]];
351
+ isSkip = true;
352
+ void onDidAccept();
353
+ return;
354
+ }
355
+ if (defaultValue) {
356
+ const selectedItems = [];
357
+ preIds.clear();
358
+ for (const id of defaultValue) {
359
+ const item = optionMap.get(id);
360
+ if (item) {
361
+ selectedItems.push(item);
362
+ preIds.add(id);
363
+ }
364
+ }
365
+ quickPick.selectedItems = selectedItems;
366
+ }
367
+ };
368
+ disposables.push(quickPick.onDidAccept(onDidAccept), quickPick.onDidHide(() => {
369
+ resolve(teamsfx_api_1.err(new error_1.UserCancelError(this.localizer.emptyOptionErrorMessage(), this.localizer.emptyOptionErrorDisplayMessage())));
370
+ }), quickPick.onDidTriggerButton(async (button) => {
371
+ if (button === vscode_1.QuickInputButtons.Back)
372
+ resolve(teamsfx_api_1.ok({ type: "back" }));
373
+ else {
374
+ await onDidAccept();
375
+ }
376
+ }));
377
+ if (config.onDidChangeSelection) {
378
+ const changeHandler = async function (items) {
379
+ let currentIds = new Set();
380
+ for (const item of items) {
381
+ currentIds.add(item.id);
382
+ }
383
+ if (config.onDidChangeSelection) {
384
+ const currentClone = cloneSet(currentIds);
385
+ currentIds = await config.onDidChangeSelection(currentIds, preIds);
386
+ const selectedItems = [];
387
+ preIds.clear();
388
+ for (const id of currentIds) {
389
+ const item = optionMap.get(id);
390
+ if (item) {
391
+ selectedItems.push(item);
392
+ preIds.add(id);
393
+ }
394
+ }
395
+ if (!isSame(currentClone, currentIds)) {
396
+ quickPick.selectedItems = selectedItems;
397
+ }
398
+ }
399
+ };
400
+ disposables.push(quickPick.onDidChangeSelection(changeHandler));
401
+ }
402
+ disposables.push(quickPick);
403
+ if (typeof config.options === "function" || typeof config.default === "function") {
404
+ // try to load dynamic data in a very short time
405
+ const timeoutPromise = new Promise((resolve) => {
406
+ setTimeout(resolve, 500, this.localizer.loadingOptionsTimeoutMessage());
407
+ });
408
+ Promise.race([loadDynamicData(), timeoutPromise])
409
+ .then((value) => {
410
+ if (value != this.localizer.loadingOptionsTimeoutMessage()) {
411
+ if (config.skipSingleOption && options.length === 1) {
412
+ quickPick.items = convertToFxQuickPickItems(options);
413
+ quickPick.selectedItems = [quickPick.items[0]];
414
+ isSkip = true;
415
+ void onDidAccept();
416
+ return;
417
+ }
418
+ else {
419
+ onDataLoaded();
420
+ quickPick.show();
421
+ }
422
+ }
423
+ else {
424
+ quickPick.show();
425
+ loadDynamicData()
426
+ .then(onDataLoaded)
427
+ .catch((e) => resolve(teamsfx_api_1.err(this.assembleError(e))));
428
+ }
429
+ })
430
+ .catch((e) => resolve(teamsfx_api_1.err(this.assembleError(e))));
431
+ }
432
+ else {
433
+ options = config.options;
434
+ defaultValue = config.default;
435
+ onDataLoaded();
436
+ quickPick.show();
437
+ }
438
+ });
439
+ }
440
+ finally {
441
+ disposables.forEach((d) => {
442
+ d.dispose();
443
+ });
444
+ }
445
+ }
446
+ async inputText(config) {
447
+ const disposables = [];
448
+ try {
449
+ const inputBox = vscode_1.window.createInputBox();
450
+ inputBox.title = config.title;
451
+ if (config.step && config.step > 1) {
452
+ inputBox.buttons = [vscode_1.QuickInputButtons.Back];
453
+ }
454
+ inputBox.ignoreFocusOut = true;
455
+ inputBox.password = config.password === true;
456
+ inputBox.prompt = config.prompt;
457
+ return await new Promise((resolve) => {
458
+ let defaultValue = undefined;
459
+ const loadDynamicData = async () => {
460
+ try {
461
+ if (typeof config.default === "function") {
462
+ defaultValue = await config.default();
463
+ }
464
+ }
465
+ catch (e) {
466
+ resolve(teamsfx_api_1.err(this.assembleError(e)));
467
+ }
468
+ };
469
+ const onDataLoaded = () => {
470
+ inputBox.busy = false;
471
+ inputBox.enabled = true;
472
+ inputBox.placeholder = config.placeholder;
473
+ inputBox.value = defaultValue || "";
474
+ };
475
+ const onDidAccept = async () => {
476
+ const validationRes = config.validation
477
+ ? await config.validation(inputBox.value)
478
+ : undefined;
479
+ if (!validationRes) {
480
+ inputBox.enabled = false;
481
+ inputBox.busy = true;
482
+ if (config.additionalValidationOnAccept) {
483
+ const oldValue = inputBox.value;
484
+ inputBox.placeholder = "Validating...";
485
+ inputBox.value = "";
486
+ try {
487
+ const additionalValidationOnAcceptRes = await config.additionalValidationOnAccept(oldValue);
488
+ if (!additionalValidationOnAcceptRes) {
489
+ resolve(teamsfx_api_1.ok({ type: "success", result: oldValue }));
490
+ }
491
+ else {
492
+ inputBox.validationMessage = additionalValidationOnAcceptRes;
493
+ inputBox.busy = false;
494
+ inputBox.enabled = true;
495
+ inputBox.value = oldValue;
496
+ return;
497
+ }
498
+ }
499
+ catch (e) {
500
+ resolve(teamsfx_api_1.err(this.assembleError(e)));
501
+ }
502
+ }
503
+ else {
504
+ resolve(teamsfx_api_1.ok({ type: "success", result: inputBox.value }));
505
+ }
506
+ resolve(teamsfx_api_1.ok({ type: "success", result: inputBox.value }));
507
+ }
508
+ else {
509
+ inputBox.validationMessage = validationRes;
510
+ }
511
+ };
512
+ if (typeof config.default === "function") {
513
+ inputBox.busy = true;
514
+ inputBox.enabled = false;
515
+ inputBox.placeholder = this.localizer.loadingDefaultPlaceholder();
516
+ loadDynamicData()
517
+ .then(onDataLoaded)
518
+ .catch((e) => resolve(teamsfx_api_1.err(this.assembleError(e))));
519
+ }
520
+ else {
521
+ defaultValue = config.default || "";
522
+ onDataLoaded();
523
+ }
524
+ disposables.push(inputBox.onDidChangeValue(async (text) => {
525
+ if (config.validation) {
526
+ const validationRes = config.validation ? await config.validation(text) : undefined;
527
+ if (!!validationRes) {
528
+ inputBox.validationMessage = validationRes;
529
+ }
530
+ else {
531
+ inputBox.validationMessage = undefined;
532
+ }
533
+ }
534
+ }), inputBox.onDidAccept(onDidAccept), inputBox.onDidHide(() => {
535
+ resolve(teamsfx_api_1.err(new error_1.UserCancelError(this.localizer.emptyOptionErrorMessage(), this.localizer.emptyOptionErrorDisplayMessage())));
536
+ }), inputBox.onDidTriggerButton(async (button) => {
537
+ if (button === vscode_1.QuickInputButtons.Back)
538
+ resolve(teamsfx_api_1.ok({ type: "back" }));
539
+ else {
540
+ await onDidAccept();
541
+ }
542
+ }));
543
+ disposables.push(inputBox);
544
+ inputBox.show();
545
+ });
546
+ }
547
+ finally {
548
+ disposables.forEach((d) => {
549
+ d.dispose();
550
+ });
551
+ }
552
+ }
553
+ async selectFolder(config) {
554
+ const disposables = [];
555
+ try {
556
+ const quickPick = vscode_1.window.createQuickPick();
557
+ quickPick.title = config.title;
558
+ if (config.step && config.step > 1) {
559
+ quickPick.buttons = [vscode_1.QuickInputButtons.Back];
560
+ }
561
+ quickPick.placeholder = config.placeholder;
562
+ quickPick.ignoreFocusOut = true;
563
+ quickPick.matchOnDescription = true;
564
+ quickPick.matchOnDetail = true;
565
+ quickPick.canSelectMany = false;
566
+ return await new Promise((resolve) => {
567
+ let defaultValue = undefined;
568
+ const loadDynamicData = async () => {
569
+ try {
570
+ if (typeof config.default === "function") {
571
+ defaultValue = await config.default();
572
+ }
573
+ }
574
+ catch (e) {
575
+ resolve(teamsfx_api_1.err(this.assembleError(e)));
576
+ }
577
+ };
578
+ const onDataLoaded = () => {
579
+ quickPick.busy = false;
580
+ quickPick.placeholder = config.placeholder;
581
+ quickPick.items = [
582
+ ...(defaultValue
583
+ ? [
584
+ {
585
+ id: "default",
586
+ label: this.localizer.defaultFolder(),
587
+ description: defaultValue,
588
+ },
589
+ ]
590
+ : []),
591
+ {
592
+ id: "browse",
593
+ label: `$(folder) ${this.localizer.browse()}`,
594
+ },
595
+ ];
596
+ };
597
+ if (typeof config.default === "function") {
598
+ quickPick.busy = true;
599
+ quickPick.placeholder = this.localizer.loadingDefaultPlaceholder();
600
+ loadDynamicData()
601
+ .then(onDataLoaded)
602
+ .catch((e) => resolve(teamsfx_api_1.err(this.assembleError(e))));
603
+ }
604
+ else {
605
+ defaultValue = config.default;
606
+ onDataLoaded();
607
+ }
608
+ let hideByDialog = false;
609
+ const onDidAccept = async () => {
610
+ const selectedItems = quickPick.selectedItems;
611
+ if (selectedItems && selectedItems.length > 0) {
612
+ const item = selectedItems[0];
613
+ if (item.id === "default") {
614
+ resolve(teamsfx_api_1.ok({ type: "success", result: defaultValue }));
615
+ }
616
+ else {
617
+ hideByDialog = true;
618
+ const uriList = await vscode_1.window.showOpenDialog({
619
+ defaultUri: defaultValue ? vscode_1.Uri.file(defaultValue) : undefined,
620
+ canSelectFiles: false,
621
+ canSelectFolders: true,
622
+ canSelectMany: false,
623
+ title: config.title,
624
+ });
625
+ if (uriList && uriList.length > 0) {
626
+ const result = uriList[0].fsPath;
627
+ resolve(teamsfx_api_1.ok({ type: "success", result: result }));
628
+ }
629
+ else {
630
+ resolve(teamsfx_api_1.err(new error_1.UserCancelError(this.localizer.emptyOptionErrorMessage(), this.localizer.emptyOptionErrorDisplayMessage())));
631
+ }
632
+ }
633
+ }
634
+ };
635
+ disposables.push(quickPick.onDidAccept(onDidAccept), quickPick.onDidHide(() => {
636
+ if (!hideByDialog) {
637
+ resolve(teamsfx_api_1.err(new error_1.UserCancelError(this.localizer.emptyOptionErrorMessage(), this.localizer.emptyOptionErrorDisplayMessage())));
638
+ }
639
+ }), quickPick.onDidTriggerButton((button) => {
640
+ if (button === vscode_1.QuickInputButtons.Back)
641
+ resolve(teamsfx_api_1.ok({ type: "back" }));
642
+ }));
643
+ disposables.push(quickPick);
644
+ quickPick.show();
645
+ });
646
+ }
647
+ finally {
648
+ disposables.forEach((d) => {
649
+ d.dispose();
650
+ });
651
+ }
652
+ }
653
+ async selectFile(config) {
654
+ if (config.default && typeof config.default === "function") {
655
+ //TODO quick workaround solution, which will blocking the UI popup
656
+ config.default = await config.default();
657
+ }
658
+ return this.selectFileInQuickPick(config, "file", config.default);
659
+ }
660
+ async selectFiles(config) {
661
+ if (config.default && typeof config.default === "function") {
662
+ //TODO quick workaround solution, which will blocking the UI popup
663
+ config.default = await config.default();
664
+ }
665
+ return this.selectFileInQuickPick(config, "files", config.default ? config.default.join(";") : undefined);
666
+ }
667
+ async selectFileInQuickPick(config, type, defaultValue) {
668
+ if (config.possibleFiles) {
669
+ if (config.possibleFiles.find((o) => o.id === "browse" || o.id === "default")) {
670
+ return Promise.resolve(teamsfx_api_1.err(new teamsfx_api_1.SystemError("UI", "InvalidInput", 'Possible files should not contain item with id "browse" or "default".')));
671
+ }
672
+ }
673
+ /// TODO: use generic constraints.
674
+ const disposables = [];
675
+ try {
676
+ const quickPick = vscode_1.window.createQuickPick();
677
+ quickPick.title = config.title;
678
+ if (config.step && config.step > 1) {
679
+ quickPick.buttons = [vscode_1.QuickInputButtons.Back];
680
+ }
681
+ quickPick.ignoreFocusOut = true;
682
+ quickPick.placeholder = config.placeholder;
683
+ quickPick.matchOnDescription = false;
684
+ quickPick.matchOnDetail = false;
685
+ quickPick.canSelectMany = false;
686
+ let fileSelectorIsOpen = false;
687
+ return await new Promise((resolve) => {
688
+ // set options
689
+ quickPick.items = [
690
+ ...(config.possibleFiles
691
+ ? config.possibleFiles
692
+ : defaultValue
693
+ ? [
694
+ {
695
+ id: "default",
696
+ label: `$(file) ${path.basename(defaultValue)}`,
697
+ description: path.dirname(defaultValue),
698
+ },
699
+ ]
700
+ : []),
701
+ {
702
+ id: "browse",
703
+ label: `$(file) ${this.localizer.browse()}`,
704
+ },
705
+ ];
706
+ const onDidAccept = async () => {
707
+ var _a, _b;
708
+ const selectedItems = quickPick.selectedItems;
709
+ let result;
710
+ if (selectedItems && selectedItems.length > 0) {
711
+ const item = selectedItems[0];
712
+ if (item.id === "default") {
713
+ result = config.default;
714
+ }
715
+ else if (item.id === "browse") {
716
+ fileSelectorIsOpen = true;
717
+ const uriList = await vscode_1.window.showOpenDialog({
718
+ defaultUri: config.default ? vscode_1.Uri.file(config.default) : undefined,
719
+ canSelectFiles: true,
720
+ canSelectFolders: false,
721
+ canSelectMany: type === "files",
722
+ filters: config.filters,
723
+ title: config.title,
724
+ });
725
+ if (uriList && uriList.length > 0) {
726
+ if (type === "files") {
727
+ const results = uriList.map((u) => u.fsPath);
728
+ result = results;
729
+ }
730
+ else {
731
+ result = uriList[0].fsPath;
732
+ }
733
+ }
734
+ else {
735
+ quickPick.selectedItems = [];
736
+ return;
737
+ }
738
+ }
739
+ else {
740
+ result = (_b = (_a = config.possibleFiles) === null || _a === void 0 ? void 0 : _a.find((f) => f.id === item.id)) === null || _b === void 0 ? void 0 : _b.id;
741
+ }
742
+ if (config.validation && result !== undefined) {
743
+ quickPick.busy = true;
744
+ quickPick.enabled = false;
745
+ try {
746
+ const validationResult = await config.validation(result);
747
+ quickPick.busy = false;
748
+ quickPick.enabled = true;
749
+ if (validationResult) {
750
+ void this.showMessage("error", validationResult, false);
751
+ quickPick.selectedItems = [];
752
+ quickPick.activeItems = [];
753
+ return;
754
+ }
755
+ }
756
+ catch (e) {
757
+ resolve(teamsfx_api_1.err(this.assembleError(e)));
758
+ }
759
+ }
760
+ resolve(teamsfx_api_1.ok({ type: "success", result: result }));
761
+ }
762
+ };
763
+ disposables.push(quickPick.onDidAccept(onDidAccept), quickPick.onDidHide(() => {
764
+ if (fileSelectorIsOpen === false)
765
+ resolve(teamsfx_api_1.err(new error_1.UserCancelError(this.localizer.emptyOptionErrorMessage(), this.localizer.emptyOptionErrorDisplayMessage())));
766
+ }), quickPick.onDidTriggerButton((button) => {
767
+ if (button === vscode_1.QuickInputButtons.Back)
768
+ resolve(teamsfx_api_1.ok({ type: "back" }));
769
+ }));
770
+ disposables.push(quickPick);
771
+ quickPick.show();
772
+ });
773
+ }
774
+ finally {
775
+ disposables.forEach((d) => {
776
+ d.dispose();
777
+ });
778
+ }
779
+ }
780
+ async openUrl(link) {
781
+ const uri = vscode_1.Uri.parse(link);
782
+ const result = await vscode_1.env.openExternal(uri);
783
+ if (result) {
784
+ return teamsfx_api_1.ok(result);
785
+ }
786
+ else {
787
+ return teamsfx_api_1.err(new error_1.InternalUIError(this.localizer.internalErrorMessage(`env.openExternal('${link}')`), this.localizer.internalErrorDisplayMessage(`env.openExternal('${link}')`)));
788
+ }
789
+ }
790
+ async selectFileOrInput(config) {
791
+ const validtionOnSelect = async (input) => {
792
+ if (input === config.inputOptionItem.id) {
793
+ return undefined;
794
+ }
795
+ if (config.validation) {
796
+ return await config.validation(input);
797
+ }
798
+ };
799
+ const selectFileConfig = Object.assign(Object.assign({}, config), { validation: validtionOnSelect, possibleFiles: [config.inputOptionItem] });
800
+ while (true) {
801
+ const selectFileOrItemRes = await this.selectFile(selectFileConfig);
802
+ if (selectFileOrItemRes.isOk()) {
803
+ if (selectFileOrItemRes.value.result === config.inputOptionItem.id) {
804
+ const inputRes = await this.inputText(Object.assign(Object.assign({}, config.inputBoxConfig), { additionalValidationOnAccept: config.validation }));
805
+ if (inputRes.isOk()) {
806
+ if (inputRes.value.type === "back")
807
+ continue;
808
+ return teamsfx_api_1.ok(inputRes.value);
809
+ }
810
+ else {
811
+ return teamsfx_api_1.err(inputRes.error);
812
+ }
813
+ }
814
+ else {
815
+ return teamsfx_api_1.ok(selectFileOrItemRes.value);
816
+ }
817
+ }
818
+ else {
819
+ return teamsfx_api_1.err(selectFileOrItemRes.error);
820
+ }
821
+ }
822
+ }
823
+ async confirm(config) {
824
+ var _a;
825
+ const confirmText = ((_a = config.transformer) === null || _a === void 0 ? void 0 : _a.call(config, true)) || "Confirm";
826
+ const res = await this.showMessage("warn", config.title, true, confirmText);
827
+ if (res.isErr()) {
828
+ return teamsfx_api_1.err(res.error);
829
+ }
830
+ const value = res.value;
831
+ if (value === confirmText)
832
+ return teamsfx_api_1.ok({ type: "success", result: true });
833
+ return teamsfx_api_1.err(new error_1.UserCancelError(this.localizer.emptyOptionErrorMessage(), this.localizer.emptyOptionErrorDisplayMessage()));
834
+ }
835
+ async showMessage(level, message, modal, ...items) {
836
+ if (message instanceof Array) {
837
+ message = message.map((x) => x.content).join("");
838
+ }
839
+ return new Promise((resolve) => {
840
+ const option = { modal: modal };
841
+ try {
842
+ let promise;
843
+ switch (level) {
844
+ case "info": {
845
+ promise = vscode_1.window.showInformationMessage(message, option, ...items);
846
+ break;
847
+ }
848
+ case "warn": {
849
+ promise = vscode_1.window.showWarningMessage(message, option, ...items);
850
+ break;
851
+ }
852
+ case "error":
853
+ promise = vscode_1.window.showErrorMessage(message, option, ...items);
854
+ }
855
+ promise.then((v) => {
856
+ if (v)
857
+ resolve(teamsfx_api_1.ok(v));
858
+ else
859
+ resolve(teamsfx_api_1.err(new error_1.UserCancelError(this.localizer.emptyOptionErrorMessage(), this.localizer.emptyOptionErrorDisplayMessage())));
860
+ }, (error) => { });
861
+ }
862
+ catch (error) {
863
+ resolve(teamsfx_api_1.err(this.assembleError(error)));
864
+ }
865
+ });
866
+ }
867
+ createProgressBar(title, totalSteps) {
868
+ return new progressHandler_1.ProgressHandler(title, totalSteps);
869
+ }
870
+ async executeFunction(config) {
871
+ const quickPick = vscode_1.window.createQuickPick();
872
+ quickPick.title = config.title;
873
+ quickPick.busy = true;
874
+ quickPick.enabled = false;
875
+ quickPick.show();
876
+ try {
877
+ return (await config.func(config.inputs));
878
+ }
879
+ finally {
880
+ quickPick.hide();
881
+ quickPick.dispose();
882
+ }
883
+ }
884
+ async runCommand(args) {
885
+ var _a, _b;
886
+ const cmd = args.cmd;
887
+ const workingDirectory = args.workingDirectory;
888
+ const shell = args.shell;
889
+ const timeout = args.timeout;
890
+ const env = args.env;
891
+ const timeoutPromise = new Promise((_resolve, reject) => {
892
+ const wait = setTimeout(() => {
893
+ clearTimeout(wait);
894
+ reject(new error_1.ScriptTimeoutError(this.localizer.commandTimeoutErrorMessage(cmd), this.localizer.commandTimeoutErrorDisplayMessage(cmd)));
895
+ }, timeout !== null && timeout !== void 0 ? timeout : 1000 * 60 * 5);
896
+ });
897
+ try {
898
+ let terminal;
899
+ const name = (_a = args.shellName) !== null && _a !== void 0 ? _a : (shell ? `${this.terminalName}-${shell}` : this.terminalName);
900
+ if (vscode_1.window.terminals.length === 0 ||
901
+ (terminal = lodash_1.find(vscode_1.window.terminals, (value) => value.name === name)) === undefined) {
902
+ terminal = vscode_1.window.createTerminal({
903
+ name,
904
+ shellPath: shell,
905
+ cwd: workingDirectory,
906
+ env,
907
+ iconPath: args.iconPath ? new vscode_1.ThemeIcon(args.iconPath) : undefined,
908
+ });
909
+ }
910
+ terminal.show();
911
+ terminal.sendText(cmd);
912
+ const processId = await Promise.race([terminal.processId, timeoutPromise]);
913
+ await sleep(500);
914
+ return teamsfx_api_1.ok((_b = processId === null || processId === void 0 ? void 0 : processId.toString()) !== null && _b !== void 0 ? _b : "");
915
+ }
916
+ catch (error) {
917
+ return teamsfx_api_1.err(this.assembleError(error));
918
+ }
919
+ }
920
+ async openFile(filePath) {
921
+ const uri = vscode_1.Uri.file(filePath);
922
+ const doc = await vscode_1.workspace.openTextDocument(uri);
923
+ if (doc) {
924
+ if (filePath.endsWith(".md")) {
925
+ await vscode_1.commands.executeCommand("markdown.showPreview", uri);
926
+ }
927
+ else {
928
+ await vscode_1.window.showTextDocument(doc);
929
+ }
930
+ return teamsfx_api_1.ok(true);
931
+ }
932
+ else {
933
+ return teamsfx_api_1.err(new error_1.InternalUIError(this.localizer.internalErrorMessage(`workspace.openTextDocument('${filePath}')`), this.localizer.internalErrorDisplayMessage(`workspace.openTextDocument('${filePath}')`)));
934
+ }
935
+ }
936
+ }
937
+ exports.VSCodeUI = VSCodeUI;
938
+ //# sourceMappingURL=ui.js.map