Skip to content

Commit c77e198

Browse files
JeanMecheatscott
authored andcommitted
docs(docs-infra): limit file interactions on tutorials. (angular#61696)
The restricted mode on the code editor prevents renaming, deleting or adding files. PR Close angular#61696
1 parent c11527f commit c77e198

File tree

8 files changed

+100
-92
lines changed

8 files changed

+100
-92
lines changed

adev/shared-docs/interfaces/tutorial.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export type TutorialNavigationData = {
140140
previousStep?: string;
141141
nextTutorial?: string;
142142
sourceCodeZipPath?: string;
143+
restrictedMode: boolean;
143144
};
144145

145146
export type PlaygroundRouteData = {

adev/shared-docs/pipeline/tutorials/routes.mts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export async function generateTutorialRoutes(
4747
title: config.title,
4848
type: config.type,
4949
step: idx + 1,
50+
restrictedMode: true,
5051
},
5152
};
5253
});
@@ -75,6 +76,7 @@ export async function generateTutorialRoutes(
7576
title: introConfig.title,
7677
type: introConfig.type,
7778
nextStep: children[0].path,
79+
restrictedMode: children[0].tutorialData.restrictedMode,
7880
},
7981
children: children,
8082
};

adev/src/app/editor/code-editor/code-editor.component.html

Lines changed: 70 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -8,61 +8,68 @@
88
not call another time init method from CodeMirrorEditor service.
99
-->
1010
@for (file of files(); track file) {
11-
<mat-tab #tab>
12-
<ng-template mat-tab-label>
13-
@if (tab.isActive && isRenamingFile()) {
14-
<form
15-
(submit)="renameFile($event, file.filename)"
16-
(docsClickOutside)="closeRenameFile()">
11+
<mat-tab #tab>
12+
<ng-template mat-tab-label>
13+
@if (tab.isActive && isRenamingFile()) {
14+
<form
15+
(submit)="renameFile($event, file.filename)"
16+
(docsClickOutside)="closeRenameFile()"
17+
>
18+
<input
19+
name="rename-file"
20+
class="adev-rename-file-input"
21+
#renameFileInput
22+
(keydown)="$event.stopPropagation()"
23+
/>
24+
</form>
25+
} @else if(restrictedMode()) {
26+
{{ file.filename.replace('src/app/', '') }}
27+
} @else {
28+
{{ file.filename.replace('src/', '') }}
29+
}
30+
31+
@if (tab.isActive && canRenameFile(file.filename)) {
32+
<button
33+
class="docs-rename-file"
34+
aria-label="rename file"
35+
(click)="onRenameButtonClick()"
36+
>
37+
<docs-icon>edit</docs-icon>
38+
</button>
39+
}
40+
@if (tab.isActive && canDeleteFile(file.filename)) {
41+
<button
42+
class="docs-delete-file"
43+
aria-label="Delete file"
44+
(click)="deleteFile(file.filename)"
45+
>
46+
<docs-icon>delete</docs-icon>
47+
</button>
48+
}
49+
</ng-template>
50+
</mat-tab>
51+
}
52+
@if (isCreatingFile()) {
53+
<mat-tab>
54+
<ng-template mat-tab-label>
55+
<form (submit)="createFile($event)">
1756
<input
18-
name="rename-file"
19-
class="adev-rename-file-input"
20-
#renameFileInput
57+
name="new-file"
58+
class="adev-new-file-input"
59+
#createFileInput
2160
(keydown)="$event.stopPropagation()"
2261
/>
2362
</form>
24-
} @else {
25-
{{ file.filename.replace('src/', '') }}
26-
}
27-
@if (tab.isActive && canRenameFile(file.filename)) {
28-
<button
29-
class="docs-rename-file"
30-
aria-label="rename file"
31-
(click)="onRenameButtonClick()"
32-
>
33-
<docs-icon>edit</docs-icon>
34-
</button>
35-
}
36-
@if (tab.isActive && canDeleteFile(file.filename)) {
37-
<button
38-
class="docs-delete-file"
39-
aria-label="Delete file"
40-
(click)="deleteFile(file.filename)"
41-
>
42-
<docs-icon>delete</docs-icon>
43-
</button>
44-
}
45-
</ng-template>
46-
</mat-tab>
47-
} @if (isCreatingFile()) {
48-
<mat-tab>
49-
<ng-template mat-tab-label>
50-
<form (submit)="createFile($event)">
51-
<input
52-
name="new-file"
53-
class="adev-new-file-input"
54-
#createFileInput
55-
(keydown)="$event.stopPropagation()"
56-
/>
57-
</form>
58-
</ng-template>
59-
</mat-tab>
63+
</ng-template>
64+
</mat-tab>
6065
}
6166
</mat-tab-group>
6267

