Skip to content

Commit ff6019c

Browse files
committed
WiP on adding minimal editor after frontend file upload
1 parent e8bd743 commit ff6019c

File tree

9 files changed

+219
-117
lines changed

9 files changed

+219
-117
lines changed

client/browser/BrowserEditor.tsx

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,99 @@
1-
import React, {lazy, Suspense, useMemo} from 'react';
1+
import React, {lazy, Suspense, useEffect, useMemo, useState} from 'react';
2+
import {createRoot} from 'react-dom/client';
23
import SelectLabels from '../finder/SelectLabels';
34

45

6+
function EditorForm(props) {
7+
const {mainContent, file_info, settings} = props;
8+
const [formHtml, setFormHtml] = useState(props.form_html);
9+
10+
useEffect(() => {
11+
const shadowRoot = mainContent.getRootNode();
12+
if (!(shadowRoot instanceof ShadowRoot))
13+
return;
14+
const labelsElement = shadowRoot.getElementById('id_labels');
15+
if (!(labelsElement instanceof HTMLSelectElement))
16+
return;
17+
if (settings.labels) {
18+
// replace the original <select multiple name="labels"> element with the "downshift" component
19+
if (labelsElement.nextElementSibling?.classList.contains('select-labels-container')) {
20+
labelsElement.nextElementSibling.remove();
21+
}
22+
const divElement = document.createElement('div');
23+
divElement.classList.add('select-labels-container');
24+
labelsElement.insertAdjacentElement('afterend', divElement);
25+
const root = createRoot(divElement);
26+
root.render(<SelectLabels labels={settings.labels} initial={[]} original={labelsElement}/>);
27+
}
28+
labelsElement.style.display = 'none';
29+
}, [formHtml]);
30+
31+
function handleSave() {
32+
const changeUrl = `${settings.baseUrl}${file_info.id}/change`;
33+
const form = mainContent.querySelector('form');
34+
if (!(form instanceof HTMLFormElement))
35+
throw new Error('Form not found');
36+
const formData = new FormData(form);
37+
fetch(changeUrl, {
38+
method: 'POST',
39+
body: formData,
40+
headers: {
41+
'X-CSRFToken': settings.csrfToken,
42+
},
43+
}).then(async response => {
44+
if (response.ok) {
45+
const content = await response.json();
46+
if ('file_info' in content) {
47+
settings.selectFile(file_info);
48+
} else if ('form_html' in content) {
49+
setFormHtml(content.form_html);
50+
} else {
51+
alert('Unexpected response');
52+
}
53+
} else {
54+
alert(response.statusText);
55+
}
56+
});
57+
}
58+
59+
function handleDismiss() {
60+
window.location.reload();
61+
}
62+
63+
return (
64+
<form>
65+
<div dangerouslySetInnerHTML={{__html: formHtml}}/>
66+
<div className="button-row">
67+
<button type="button" className="default" onClick={handleSave}>{gettext("Save")}</button>
68+
<button type="button" className="dismiss" onClick={handleDismiss}>{gettext("Dismiss")}</button>
69+
</div>
70+
</form>
71+
);
72+
}
73+
74+
575
export default function BrowserEditor(props) {
6-
const {uploadedFile, mainContent} = props;
76+
const {uploadedFile, mainContent, settings} = props as {uploadedFile: any, mainContent: HTMLElement, settings: any};
777
const DetailEditor = useMemo(() => {
878
if (uploadedFile.file_info.browser_component) {
979
const component = `./components/browser/${uploadedFile.file_info.browser_component}.js`;
1080
const LazyItem = lazy(() => import(component));
1181
return (props) => (
12-
<div className="detail-editor">
82+
<div className="browser-editor">
1383
<Suspense fallback={<span>{gettext("Loading...")}</span>}>
1484
<LazyItem fileInfo={props.file_info} />
1585
</Suspense>
16-
<form>
17-
<SelectLabels settings={{labels: uploadedFile.labels, mainContent: mainContent}} />
18-
<div dangerouslySetInnerHTML={{__html: props.form_html}} />
19-
</form>
86+
<EditorForm {...props} />
2087
</div>
2188
);
2289
}
2390
return (props) => (
24-
<div className="detail-editor">
91+
<div className="browser-editor">
2592
<img src={props.file_info.thumbnail_url} />
26-
<form>
27-
<SelectLabels settings={{labels: uploadedFile.labels, mainContent: mainContent}} />
28-
<div dangerouslySetInnerHTML={{__html: props.form_html}} />
29-
</form>
93+
<EditorForm {...props} />
3094
</div>
3195
);
3296
}, [uploadedFile.file_info.browser_component]);
3397

34-
return <DetailEditor {...uploadedFile} />;
98+
return <DetailEditor mainContent={mainContent} {...uploadedFile} settings={settings} />;
3599
}

