@theia/getting-started 1.76.0-next.14 → 1.76.0-next.18
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/README.md +44 -0
- package/lib/browser/getting-started-frontend-module.d.ts.map +1 -1
- package/lib/browser/getting-started-frontend-module.js +3 -0
- package/lib/browser/getting-started-frontend-module.js.map +1 -1
- package/lib/browser/getting-started-widget.d.ts +0 -7
- package/lib/browser/getting-started-widget.d.ts.map +1 -1
- package/lib/browser/getting-started-widget.js +1 -29
- package/lib/browser/getting-started-widget.js.map +1 -1
- package/lib/browser/walkthrough-section.d.ts +2 -2
- package/lib/browser/walkthrough-section.d.ts.map +1 -1
- package/lib/browser/walkthrough-section.js +7 -5
- package/lib/browser/walkthrough-section.js.map +1 -1
- package/lib/browser/walkthrough-section.spec.js +17 -1
- package/lib/browser/walkthrough-section.spec.js.map +1 -1
- package/lib/browser/walkthrough-service.d.ts +26 -5
- package/lib/browser/walkthrough-service.d.ts.map +1 -1
- package/lib/browser/walkthrough-service.js +77 -22
- package/lib/browser/walkthrough-service.js.map +1 -1
- package/lib/browser/walkthrough-service.spec.js +173 -57
- package/lib/browser/walkthrough-service.spec.js.map +1 -1
- package/lib/common/walkthrough-provider.d.ts +22 -0
- package/lib/common/walkthrough-provider.d.ts.map +1 -0
- package/lib/common/walkthrough-provider.js +27 -0
- package/lib/common/walkthrough-provider.js.map +1 -0
- package/lib/common/walkthrough-types.d.ts +18 -5
- package/lib/common/walkthrough-types.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/browser/getting-started-frontend-module.ts +3 -0
- package/src/browser/getting-started-widget.tsx +31 -101
- package/src/browser/style/index.css +69 -35
- package/src/browser/walkthrough-section.spec.tsx +29 -1
- package/src/browser/walkthrough-section.tsx +7 -5
- package/src/browser/walkthrough-service.spec.ts +207 -57
- package/src/browser/walkthrough-service.ts +82 -25
- package/src/common/walkthrough-provider.ts +38 -0
- package/src/common/walkthrough-types.ts +20 -5
|
@@ -21,6 +21,8 @@ import { WalkthroughService } from './walkthrough-service';
|
|
|
21
21
|
import { Emitter } from '@theia/core/lib/common/event';
|
|
22
22
|
import { WalkthroughContribution } from '@theia/plugin-ext/lib/common/plugin-protocol';
|
|
23
23
|
import { ContextKeyChangeEvent } from '@theia/core/lib/browser/context-key-service';
|
|
24
|
+
import { WalkthroughProvider } from '../common/walkthrough-provider';
|
|
25
|
+
import { WalkthroughDefinition } from '../common/walkthrough-types';
|
|
24
26
|
|
|
25
27
|
describe('WalkthroughService', () => {
|
|
26
28
|
|
|
@@ -40,6 +42,7 @@ describe('WalkthroughService', () => {
|
|
|
40
42
|
let mockOpenerOpenCalls: string[];
|
|
41
43
|
let reportedErrors: string[];
|
|
42
44
|
let mockDisabledByTrust: Set<string>;
|
|
45
|
+
let mockWalkthroughProviders: WalkthroughProvider[];
|
|
43
46
|
|
|
44
47
|
function createContribution(overrides?: Partial<WalkthroughContribution>): WalkthroughContribution {
|
|
45
48
|
return {
|
|
@@ -65,6 +68,12 @@ describe('WalkthroughService', () => {
|
|
|
65
68
|
};
|
|
66
69
|
}
|
|
67
70
|
|
|
71
|
+
/** Registers a plugin contribution the way {@link WalkthroughService.collectPluginWalkthroughs} does. */
|
|
72
|
+
function registerContribution(contribution: WalkthroughContribution): void {
|
|
73
|
+
(service as any).registerWalkthrough(
|
|
74
|
+
`${contribution.pluginId}.${contribution.id}`, contribution, contribution.pluginId, contribution.pluginIcon);
|
|
75
|
+
}
|
|
76
|
+
|
|
68
77
|
beforeEach(() => {
|
|
69
78
|
storedData = {};
|
|
70
79
|
onDidChangePluginsEmitter = new Emitter();
|
|
@@ -78,6 +87,7 @@ describe('WalkthroughService', () => {
|
|
|
78
87
|
mockOpenerOpenCalls = [];
|
|
79
88
|
reportedErrors = [];
|
|
80
89
|
mockDisabledByTrust = new Set();
|
|
90
|
+
mockWalkthroughProviders = [];
|
|
81
91
|
const mockOpener = { open: (...args: unknown[]) => { mockOpenerOpenCalls.push(String(args[0])); } };
|
|
82
92
|
mockOpenerGetOpener = () => Promise.resolve(mockOpener);
|
|
83
93
|
onDidExpandViewEmitter = new Emitter();
|
|
@@ -138,6 +148,9 @@ describe('WalkthroughService', () => {
|
|
|
138
148
|
get disabledByTrust(): ReadonlySet<string> { return mockDisabledByTrust; },
|
|
139
149
|
onDidChangePlugins: onDidChangePluginsEmitter.event
|
|
140
150
|
};
|
|
151
|
+
(service as any).walkthroughProviders = {
|
|
152
|
+
getContributions: () => mockWalkthroughProviders
|
|
153
|
+
};
|
|
141
154
|
});
|
|
142
155
|
|
|
143
156
|
afterEach(() => {
|
|
@@ -152,7 +165,7 @@ describe('WalkthroughService', () => {
|
|
|
152
165
|
describe('registerWalkthrough', () => {
|
|
153
166
|
it('should register a walkthrough and make it retrievable', () => {
|
|
154
167
|
const contribution = createContribution();
|
|
155
|
-
(
|
|
168
|
+
registerContribution(contribution);
|
|
156
169
|
|
|
157
170
|
const walkthroughs = service.getWalkthroughs();
|
|
158
171
|
expect(walkthroughs).to.have.lengthOf(1);
|
|
@@ -163,7 +176,7 @@ describe('WalkthroughService', () => {
|
|
|
163
176
|
|
|
164
177
|
it('should construct full ID from pluginId and walkthrough id', () => {
|
|
165
178
|
const contribution = createContribution({ pluginId: 'my.plugin', id: 'my-wt' });
|
|
166
|
-
(
|
|
179
|
+
registerContribution(contribution);
|
|
167
180
|
|
|
168
181
|
expect(service.getWalkthrough('my.plugin.my-wt')).to.not.be.undefined;
|
|
169
182
|
});
|
|
@@ -172,12 +185,12 @@ describe('WalkthroughService', () => {
|
|
|
172
185
|
let fired = false;
|
|
173
186
|
service.onDidChangeWalkthroughs(() => { fired = true; });
|
|
174
187
|
|
|
175
|
-
(
|
|
188
|
+
registerContribution(createContribution());
|
|
176
189
|
expect(fired).to.be.true;
|
|
177
190
|
});
|
|
178
191
|
|
|
179
192
|
it('should initialize steps as not complete', () => {
|
|
180
|
-
(
|
|
193
|
+
registerContribution(createContribution());
|
|
181
194
|
const walkthrough = service.getWalkthroughs()[0];
|
|
182
195
|
for (const step of walkthrough.steps) {
|
|
183
196
|
expect(step.isComplete).to.be.false;
|
|
@@ -187,7 +200,7 @@ describe('WalkthroughService', () => {
|
|
|
187
200
|
|
|
188
201
|
describe('markStepComplete', () => {
|
|
189
202
|
beforeEach(() => {
|
|
190
|
-
(
|
|
203
|
+
registerContribution(createContribution());
|
|
191
204
|
});
|
|
192
205
|
|
|
193
206
|
it('should mark a step as complete', async () => {
|
|
@@ -243,7 +256,7 @@ describe('WalkthroughService', () => {
|
|
|
243
256
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
244
257
|
|
|
245
258
|
beforeEach(() => {
|
|
246
|
-
(
|
|
259
|
+
registerContribution(createContribution());
|
|
247
260
|
});
|
|
248
261
|
|
|
249
262
|
it('should take the completion mark off a step again', async () => {
|
|
@@ -293,7 +306,7 @@ describe('WalkthroughService', () => {
|
|
|
293
306
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
294
307
|
|
|
295
308
|
beforeEach(() => {
|
|
296
|
-
(
|
|
309
|
+
registerContribution(createContribution());
|
|
297
310
|
});
|
|
298
311
|
|
|
299
312
|
it('should complete every step', async () => {
|
|
@@ -333,7 +346,7 @@ describe('WalkthroughService', () => {
|
|
|
333
346
|
|
|
334
347
|
describe('resetProgress', () => {
|
|
335
348
|
beforeEach(async () => {
|
|
336
|
-
(
|
|
349
|
+
registerContribution(createContribution());
|
|
337
350
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
338
351
|
await service.markStepComplete(wtId, 'step1');
|
|
339
352
|
await service.markStepComplete(wtId, 'step2');
|
|
@@ -365,7 +378,7 @@ describe('WalkthroughService', () => {
|
|
|
365
378
|
|
|
366
379
|
describe('getStepProgress', () => {
|
|
367
380
|
beforeEach(() => {
|
|
368
|
-
(
|
|
381
|
+
registerContribution(createContribution());
|
|
369
382
|
});
|
|
370
383
|
|
|
371
384
|
it('should return correct progress', () => {
|
|
@@ -393,7 +406,7 @@ describe('WalkthroughService', () => {
|
|
|
393
406
|
|
|
394
407
|
describe('completion event handling', () => {
|
|
395
408
|
beforeEach(() => {
|
|
396
|
-
(
|
|
409
|
+
registerContribution(createContribution());
|
|
397
410
|
// Wire up the event handlers that @postConstruct would normally set up
|
|
398
411
|
(service as any).toDispose.push(
|
|
399
412
|
(service as any).commandRegistry.onDidExecuteCommand((e: { commandId: string }) => {
|
|
@@ -452,7 +465,7 @@ describe('WalkthroughService', () => {
|
|
|
452
465
|
|
|
453
466
|
// Simulate what loadProgress does
|
|
454
467
|
await (service as any).loadProgress();
|
|
455
|
-
(
|
|
468
|
+
registerContribution(createContribution());
|
|
456
469
|
|
|
457
470
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
458
471
|
const walkthrough = service.getWalkthrough(wtId)!;
|
|
@@ -490,7 +503,7 @@ describe('WalkthroughService', () => {
|
|
|
490
503
|
|
|
491
504
|
it('should handle missing storage data gracefully', async () => {
|
|
492
505
|
await (service as any).loadProgress();
|
|
493
|
-
(
|
|
506
|
+
registerContribution(createContribution());
|
|
494
507
|
|
|
495
508
|
const wtId = 'test.publisher.test-plugin.test-walkthrough';
|
|
496
509
|
const walkthrough = service.getWalkthrough(wtId)!;
|
|
@@ -502,14 +515,14 @@ describe('WalkthroughService', () => {
|
|
|
502
515
|
|
|
503
516
|
describe('extension icon', () => {
|
|
504
517
|
it('should carry the icon of the contributing extension', () => {
|
|
505
|
-
(
|
|
518
|
+
registerContribution(createContribution({ pluginIcon: 'hostedPlugin/pub_name/icon.png' }));
|
|
506
519
|
|
|
507
520
|
const walkthrough = service.getWalkthrough('test.publisher.test-plugin.test-walkthrough')!;
|
|
508
521
|
expect(walkthrough.pluginIcon).to.equal('hostedPlugin/pub_name/icon.png');
|
|
509
522
|
});
|
|
510
523
|
|
|
511
524
|
it('should leave the icon undefined when the extension declares none', () => {
|
|
512
|
-
(
|
|
525
|
+
registerContribution(createContribution());
|
|
513
526
|
|
|
514
527
|
const walkthrough = service.getWalkthrough('test.publisher.test-plugin.test-walkthrough')!;
|
|
515
528
|
expect(walkthrough.pluginIcon).to.be.undefined;
|
|
@@ -525,7 +538,7 @@ describe('WalkthroughService', () => {
|
|
|
525
538
|
});
|
|
526
539
|
|
|
527
540
|
it('should retain the selected walkthrough and fire onDidChangeSelection', () => {
|
|
528
|
-
(
|
|
541
|
+
registerContribution(createContribution());
|
|
529
542
|
|
|
530
543
|
let fired = 0;
|
|
531
544
|
service.onDidChangeSelection(() => { fired++; });
|
|
@@ -536,14 +549,14 @@ describe('WalkthroughService', () => {
|
|
|
536
549
|
});
|
|
537
550
|
|
|
538
551
|
it('should preselect the first pending step', () => {
|
|
539
|
-
(
|
|
552
|
+
registerContribution(createContribution());
|
|
540
553
|
service.selectWalkthrough(wtId);
|
|
541
554
|
|
|
542
555
|
expect(service.selectedStep?.id).to.equal('step1');
|
|
543
556
|
});
|
|
544
557
|
|
|
545
558
|
it('should preselect the first step that is not yet complete', async () => {
|
|
546
|
-
(
|
|
559
|
+
registerContribution(createContribution());
|
|
547
560
|
await service.markStepComplete(wtId, 'step1');
|
|
548
561
|
service.selectWalkthrough(wtId);
|
|
549
562
|
|
|
@@ -551,7 +564,7 @@ describe('WalkthroughService', () => {
|
|
|
551
564
|
});
|
|
552
565
|
|
|
553
566
|
it('should accept the VS Code `publisher.name#walkthroughId` form', () => {
|
|
554
|
-
(
|
|
567
|
+
registerContribution(createContribution());
|
|
555
568
|
service.selectWalkthrough('test.publisher.test-plugin#test-walkthrough');
|
|
556
569
|
|
|
557
570
|
expect(service.selectedWalkthrough?.id).to.equal(wtId);
|
|
@@ -567,7 +580,7 @@ describe('WalkthroughService', () => {
|
|
|
567
580
|
});
|
|
568
581
|
|
|
569
582
|
it('should select another step of the selected walkthrough', () => {
|
|
570
|
-
(
|
|
583
|
+
registerContribution(createContribution());
|
|
571
584
|
service.selectWalkthrough(wtId);
|
|
572
585
|
service.selectStep('step2');
|
|
573
586
|
|
|
@@ -575,7 +588,7 @@ describe('WalkthroughService', () => {
|
|
|
575
588
|
});
|
|
576
589
|
|
|
577
590
|
it('should ignore a step that does not belong to the selected walkthrough', () => {
|
|
578
|
-
(
|
|
591
|
+
registerContribution(createContribution());
|
|
579
592
|
service.selectWalkthrough(wtId);
|
|
580
593
|
service.selectStep('nonexistent');
|
|
581
594
|
|
|
@@ -583,7 +596,7 @@ describe('WalkthroughService', () => {
|
|
|
583
596
|
});
|
|
584
597
|
|
|
585
598
|
it('should clear the selection', () => {
|
|
586
|
-
(
|
|
599
|
+
registerContribution(createContribution());
|
|
587
600
|
service.selectWalkthrough(wtId);
|
|
588
601
|
|
|
589
602
|
let fired = 0;
|
|
@@ -604,7 +617,7 @@ describe('WalkthroughService', () => {
|
|
|
604
617
|
});
|
|
605
618
|
|
|
606
619
|
it('should reflect step completion in the selected step', async () => {
|
|
607
|
-
(
|
|
620
|
+
registerContribution(createContribution());
|
|
608
621
|
service.selectWalkthrough(wtId);
|
|
609
622
|
await service.markStepComplete(wtId, 'step1');
|
|
610
623
|
|
|
@@ -618,7 +631,7 @@ describe('WalkthroughService', () => {
|
|
|
618
631
|
|
|
619
632
|
it('should hide a walkthrough whose when clause does not hold', () => {
|
|
620
633
|
mockContextKeyMatchResult = false;
|
|
621
|
-
(
|
|
634
|
+
registerContribution(createContribution({ when: 'someKey' }));
|
|
622
635
|
|
|
623
636
|
expect(service.getWalkthroughs()).to.be.empty;
|
|
624
637
|
expect(service.getWalkthrough(wtId)).to.be.undefined;
|
|
@@ -626,21 +639,21 @@ describe('WalkthroughService', () => {
|
|
|
626
639
|
|
|
627
640
|
it('should list a walkthrough whose when clause holds', () => {
|
|
628
641
|
mockContextKeyMatchResult = true;
|
|
629
|
-
(
|
|
642
|
+
registerContribution(createContribution({ when: 'someKey' }));
|
|
630
643
|
|
|
631
644
|
expect(service.getWalkthroughs()).to.have.lengthOf(1);
|
|
632
645
|
});
|
|
633
646
|
|
|
634
647
|
it('should always list a walkthrough without a when clause', () => {
|
|
635
648
|
mockContextKeyMatchResult = false;
|
|
636
|
-
(
|
|
649
|
+
registerContribution(createContribution());
|
|
637
650
|
|
|
638
651
|
expect(service.getWalkthroughs()).to.have.lengthOf(1);
|
|
639
652
|
});
|
|
640
653
|
|
|
641
654
|
it('should hide the steps whose when clause does not hold', () => {
|
|
642
655
|
mockContextKeyMatchResult = false;
|
|
643
|
-
(
|
|
656
|
+
registerContribution(createContribution({
|
|
644
657
|
steps: [
|
|
645
658
|
{ id: 'always', title: 'Always', description: 'd' },
|
|
646
659
|
{ id: 'never', title: 'Never', description: 'd', when: 'someKey' }
|
|
@@ -654,7 +667,7 @@ describe('WalkthroughService', () => {
|
|
|
654
667
|
|
|
655
668
|
it('should exclude hidden steps from the progress', () => {
|
|
656
669
|
mockContextKeyMatchResult = false;
|
|
657
|
-
(
|
|
670
|
+
registerContribution(createContribution({
|
|
658
671
|
steps: [
|
|
659
672
|
{ id: 'always', title: 'Always', description: 'd' },
|
|
660
673
|
{ id: 'never', title: 'Never', description: 'd', when: 'someKey' }
|
|
@@ -666,7 +679,7 @@ describe('WalkthroughService', () => {
|
|
|
666
679
|
|
|
667
680
|
it('should not select a hidden walkthrough', () => {
|
|
668
681
|
mockContextKeyMatchResult = false;
|
|
669
|
-
(
|
|
682
|
+
registerContribution(createContribution({ when: 'someKey' }));
|
|
670
683
|
service.selectWalkthrough(wtId);
|
|
671
684
|
|
|
672
685
|
expect(service.selectedWalkthrough).to.be.undefined;
|
|
@@ -674,7 +687,7 @@ describe('WalkthroughService', () => {
|
|
|
674
687
|
|
|
675
688
|
it('should preselect the first pending visible step', () => {
|
|
676
689
|
mockContextKeyMatchResult = false;
|
|
677
|
-
(
|
|
690
|
+
registerContribution(createContribution({
|
|
678
691
|
steps: [
|
|
679
692
|
{ id: 'hidden', title: 'Hidden', description: 'd', when: 'someKey' },
|
|
680
693
|
{ id: 'visible', title: 'Visible', description: 'd' }
|
|
@@ -687,7 +700,7 @@ describe('WalkthroughService', () => {
|
|
|
687
700
|
|
|
688
701
|
it('should re-evaluate visibility whenever it is queried', () => {
|
|
689
702
|
mockContextKeyMatchResult = false;
|
|
690
|
-
(
|
|
703
|
+
registerContribution(createContribution({ when: 'someKey' }));
|
|
691
704
|
expect(service.getWalkthroughs()).to.be.empty;
|
|
692
705
|
|
|
693
706
|
mockContextKeyMatchResult = true;
|
|
@@ -695,7 +708,7 @@ describe('WalkthroughService', () => {
|
|
|
695
708
|
});
|
|
696
709
|
|
|
697
710
|
it('should collect the context keys of every when clause and onContext event', () => {
|
|
698
|
-
(
|
|
711
|
+
registerContribution(createContribution({
|
|
699
712
|
when: 'walkthroughKey',
|
|
700
713
|
steps: [{ id: 's1', title: 'S1', description: 'd', when: 'stepKey', completionEvents: ['onContext:eventKey'] }]
|
|
701
714
|
}));
|
|
@@ -705,7 +718,7 @@ describe('WalkthroughService', () => {
|
|
|
705
718
|
});
|
|
706
719
|
|
|
707
720
|
it('should notify when visibility changed', () => {
|
|
708
|
-
(
|
|
721
|
+
registerContribution(createContribution({ when: 'someKey' }));
|
|
709
722
|
|
|
710
723
|
let fired = false;
|
|
711
724
|
service.onDidChangeWalkthroughs(() => { fired = true; });
|
|
@@ -716,7 +729,7 @@ describe('WalkthroughService', () => {
|
|
|
716
729
|
|
|
717
730
|
it('should close a selected walkthrough that becomes hidden', () => {
|
|
718
731
|
mockContextKeyMatchResult = true;
|
|
719
|
-
(
|
|
732
|
+
registerContribution(createContribution({ when: 'someKey' }));
|
|
720
733
|
service.selectWalkthrough(wtId);
|
|
721
734
|
expect(service.selectedWalkthrough?.id).to.equal(wtId);
|
|
722
735
|
|
|
@@ -728,7 +741,7 @@ describe('WalkthroughService', () => {
|
|
|
728
741
|
|
|
729
742
|
it('should mark only the visible steps done', async () => {
|
|
730
743
|
mockContextKeyMatchResult = false;
|
|
731
|
-
(
|
|
744
|
+
registerContribution(createContribution({
|
|
732
745
|
steps: [
|
|
733
746
|
{ id: 'always', title: 'Always', description: 'd' },
|
|
734
747
|
{ id: 'never', title: 'Never', description: 'd', when: 'someKey' }
|
|
@@ -751,8 +764,8 @@ describe('WalkthroughService', () => {
|
|
|
751
764
|
});
|
|
752
765
|
|
|
753
766
|
it('should return all registered walkthroughs', () => {
|
|
754
|
-
(
|
|
755
|
-
(
|
|
767
|
+
registerContribution(createContribution({ id: 'wt1' }));
|
|
768
|
+
registerContribution(createContribution({ id: 'wt2' }));
|
|
756
769
|
|
|
757
770
|
const walkthroughs = service.getWalkthroughs();
|
|
758
771
|
expect(walkthroughs).to.have.lengthOf(2);
|
|
@@ -766,7 +779,7 @@ describe('WalkthroughService', () => {
|
|
|
766
779
|
beforeEach(() => {
|
|
767
780
|
mockPlugins = [{ model: { id: pluginId, publisher: 'test.publisher', name: 'test-plugin' } }];
|
|
768
781
|
mockDeployedPlugins.set(pluginId, { contributes: { walkthroughs: [createContribution()] } });
|
|
769
|
-
(service as any).
|
|
782
|
+
(service as any).syncWalkthroughs();
|
|
770
783
|
});
|
|
771
784
|
|
|
772
785
|
it('should offer the walkthrough of an installed plugin', () => {
|
|
@@ -784,7 +797,7 @@ describe('WalkthroughService', () => {
|
|
|
784
797
|
})]
|
|
785
798
|
}
|
|
786
799
|
});
|
|
787
|
-
(service as any).
|
|
800
|
+
(service as any).syncWalkthroughs();
|
|
788
801
|
|
|
789
802
|
const steps = service.getWalkthrough(wtId)!.steps;
|
|
790
803
|
expect(steps).to.have.lengthOf(1);
|
|
@@ -794,7 +807,7 @@ describe('WalkthroughService', () => {
|
|
|
794
807
|
it('should keep a walkthrough whose definition is unchanged', () => {
|
|
795
808
|
let fired = false;
|
|
796
809
|
service.onDidChangeWalkthroughs(() => { fired = true; });
|
|
797
|
-
(service as any).
|
|
810
|
+
(service as any).syncWalkthroughs();
|
|
798
811
|
|
|
799
812
|
expect(fired, 'an unchanged sync must not notify').to.be.false;
|
|
800
813
|
});
|
|
@@ -803,18 +816,18 @@ describe('WalkthroughService', () => {
|
|
|
803
816
|
expect(service.getWalkthrough(wtId), 'offered while the workspace is trusted').to.not.be.undefined;
|
|
804
817
|
|
|
805
818
|
mockDisabledByTrust.add(pluginId);
|
|
806
|
-
(service as any).
|
|
819
|
+
(service as any).syncWalkthroughs();
|
|
807
820
|
|
|
808
821
|
expect(service.getWalkthroughs()).to.be.empty;
|
|
809
822
|
});
|
|
810
823
|
|
|
811
824
|
it('should offer it again once the workspace is trusted', () => {
|
|
812
825
|
mockDisabledByTrust.add(pluginId);
|
|
813
|
-
(service as any).
|
|
826
|
+
(service as any).syncWalkthroughs();
|
|
814
827
|
expect(service.getWalkthroughs()).to.be.empty;
|
|
815
828
|
|
|
816
829
|
mockDisabledByTrust.delete(pluginId);
|
|
817
|
-
(service as any).
|
|
830
|
+
(service as any).syncWalkthroughs();
|
|
818
831
|
|
|
819
832
|
expect(service.getWalkthrough(wtId)).to.not.be.undefined;
|
|
820
833
|
});
|
|
@@ -824,7 +837,7 @@ describe('WalkthroughService', () => {
|
|
|
824
837
|
expect(service.selectedWalkthrough?.id).to.equal(wtId);
|
|
825
838
|
|
|
826
839
|
mockDisabledByTrust.add(pluginId);
|
|
827
|
-
(service as any).
|
|
840
|
+
(service as any).syncWalkthroughs();
|
|
828
841
|
|
|
829
842
|
expect(service.selectedWalkthrough).to.be.undefined;
|
|
830
843
|
});
|
|
@@ -832,7 +845,7 @@ describe('WalkthroughService', () => {
|
|
|
832
845
|
it('should drop the walkthrough once the plugin is out of sync', () => {
|
|
833
846
|
// Theia keeps an uninstalled or disabled plugin loaded until the next reload, flagged as out of sync.
|
|
834
847
|
mockPlugins[0].outOfSync = true;
|
|
835
|
-
(service as any).
|
|
848
|
+
(service as any).syncWalkthroughs();
|
|
836
849
|
|
|
837
850
|
expect(service.getWalkthrough(wtId)).to.be.undefined;
|
|
838
851
|
expect(service.getWalkthroughs()).to.be.empty;
|
|
@@ -842,7 +855,7 @@ describe('WalkthroughService', () => {
|
|
|
842
855
|
let fired = false;
|
|
843
856
|
service.onDidChangeWalkthroughs(() => { fired = true; });
|
|
844
857
|
mockPlugins[0].outOfSync = true;
|
|
845
|
-
(service as any).
|
|
858
|
+
(service as any).syncWalkthroughs();
|
|
846
859
|
|
|
847
860
|
expect(fired).to.be.true;
|
|
848
861
|
});
|
|
@@ -852,12 +865,149 @@ describe('WalkthroughService', () => {
|
|
|
852
865
|
expect(service.selectedWalkthrough?.id).to.equal(wtId);
|
|
853
866
|
|
|
854
867
|
mockPlugins[0].outOfSync = true;
|
|
855
|
-
(service as any).
|
|
868
|
+
(service as any).syncWalkthroughs();
|
|
856
869
|
|
|
857
870
|
expect(service.selectedWalkthrough).to.be.undefined;
|
|
858
871
|
});
|
|
859
872
|
});
|
|
860
873
|
|
|
874
|
+
describe('contributed walkthroughs', () => {
|
|
875
|
+
const providedId = 'theia.test-walkthrough';
|
|
876
|
+
const pluginId = 'test.publisher.test-plugin';
|
|
877
|
+
const pluginWalkthroughId = 'test.publisher.test-plugin.test-walkthrough';
|
|
878
|
+
|
|
879
|
+
function createDefinition(overrides?: Partial<WalkthroughDefinition>): WalkthroughDefinition {
|
|
880
|
+
return {
|
|
881
|
+
id: providedId,
|
|
882
|
+
title: 'Provided Walkthrough',
|
|
883
|
+
description: 'Contributed by a Theia extension',
|
|
884
|
+
icon: 'sparkle',
|
|
885
|
+
steps: [
|
|
886
|
+
{ id: 'first', title: 'First', description: 'First step' },
|
|
887
|
+
{ id: 'second', title: 'Second', description: 'Second step' }
|
|
888
|
+
],
|
|
889
|
+
...overrides
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
function provide(...definitions: WalkthroughDefinition[]): void {
|
|
894
|
+
mockWalkthroughProviders = [{ getWalkthroughs: () => definitions }];
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
it('should register the walkthroughs of a provider under their own id', () => {
|
|
898
|
+
provide(createDefinition());
|
|
899
|
+
(service as any).syncWalkthroughs();
|
|
900
|
+
|
|
901
|
+
const walkthrough = service.getWalkthrough(providedId);
|
|
902
|
+
expect(walkthrough).to.not.be.undefined;
|
|
903
|
+
expect(walkthrough!.title).to.equal('Provided Walkthrough');
|
|
904
|
+
expect(walkthrough!.icon).to.equal('sparkle');
|
|
905
|
+
expect(walkthrough!.pluginId).to.be.undefined;
|
|
906
|
+
expect(walkthrough!.steps.map(step => step.isComplete)).to.deep.equal([false, false]);
|
|
907
|
+
});
|
|
908
|
+
|
|
909
|
+
it('should keep plugin and provided walkthroughs alongside each other', () => {
|
|
910
|
+
mockPlugins = [{ model: { id: pluginId, publisher: 'test.publisher', name: 'test-plugin' } }];
|
|
911
|
+
mockDeployedPlugins.set(pluginId, { contributes: { walkthroughs: [createContribution()] } });
|
|
912
|
+
provide(createDefinition());
|
|
913
|
+
(service as any).syncWalkthroughs();
|
|
914
|
+
|
|
915
|
+
expect(service.getWalkthroughs().map(walkthrough => walkthrough.id)).to.have.members([pluginWalkthroughId, providedId]);
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
it('should not drop a provided walkthrough when plugins change', async () => {
|
|
919
|
+
provide(createDefinition());
|
|
920
|
+
(service as any).syncWalkthroughs();
|
|
921
|
+
|
|
922
|
+
mockPlugins = [{ model: { id: pluginId, publisher: 'test.publisher', name: 'test-plugin' } }];
|
|
923
|
+
mockDeployedPlugins.set(pluginId, { contributes: { walkthroughs: [createContribution()] } });
|
|
924
|
+
await (service as any).handlePluginsChanged();
|
|
925
|
+
|
|
926
|
+
expect(service.getWalkthrough(providedId)).to.not.be.undefined;
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
it('should keep the progress of a re-synced, unchanged walkthrough', async () => {
|
|
930
|
+
provide(createDefinition());
|
|
931
|
+
(service as any).syncWalkthroughs();
|
|
932
|
+
await service.markStepComplete(providedId, 'first');
|
|
933
|
+
|
|
934
|
+
(service as any).syncWalkthroughs();
|
|
935
|
+
|
|
936
|
+
expect(service.getWalkthrough(providedId)!.steps[0].isComplete).to.be.true;
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
it('should re-register a walkthrough whose definition changed', () => {
|
|
940
|
+
provide(createDefinition());
|
|
941
|
+
(service as any).syncWalkthroughs();
|
|
942
|
+
expect(service.getWalkthrough(providedId)!.steps).to.have.lengthOf(2);
|
|
943
|
+
|
|
944
|
+
provide(createDefinition({ steps: [{ id: 'only', title: 'Only', description: 'Only step' }] }));
|
|
945
|
+
(service as any).syncWalkthroughs();
|
|
946
|
+
|
|
947
|
+
expect(service.getWalkthrough(providedId)!.steps).to.have.lengthOf(1);
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
it('should drop a walkthrough that is no longer provided', () => {
|
|
951
|
+
provide(createDefinition());
|
|
952
|
+
(service as any).syncWalkthroughs();
|
|
953
|
+
|
|
954
|
+
provide();
|
|
955
|
+
(service as any).syncWalkthroughs();
|
|
956
|
+
|
|
957
|
+
expect(service.getWalkthrough(providedId)).to.be.undefined;
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
it('should keep the other walkthroughs when a provider throws', () => {
|
|
961
|
+
mockWalkthroughProviders = [
|
|
962
|
+
{ getWalkthroughs: () => { throw new Error('provider is broken'); } },
|
|
963
|
+
{ getWalkthroughs: () => [createDefinition()] }
|
|
964
|
+
];
|
|
965
|
+
|
|
966
|
+
(service as any).syncWalkthroughs();
|
|
967
|
+
|
|
968
|
+
expect(service.getWalkthrough(providedId)).to.not.be.undefined;
|
|
969
|
+
});
|
|
970
|
+
|
|
971
|
+
it('should not reject the sync when a provider throws', async () => {
|
|
972
|
+
mockWalkthroughProviders = [{ getWalkthroughs: () => { throw new Error('provider is broken'); } }];
|
|
973
|
+
(service as any).init();
|
|
974
|
+
|
|
975
|
+
// A rejected `progressReady` would stop every later sync, so it has to survive a failing provider.
|
|
976
|
+
await (service as any).progressReady;
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
it('should ignore a walkthrough whose id is already taken', () => {
|
|
980
|
+
mockWalkthroughProviders = [
|
|
981
|
+
{ getWalkthroughs: () => [createDefinition({ title: 'First' })] },
|
|
982
|
+
{ getWalkthroughs: () => [createDefinition({ title: 'Second' })] }
|
|
983
|
+
];
|
|
984
|
+
|
|
985
|
+
(service as any).syncWalkthroughs();
|
|
986
|
+
|
|
987
|
+
expect(service.getWalkthroughs()).to.have.lengthOf(1);
|
|
988
|
+
expect(service.getWalkthrough(providedId)!.title).to.equal('First');
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
it('should re-sync when a provider signals a change', async () => {
|
|
992
|
+
const onDidChangeEmitter = new Emitter<void>();
|
|
993
|
+
let definitions: WalkthroughDefinition[] = [];
|
|
994
|
+
mockWalkthroughProviders = [{
|
|
995
|
+
getWalkthroughs: () => definitions,
|
|
996
|
+
onDidChange: onDidChangeEmitter.event
|
|
997
|
+
}];
|
|
998
|
+
(service as any).init();
|
|
999
|
+
await (service as any).progressReady;
|
|
1000
|
+
expect(service.getWalkthroughs()).to.be.empty;
|
|
1001
|
+
|
|
1002
|
+
definitions = [createDefinition()];
|
|
1003
|
+
onDidChangeEmitter.fire();
|
|
1004
|
+
await (service as any).progressReady;
|
|
1005
|
+
|
|
1006
|
+
expect(service.getWalkthrough(providedId)).to.not.be.undefined;
|
|
1007
|
+
onDidChangeEmitter.dispose();
|
|
1008
|
+
});
|
|
1009
|
+
});
|
|
1010
|
+
|
|
861
1011
|
describe('extensionInstalled completion event', () => {
|
|
862
1012
|
const walkthroughContribution = createContribution({
|
|
863
1013
|
steps: [
|
|
@@ -879,14 +1029,14 @@ describe('WalkthroughService', () => {
|
|
|
879
1029
|
}
|
|
880
1030
|
|
|
881
1031
|
beforeEach(() => {
|
|
882
|
-
// Set up the plugin so the walkthrough is discovered via
|
|
1032
|
+
// Set up the plugin so the walkthrough is discovered via syncWalkthroughs
|
|
883
1033
|
setupPluginWithWalkthrough();
|
|
884
|
-
(service as any).
|
|
1034
|
+
(service as any).syncWalkthroughs();
|
|
885
1035
|
// Wire up the onDidChangePlugins handler manually (simulating @postConstruct)
|
|
886
1036
|
(service as any).toDispose.push(
|
|
887
1037
|
(service as any).pluginSupport.onDidChangePlugins(() => {
|
|
888
1038
|
const previousIds = new Set((service as any).knownPluginIds);
|
|
889
|
-
(service as any).
|
|
1039
|
+
(service as any).syncWalkthroughs();
|
|
890
1040
|
const newIds = new Set(
|
|
891
1041
|
(service as any).pluginSupport.plugins.map((p: any) => p.model.id)
|
|
892
1042
|
);
|
|
@@ -955,7 +1105,7 @@ describe('WalkthroughService', () => {
|
|
|
955
1105
|
|
|
956
1106
|
describe('onContext completion event', () => {
|
|
957
1107
|
beforeEach(() => {
|
|
958
|
-
(
|
|
1108
|
+
registerContribution(createContribution({
|
|
959
1109
|
steps: [
|
|
960
1110
|
{
|
|
961
1111
|
id: 'context-step',
|
|
@@ -1030,7 +1180,7 @@ describe('WalkthroughService', () => {
|
|
|
1030
1180
|
describe('onContext expressions', () => {
|
|
1031
1181
|
it('should complete a step whose context expression already holds at registration', () => {
|
|
1032
1182
|
mockContextKeyMatchResult = true;
|
|
1033
|
-
(
|
|
1183
|
+
registerContribution(createContribution({
|
|
1034
1184
|
steps: [{ id: 'static', title: 'Static', description: 'd', completionEvents: ['onContext:isLinux'] }]
|
|
1035
1185
|
}));
|
|
1036
1186
|
|
|
@@ -1039,7 +1189,7 @@ describe('WalkthroughService', () => {
|
|
|
1039
1189
|
});
|
|
1040
1190
|
|
|
1041
1191
|
it('should react to a context expression rather than treating it as a single key', () => {
|
|
1042
|
-
(
|
|
1192
|
+
registerContribution(createContribution({
|
|
1043
1193
|
steps: [{ id: 'expr', title: 'Expression', description: 'd', completionEvents: ['onContext:foo && bar'] }]
|
|
1044
1194
|
}));
|
|
1045
1195
|
|
|
@@ -1057,7 +1207,7 @@ describe('WalkthroughService', () => {
|
|
|
1057
1207
|
|
|
1058
1208
|
describe('onView completion event', () => {
|
|
1059
1209
|
beforeEach(() => {
|
|
1060
|
-
(
|
|
1210
|
+
registerContribution(createContribution({
|
|
1061
1211
|
steps: [
|
|
1062
1212
|
{
|
|
1063
1213
|
id: 'view-step',
|
|
@@ -1097,7 +1247,7 @@ describe('WalkthroughService', () => {
|
|
|
1097
1247
|
|
|
1098
1248
|
it('should handle multiple onView completion events on different steps', async () => {
|
|
1099
1249
|
// Register a second walkthrough with a different view event
|
|
1100
|
-
(
|
|
1250
|
+
registerContribution(createContribution({
|
|
1101
1251
|
id: 'multi-view-walkthrough',
|
|
1102
1252
|
steps: [
|
|
1103
1253
|
{
|
|
@@ -1134,7 +1284,7 @@ describe('WalkthroughService', () => {
|
|
|
1134
1284
|
|
|
1135
1285
|
describe('onLink completion event', () => {
|
|
1136
1286
|
beforeEach(() => {
|
|
1137
|
-
(
|
|
1287
|
+
registerContribution(createContribution({
|
|
1138
1288
|
steps: [
|
|
1139
1289
|
{
|
|
1140
1290
|
id: 'link-step',
|
|
@@ -1169,7 +1319,7 @@ describe('WalkthroughService', () => {
|
|
|
1169
1319
|
});
|
|
1170
1320
|
|
|
1171
1321
|
it('should complete step with command: URI', async () => {
|
|
1172
|
-
(
|
|
1322
|
+
registerContribution(createContribution({
|
|
1173
1323
|
id: 'cmd-link-walkthrough',
|
|
1174
1324
|
steps: [
|
|
1175
1325
|
{
|
|
@@ -1234,7 +1384,7 @@ describe('WalkthroughService', () => {
|
|
|
1234
1384
|
(service as any).toDispose.push(
|
|
1235
1385
|
(service as any).pluginSupport.onDidChangePlugins(() => {
|
|
1236
1386
|
const previousIds = new Set((service as any).knownPluginIds);
|
|
1237
|
-
(service as any).
|
|
1387
|
+
(service as any).syncWalkthroughs();
|
|
1238
1388
|
const newIds = new Set(
|
|
1239
1389
|
(service as any).pluginSupport.plugins.map((p: any) => p.model.id)
|
|
1240
1390
|
);
|