Skip to content

Commit c7f1937

Browse files
authored
feat: allow renaming editor files (#1158)
* feat: allow renaming editor files * fix: adjust input width
1 parent 517910c commit c7f1937

File tree

4 files changed

+207
-1
lines changed

4 files changed

+207
-1
lines changed

src/less/blueprint.less

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,8 @@
4343
.bp3-running-text {
4444
font-size: 14px;
4545
}
46+
47+
.bp3-alert-contents {
48+
width: 100%;
49+
}
4650
}

src/renderer/components/sidebar-file-tree.tsx

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import classNames from 'classnames';
1515
import { observer } from 'mobx-react';
1616

1717
import { EditorId } from '../../interfaces';
18-
import { isRequiredFile } from '../../utils/editor-utils';
18+
import { isRequiredFile, isSupportedFile } from '../../utils/editor-utils';
1919
import { EditorPresence } from '../editor-mosaic';
2020
import { AppState } from '../state';
2121

@@ -61,6 +61,12 @@ export const SidebarFileTree = observer(
6161
onClick={() => this.setFocusedFile(editorId)}
6262
content={
6363
<Menu>
64+
<MenuItem
65+
icon="redo"
66+
text="Rename"
67+
intent="primary"
68+
onClick={() => this.renameEditor(editorId)}
69+
/>
6470
<MenuItem
6571
disabled={isRequiredFile(editorId)}
6672
icon="remove"
@@ -170,6 +176,33 @@ export const SidebarFileTree = observer(
170176
editorMosaic.setFocusedFile(editorId);
171177
};
172178

179+
public renameEditor = async (editorId: EditorId) => {
180+
const { appState } = this.props;
181+
182+
const visible =
183+
appState.editorMosaic.files.get(editorId) === EditorPresence.Visible;
184+
const id = (await appState.showInputDialog({
185+
label: 'Enter New Filename',
186+
ok: 'Rename',
187+
placeholder: 'New Name',
188+
})) as EditorId;
189+
190+
if (!id) return;
191+
192+
if (!isSupportedFile(id)) {
193+
await appState.showErrorDialog(
194+
`Invalid filename "${id}": Must be a file ending in .js, .html, or .css`,
195+
);
196+
return;
197+
}
198+
199+
const contents = appState.editorMosaic.value(editorId).trim();
200+
appState.editorMosaic.remove(editorId);
201+
appState.editorMosaic.addNewFile(id, contents);
202+
203+
if (visible) appState.editorMosaic.show(id);
204+
};
205+
173206
public removeEditor = (editorId: EditorId) => {
174207
const { editorMosaic } = this.props.appState;
175208
editorMosaic.remove(editorId);

tests/renderer/components/__snapshots__/sidebar-file-tree-spec.tsx.snap

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ exports[`SidebarFileTree component can bring up the Add File input 1`] = `
2222
className="pointer"
2323
content={
2424
<Blueprint3.Menu>
25+
<Blueprint3.MenuItem
26+
disabled={false}
27+
icon="redo"
28+
intent="primary"
29+
multiline={false}
30+
onClick={[Function]}
31+
popoverProps={Object {}}
32+
shouldDismissPopover={true}
33+
text="Rename"
34+
/>
2535
<Blueprint3.MenuItem
2636
disabled={false}
2737
icon="remove"
@@ -66,6 +76,16 @@ exports[`SidebarFileTree component can bring up the Add File input 1`] = `
6676
className="pointer"
6777
content={
6878
<Blueprint3.Menu>
79+
<Blueprint3.MenuItem
80+
disabled={false}
81+
icon="redo"
82+
intent="primary"
83+
multiline={false}
84+
onClick={[Function]}
85+
popoverProps={Object {}}
86+
shouldDismissPopover={true}
87+
text="Rename"
88+
/>
6989
<Blueprint3.MenuItem
7090
disabled={true}
7191
icon="remove"
@@ -110,6 +130,16 @@ exports[`SidebarFileTree component can bring up the Add File input 1`] = `
110130
className="pointer"
111131
content={
112132
<Blueprint3.Menu>
133+
<Blueprint3.MenuItem
134+
disabled={false}
135+
icon="redo"
136+
intent="primary"
137+
multiline={false}
138+
onClick={[Function]}
139+
popoverProps={Object {}}
140+
shouldDismissPopover={true}
141+
text="Rename"
142+
/>
113143
<Blueprint3.MenuItem
114144
disabled={false}
115145
icon="remove"
@@ -154,6 +184,16 @@ exports[`SidebarFileTree component can bring up the Add File input 1`] = `
154184
className="pointer"
155185
content={
156186
<Blueprint3.Menu>
187+
<Blueprint3.MenuItem
188+
disabled={false}
189+
icon="redo"
190+
intent="primary"
191+
multiline={false}
192+
onClick={[Function]}
193+
popoverProps={Object {}}
194+
shouldDismissPopover={true}
195+
text="Rename"
196+
/>
157197
<Blueprint3.MenuItem
158198
disabled={false}
159199
icon="remove"
@@ -198,6 +238,16 @@ exports[`SidebarFileTree component can bring up the Add File input 1`] = `
198238
className="pointer"
199239
content={
200240
<Blueprint3.Menu>
241+
<Blueprint3.MenuItem
242+
disabled={false}
243+
icon="redo"
244+
intent="primary"
245+
multiline={false}
246+
onClick={[Function]}
247+
popoverProps={Object {}}
248+
shouldDismissPopover={true}
249+
text="Rename"
250+
/>
201251
<Blueprint3.MenuItem
202252
disabled={false}
203253
icon="remove"
@@ -316,6 +366,16 @@ exports[`SidebarFileTree component reflects the visibility state of all icons 1`
316366
className="pointer"
317367
content={
318368
<Blueprint3.Menu>
369+
<Blueprint3.MenuItem
370+
disabled={false}
371+
icon="redo"
372+
intent="primary"
373+
multiline={false}
374+
onClick={[Function]}
375+
popoverProps={Object {}}
376+
shouldDismissPopover={true}
377+
text="Rename"
378+
/>
319379
<Blueprint3.MenuItem
320380
disabled={false}
321381
icon="remove"
@@ -360,6 +420,16 @@ exports[`SidebarFileTree component reflects the visibility state of all icons 1`
360420
className="pointer"
361421
content={
362422
<Blueprint3.Menu>
423+
<Blueprint3.MenuItem
424+
disabled={false}
425+
icon="redo"
426+
intent="primary"
427+
multiline={false}
428+
onClick={[Function]}
429+
popoverProps={Object {}}
430+
shouldDismissPopover={true}
431+
text="Rename"
432+
/>
363433
<Blueprint3.MenuItem
364434
disabled={true}
365435
icon="remove"
@@ -404,6 +474,16 @@ exports[`SidebarFileTree component reflects the visibility state of all icons 1`
404474
className="pointer"
405475
content={
406476
<Blueprint3.Menu>
477+
<Blueprint3.MenuItem
478+
disabled={false}
479+
icon="redo"
480+
intent="primary"
481+
multiline={false}
482+
onClick={[Function]}
483+
popoverProps={Object {}}
484+
shouldDismissPopover={true}
485+
text="Rename"
486+
/>
407487
<Blueprint3.MenuItem
408488
disabled={false}
409489
icon="remove"
@@ -448,6 +528,16 @@ exports[`SidebarFileTree component reflects the visibility state of all icons 1`
448528
className="pointer"
449529
content={
450530
<Blueprint3.Menu>
531+
<Blueprint3.MenuItem
532+
disabled={false}
533+
icon="redo"
534+
intent="primary"
535+
multiline={false}
536+
onClick={[Function]}
537+
popoverProps={Object {}}
538+
shouldDismissPopover={true}
539+
text="Rename"
540+
/>
451541
<Blueprint3.MenuItem
452542
disabled={false}
453543
icon="remove"
@@ -492,6 +582,16 @@ exports[`SidebarFileTree component reflects the visibility state of all icons 1`
492582
className="pointer"
493583
content={
494584
<Blueprint3.Menu>
585+
<Blueprint3.MenuItem
586+
disabled={false}
587+
icon="redo"
588+
intent="primary"
589+
multiline={false}
590+
onClick={[Function]}
591+
popoverProps={Object {}}
592+
shouldDismissPopover={true}
593+
text="Rename"
594+
/>
495595
<Blueprint3.MenuItem
496596
disabled={false}
497597
icon="remove"
@@ -592,6 +692,16 @@ exports[`SidebarFileTree component renders 1`] = `
592692
className="pointer"
593693
content={
594694
<Blueprint3.Menu>
695+
<Blueprint3.MenuItem
696+
disabled={false}
697+
icon="redo"
698+
intent="primary"
699+
multiline={false}
700+
onClick={[Function]}
701+
popoverProps={Object {}}
702+
shouldDismissPopover={true}
703+
text="Rename"
704+
/>
595705
<Blueprint3.MenuItem
596706
disabled={false}
597707
icon="remove"
@@ -636,6 +746,16 @@ exports[`SidebarFileTree component renders 1`] = `
636746
className="pointer"
637747
content={
638748
<Blueprint3.Menu>
749+
<Blueprint3.MenuItem
750+
disabled={false}
751+
icon="redo"
752+
intent="primary"
753+
multiline={false}
754+
onClick={[Function]}
755+
popoverProps={Object {}}
756+
shouldDismissPopover={true}
757+
text="Rename"
758+
/>
639759
<Blueprint3.MenuItem
640760
disabled={true}
641761
icon="remove"
@@ -680,6 +800,16 @@ exports[`SidebarFileTree component renders 1`] = `
680800
className="pointer"
681801
content={
682802
<Blueprint3.Menu>
803+
<Blueprint3.MenuItem
804+
disabled={false}
805+
icon="redo"
806+
intent="primary"
807+
multiline={false}
808+
onClick={[Function]}
809+
popoverProps={Object {}}
810+
shouldDismissPopover={true}
811+
text="Rename"
812+
/>
683813
<Blueprint3.MenuItem
684814
disabled={false}
685815
icon="remove"
@@ -724,6 +854,16 @@ exports[`SidebarFileTree component renders 1`] = `
724854
className="pointer"
725855
content={
726856
<Blueprint3.Menu>
857+
<Blueprint3.MenuItem
858+
disabled={false}
859+
icon="redo"
860+
intent="primary"
861+
multiline={false}
862+
onClick={[Function]}
863+
popoverProps={Object {}}
864+
shouldDismissPopover={true}
865+
text="Rename"
866+
/>
727867
<Blueprint3.MenuItem
728868
disabled={false}
729869
icon="remove"
@@ -768,6 +908,16 @@ exports[`SidebarFileTree component renders 1`] = `
768908
className="pointer"
769909
content={
770910
<Blueprint3.Menu>
911+
<Blueprint3.MenuItem
912+
disabled={false}
913+
icon="redo"
914+
intent="primary"
915+
multiline={false}
916+
onClick={[Function]}
917+
popoverProps={Object {}}
918+
shouldDismissPopover={true}
919+
text="Rename"
920+
/>
771921
<Blueprint3.MenuItem
772922
disabled={false}
773923
icon="remove"

tests/renderer/components/sidebar-file-tree-spec.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,25 @@ describe('SidebarFileTree component', () => {
8080
expect(editorMosaic.files.get('index.html')).toBe(undefined);
8181
});
8282

83+
it('can rename editors', async () => {
84+
const wrapper = shallow(<SidebarFileTree appState={store} />);
85+
const instance: any = wrapper.instance() as any;
86+
87+
const EDITOR_NAME = 'index.html';
88+
const EDITOR_NEW_NAME = 'new_index.html';
89+
90+
store.showInputDialog = jest.fn().mockResolvedValueOnce(EDITOR_NEW_NAME);
91+
92+
expect(editorMosaic.files.get(EDITOR_NAME)).toBe(EditorPresence.Pending);
93+
94+
await instance.renameEditor(EDITOR_NAME);
95+
96+
expect(editorMosaic.files.get(EDITOR_NAME)).toBe(undefined);
97+
expect(editorMosaic.files.get(EDITOR_NEW_NAME)).toBe(
98+
EditorPresence.Pending,
99+
);
100+
});
101+
83102
it('can reset the editor layout', () => {
84103
const wrapper = shallow(<SidebarFileTree appState={store} />);
85104
const instance: any = wrapper.instance() as any;

0 commit comments

Comments
 (0)