Skip to content

Commit eef08aa

Browse files
committed
feat(runtime): support glob patterns in editor.fileTree.allowEdits
1 parent afbc81f commit eef08aa

File tree

4 files changed

+166
-4
lines changed

4 files changed

+166
-4
lines changed

docs/tutorialkit.dev/src/content/docs/reference/configuration.mdx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,11 @@ File tree can be set to allow file editing from right clicks by setting `fileTre
144144
The `Editor` type has the following shape:
145145

146146
```ts
147+
type GlobPattern = string
148+
147149
type Editor =
148150
| false
149-
| { editor: { allowEdits: boolean } }
151+
| { editor: { allowEdits: boolean | GlobPattern | GlobPattern[] } }
150152

151153
```
152154

@@ -161,6 +163,18 @@ editor: # Editor is visible
161163
editor: # Editor is visible
162164
fileTree: # File tree is visible
163165
allowEdits: true # User can add new files and folders from the file tree
166+
167+
168+
editor: # Editor is visible
169+
fileTree: # File tree is visible
170+
allowEdits: "/src/**" # User can add files and folders anywhere inside "/src/"
171+
172+
editor: # Editor is visible
173+
fileTree: # File tree is visible
174+
allowEdits:
175+
- "/*" # User can add files and folders directly in the root
176+
- "/first-level/allowed-filename-only.js" # Only "allowed-filename-only.js" inside "/first-level" folder
177+
- "**/second-level/**" # Anything inside "second-level" folders anywhere
164178
```
165179
166180
##### `previews`
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { expect, test } from 'vitest';
2+
import { EditorConfig } from './editor-config.js';
3+
4+
expect.addSnapshotSerializer({
5+
serialize: (val: EditorConfig) => JSON.stringify({ visible: val.visible, fileTree: val.fileTree }, null, 2),
6+
test: (val) => val instanceof EditorConfig,
7+
});
8+
9+
test('sets default values', () => {
10+
const config = new EditorConfig();
11+
12+
expect(config).toMatchInlineSnapshot(`
13+
{
14+
"visible": true,
15+
"fileTree": {
16+
"visible": true,
17+
"allowEdits": false
18+
}
19+
}
20+
`);
21+
});
22+
23+
test('false hides editor', () => {
24+
const config = new EditorConfig(false);
25+
26+
expect(config).toMatchInlineSnapshot(`
27+
{
28+
"visible": false,
29+
"fileTree": {
30+
"visible": false,
31+
"allowEdits": false
32+
}
33+
}
34+
`);
35+
});
36+
37+
test('true enables editor, doesnt allow editing', () => {
38+
const config = new EditorConfig(true);
39+
40+
expect(config).toMatchInlineSnapshot(`
41+
{
42+
"visible": true,
43+
"fileTree": {
44+
"visible": true,
45+
"allowEdits": false
46+
}
47+
}
48+
`);
49+
});
50+
51+
test('"fileTree: false" hides fileTree', () => {
52+
const config = new EditorConfig({ fileTree: false });
53+
54+
expect(config).toMatchInlineSnapshot(`
55+
{
56+
"visible": true,
57+
"fileTree": {
58+
"visible": false,
59+
"allowEdits": false
60+
}
61+
}
62+
`);
63+
});
64+
65+
test('"fileTree: true" enables fileTree, disables editing', () => {
66+
const config = new EditorConfig({ fileTree: true });
67+
68+
expect(config.fileTree).toMatchInlineSnapshot(`
69+
{
70+
"allowEdits": false,
71+
"visible": true,
72+
}
73+
`);
74+
});
75+
76+
test('"fileTree.allowEdits: true" allows editing all entries', () => {
77+
const config = new EditorConfig({ fileTree: { allowEdits: true } });
78+
79+
expect(config.fileTree).toMatchInlineSnapshot(`
80+
{
81+
"allowEdits": [
82+
"**",
83+
],
84+
"visible": true,
85+
}
86+
`);
87+
});
88+
89+
test('"fileTree.allowEdits: false" disables all editing', () => {
90+
const config = new EditorConfig({ fileTree: { allowEdits: false } });
91+
92+
expect(config.fileTree).toMatchInlineSnapshot(`
93+
{
94+
"allowEdits": false,
95+
"visible": true,
96+
}
97+
`);
98+
});
99+
100+
test('"fileTree.allowEdits" is converted to array', () => {
101+
const config = new EditorConfig({ fileTree: { allowEdits: '/src/**' } });
102+
103+
expect(config.fileTree).toMatchInlineSnapshot(`
104+
{
105+
"allowEdits": [
106+
"/src/**",
107+
],
108+
"visible": true,
109+
}
110+
`);
111+
});
112+
113+
test('"fileTree.allowEdits: [...]" works', () => {
114+
const config = new EditorConfig({ fileTree: { allowEdits: ['/src/**', '**/*.test.ts'] } });
115+
116+
expect(config.fileTree).toMatchInlineSnapshot(`
117+
{
118+
"allowEdits": [
119+
"/src/**",
120+
"**/*.test.ts",
121+
],
122+
"visible": true,
123+
}
124+
`);
125+
});

packages/runtime/src/webcontainer/editor-config.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ interface NormalizedEditorConfig {
99
visible: boolean;
1010

1111
/** Whether to allow file and folder editing in file tree */
12-
allowEdits: boolean;
12+
allowEdits: false | string[];
1313
};
1414
}
1515

@@ -60,11 +60,25 @@ function normalizeEditorConfig(config?: EditorSchema): NormalizedEditorConfig {
6060
};
6161
}
6262

63+
if (typeof config.fileTree?.allowEdits === 'boolean' || !config.fileTree?.allowEdits) {
64+
return {
65+
visible: true,
66+
fileTree: {
67+
visible: true,
68+
allowEdits: config.fileTree?.allowEdits ? ['**'] : false,
69+
},
70+
};
71+
}
72+
6373
return {
6474
visible: true,
6575
fileTree: {
6676
visible: true,
67-
allowEdits: config.fileTree?.allowEdits || false,
77+
allowEdits: toArray(config.fileTree.allowEdits),
6878
},
6979
};
7080
}
81+
82+
function toArray<T>(items: T | T[]): T[] {
83+
return Array.isArray(items) ? items : [items];
84+
}

packages/types/src/schemas/common.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,16 @@ export const editorSchema = z.union([
174174
// or configure file tree with options
175175
z.strictObject({
176176
allowEdits: z
177-
.boolean()
177+
.union([
178+
// allow editing all files or disable completely
179+
z.boolean(),
180+
181+
// limit file editing to files and folders that match a single glob pattern
182+
z.string(),
183+
184+
// limit file editing to files and folders that match one of multiple glob patterns
185+
z.array(z.string()),
186+
])
178187
.describe(
179188
'Allow file tree’s items to be edited by right clicking them. Supports file and folder creation.',
180189
),

0 commit comments

Comments
 (0)