client/browser/FileSelectDialog.tsx

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import FigureLabels from '../finder/FigureLabels';
1212
import BrowserEditor from './BrowserEditor';
1313
import FileUploader from '../finder/FileUploader';
1414
import FolderStructure from './FolderStructure';
15-
import Menu from './Menu';
15+
import MenuBar from './MenuBar';
1616

1717

1818
function StaticFigure(props) {
@@ -67,16 +67,31 @@ const FilesList = memo((props: any) => {
6767

6868

6969
export default function FileSelectDialog(props) {
70-
const {baseUrl, csrfToken, realm, selectFile} = props;
70+
const {realm, baseUrl, csrfToken, selectFile} = props;
7171
const [structure, setStructure] = useState({root_folder: null, last_folder: null, files: null});
7272
const [uploadedFile, setUploadedFile] = useState(null);
7373
const ref = useRef(null);
7474
const uploaderRef = useRef(null);
75+
const dialog = ref.current?.closest('dialog');
7576

7677
useEffect(() => {
7778
getStructure();
7879
}, []);
7980

81+
useEffect(() => {
82+
if (!dialog) {
83+
return;
84+
}
85+
const dialogClosed = () => {
86+
setUploadedFile(null);
87+
};
88+
89+
dialog.addEventListener('close', dialogClosed);
90+
return () => {
91+
dialog.removeEventListener('close', dialogClosed);
92+
};
93+
}, [dialog]);
94+
8095
async function getStructure() {
8196
const response = await fetch(`${baseUrl}structure/${realm}`);
8297
if (response.ok) {
@@ -114,27 +129,31 @@ export default function FileSelectDialog(props) {
114129
setUploadedFile(uploadedFiles[0]);
115130
}
116131

117-
return structure.root_folder && (<>
132+
return (<>
118133
<div className="wrapper" ref={ref}>
119-
<Menu
134+
{uploadedFile ?
135+
<BrowserEditor
136+
uploadedFile={uploadedFile}
137+
mainContent={ref.current}
138+
settings={{csrfToken, baseUrl, selectFile, labels: uploadedFile.labels}}
139+
/> : <>
140+
<MenuBar
120141
lastFolderId={structure.last_folder}
121142
fetchFiles={fetchFiles}
122143
openUploader={() => uploaderRef.current.openUploader()}
123144
/>
124145
<div className="browser-body">
125146
<nav className="folder-structure">
126-
<ul>
127-
<FolderStructure
147+
<ul role="navigation">
148+
{structure.root_folder && <FolderStructure
128149
baseUrl={baseUrl}
129150
folder={structure.root_folder}
130151
lastFolderId={structure.last_folder}
131152
fetchFiles={fetchFiles}
132153
refreshStructure={refreshStructure}
133-
/>
154+
/>}
134155
</ul>
135156
</nav>
136-
{uploadedFile ?
137-
<BrowserEditor uploadedFile={uploadedFile} mainContent={ref.current} /> :
138157
<FileUploader
139158
folderId={structure.last_folder}
140159
handleUpload={handleUpload}
@@ -144,8 +163,9 @@ export default function FileSelectDialog(props) {
144163
structure.files === null ?
145164
<div className="status">{gettext("Loading files…")}</div> :
146165
<FilesList files={structure.files} selectFile={selectFile} />
147-
}</FileUploader>}
166+
}</FileUploader>
148167
</div>
168+
</>}
149169
</div>
150170
<Tooltip id="django-finder-tooltip" place="bottom-start" />
151171
</>);

client/browser/FinderFileSelect.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export default function FinderFileSelect(props) {
4949

5050
function closeDialog() {
5151
dialogRef.current.close();
52+
dialogRef.current.dispatchEvent(new CustomEvent('close'));
5253
}
5354

5455
function deleteFile() {
@@ -99,9 +100,9 @@ export default function FinderFileSelect(props) {
99100
</div>
100101
<dialog ref={dialogRef}>
101102
<FileSelectDialog
103+
realm={props.realm}
102104
baseUrl={baseUrl}
103105
csrfToken={csrfToken}
104-
realm={props.realm}
105106
selectFile={selectFile}
106107
/>
107108
<div

client/browser/Menu.tsx

Lines changed: 0 additions & 91 deletions
This file was deleted.

0 commit comments

Comments
 (0)