63-
<button class="adev-add-file" (click)="onAddButtonClick()" aria-label="Add a new file">
64-
<docs-icon>add</docs-icon>
65-
</button>
68+
@if (canCreateFile()) {
69+
<button class="adev-add-file" (click)="onAddButtonClick()" aria-label="Add a new file">
70+
<docs-icon>add</docs-icon>
71+
</button>
72+
}
6673
</div>
6774

6875
<button
@@ -76,13 +83,11 @@
7683
<!-- launcher dropdown window -->
7784
<ng-template #launcherMenu>
7885
<div class="adev-editor-dropdown" cdkMenu>
79-
<button cdkMenuItem (click)="openCurrentSolutionInIDX()">
80-
<span>Open in IDX </span>
81-
<img class="icon" src="assets/images/tutorials/common/idx_logo.svg" height="32">
82-
</button>
83-
<button cdkMenuItem (click)="openCurrentCodeInStackBlitz()">
84-
Open in StackBlitz
85-
</button>
86+
<button cdkMenuItem (click)="openCurrentSolutionInIDX()">
87+
<span>Open in IDX </span>
88+
<img class="icon" src="assets/images/tutorials/common/idx_logo.svg" height="32" />
89+
</button>
90+
<button cdkMenuItem (click)="openCurrentCodeInStackBlitz()">Open in StackBlitz</button>
8691
</div>
8792
</ng-template>
8893
<button
@@ -100,14 +105,14 @@
100105
<div #codeEditorWrapper class="adev-code-editor-wrapper"></div>
101106

102107
@if (displayErrorsBox()) {
103-
<div class="adev-inline-errors-box">
104-
<button type="button" (click)="closeErrorsBox()">
105-
<docs-icon class="docs-icon_high-contrast">close</docs-icon>
106-
</button>
107-
<ul>
108-
@for (error of errors(); track error) {
109-
<li>(line: {{ error.lineNumber }}:{{ error.characterPosition }}) {{ error.message }}</li>
110-
}
111-
</ul>
112-
</div>
108+
<div class="adev-inline-errors-box">
109+
<button type="button" (click)="closeErrorsBox()">
110+
<docs-icon class="docs-icon_high-contrast">close</docs-icon>
111+
</button>
112+
<ul>
113+
@for (error of errors(); track error) {
114+
<li>(line: {{ error.lineNumber }}:{{ error.characterPosition }}) {{ error.message }}</li>
115+
}
116+
</ul>
117+
</div>
113118
}

adev/src/app/editor/code-editor/code-editor.component.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
OnDestroy,
1818
afterRenderEffect,
1919
inject,
20+
input,
2021
signal,
2122
viewChild,
2223
} from '@angular/core';
@@ -61,6 +62,8 @@ const ANGULAR_DEV = 'https://angular.dev';
6162
],
6263
})
6364
export class CodeEditor implements AfterViewInit, OnDestroy {
65+
readonly restrictedMode = input(false);
66+
6467
readonly codeEditorWrapperRef =
6568
viewChild.required<ElementRef<HTMLDivElement>>('codeEditorWrapper');
6669
readonly matTabGroup = viewChild.required(MatTabGroup);
@@ -157,9 +160,11 @@ export class CodeEditor implements AfterViewInit, OnDestroy {
157160
canRenameFile = (filename: string) => this.canDeleteFile(filename);
158161

159162
canDeleteFile(filename: string) {
160-
return !REQUIRED_FILES.has(filename);
163+
return !REQUIRED_FILES.has(filename) && !this.restrictedMode();
161164
}
162165

166+
canCreateFile = () => !this.restrictedMode();
167+
163168
async deleteFile(filename: string) {
164169
await this.codeMirrorEditor.deleteFile(filename);
165170
this.matTabGroup().selectedIndex = 0;

adev/src/app/editor/embedded-editor.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
} @else {
99
<as-split class="docs-editor" [direction]="splitDirection()" restrictMove="true" gutterSize="5">
1010
<as-split-area class="adev-left-side" size="50">
11-
<docs-tutorial-code-editor class="adev-tutorial-code-editor" />
11+
<docs-tutorial-code-editor class="adev-tutorial-code-editor" [restrictedMode]="restrictedMode()" />
1212
</as-split-area>
1313

1414
<as-split-area size="50">

adev/src/app/editor/embedded-editor.component.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
afterRenderEffect,
1717
computed,
1818
inject,
19+
input,
1920
linkedSignal,
2021
signal,
2122
viewChild,
@@ -51,6 +52,9 @@ export const LARGE_EDITOR_HEIGHT_BREAKPOINT = 550;
5152
providers: [EditorUiState],
5253
})
5354
export class EmbeddedEditor {
55+
// Prevents from adding, removing or renaming files
56+
restrictedMode = input<boolean>(false);
57+
5458
readonly editorContainer = viewChild<ElementRef<HTMLDivElement>>('editorContainer');
5559
readonly matTabGroup = viewChild(MatTabGroup);
5660

adev/src/app/features/tutorial/tutorial.component.html

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
<div class="adev-page-content" [class.adev-nav-open]="showNavigationDropdown()">
22
<ng-container *ngTemplateOutlet="tutorialNav" />
3-
@if (shouldRenderContent()) {
4-
<div
5-
#content
6-
class="docs-tutorial-content"
7-
[class.adev-nav-open]="showNavigationDropdown()"
8-
>
3+
@if (shouldRenderContent()) {
4+
<div #content class="docs-tutorial-content" [class.adev-nav-open]="showNavigationDropdown()">
95
<!-- Tutorial Nav: Current Tutorial Title and Nav Buttons -->
106
<ng-container *ngTemplateOutlet="tutorialNav" />
117

128
<!-- Tutorial Content -->
139
@if (documentContent(); as documentContent) {
14-
<docs-viewer
15-
[docContent]="documentContent"
16-
class="docs-viewer docs-viewer-scroll-margin-large"
17-
/>
10+
<docs-viewer
11+
[docContent]="documentContent"
12+
class="docs-viewer docs-viewer-scroll-margin-large"
13+
/>
1814
}
19-
</div>}
15+
</div>
16+
}
2017

2118
<!-- Split View Resizer -->
2219
<button
@@ -28,13 +25,11 @@
2825

2926
<!-- Embedded Editor -->
3027
@if (shouldRenderEmbeddedEditor()) {
31-
<div
32-
#editor
33-
class="docs-tutorial-editor"
34-
[class.adev-split-tutorial]="shouldRenderContent()"
35-
>
28+
<div #editor class="docs-tutorial-editor" [class.adev-split-tutorial]="shouldRenderContent()">
3629
@if (embeddedEditorComponent) {
37-
<ng-container *ngComponentOutlet="embeddedEditorComponent" />
30+
<ng-container
31+
*ngComponentOutlet="embeddedEditorComponent; inputs:{restrictedMode:restrictedMode()}"
32+
/>
3833
}
3934
</div>
4035
}
@@ -70,10 +65,7 @@
7065

7166
<!-- Download code -->
7267
@if (localTutorialZipUrl()) {
73-
<a
74-
[download]="stepName() + '.zip'"
75-
[href]="localTutorialZipUrl()"
76-
>
68+
<a [download]="stepName() + '.zip'" [href]="localTutorialZipUrl()">
7769
<button class="adev-download-button docs-primary-btn">
7870
<docs-icon>download</docs-icon>
7971
</button>
@@ -127,10 +119,7 @@
127119

128120
<!-- Tutorial Nav: List -->
129121
@if (showNavigationDropdown()) {
130-
<div
131-
class="adev-tutorial-nav-list-dropdown"
132-
(docsClickOutside)="hideNavigationDropdown()"
133-
>
122+
<div class="adev-tutorial-nav-list-dropdown" (docsClickOutside)="hideNavigationDropdown()">
134123
<docs-navigation-list
135124
[isDropdownView]="true"
136125
[navigationItems]="tutorialNavigationItems()"

adev/src/app/features/tutorial/tutorial.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export default class Tutorial {
9898
readonly shouldRenderContent = signal<boolean>(false);
9999
readonly shouldRenderEmbeddedEditor = signal<boolean>(false);
100100
readonly shouldRenderRevealAnswer = signal<boolean>(false);
101+
readonly restrictedMode = signal<boolean>(false);
101102

102103
nextStepPath: string | undefined;
103104
previousStepPath: string | undefined;
@@ -188,6 +189,7 @@ export default class Tutorial {
188189
private async setTutorialData(tutorialNavigationItem: TutorialNavigationItem): Promise<void> {
189190
this.showNavigationDropdown.set(false);
190191
this.answerRevealed.set(false);
192+
this.restrictedMode.set(tutorialNavigationItem.tutorialData.restrictedMode);
191193

192194
this.setRouteData(tutorialNavigationItem);
193195

0 commit comments

Comments
 (0)