Skip to content
This repository was archived by the owner on Mar 4, 2025. It is now read-only.

Commit b33e05a

Browse files
committed
webui: Add new React component for markdown editor and preview
Create a new React component to replace the old markdown editor and preview tabs using AngularJS code. Use the new component on the Create Branch page.
1 parent f100255 commit b33e05a

File tree

8 files changed

+204
-75
lines changed

8 files changed

+204
-75
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,4 @@ node_modules
5252
webui/js/dbhub.js*
5353
webui/js/auth.js
5454
webui/js/db-header.js
55+
webui/js/markdown-editor.js

cypress/e2e/1-webui/branches.cy.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ describe('branches', () => {
1111
cy.get('[data-cy="commitslnk"]').click()
1212
cy.get('[data-cy="createbranchbtn"]').click()
1313
cy.get('[data-cy="nameinput"]').type('{selectall}{backspace}').type('Some branch name').should('have.value', 'Some branch name')
14-
cy.get('[data-cy="desctext"]').type('{selectall}{backspace}').type('Some branch description').should('have.value', 'Some branch description')
15-
cy.get('[data-cy="previewtab"]').click()
16-
cy.get('[data-cy="previewdiv"]').should('contain', 'Some branch description')
14+
cy.get('[data-cy="branchdesc"]').type('{selectall}{backspace}').type('Some branch description').should('have.value', 'Some branch description')
15+
cy.get('[data-cy="branchdesc-preview-tab"]').click()
16+
cy.get('[data-cy="branchdesc-preview"]').should('contain', 'Some branch description')
1717
cy.get('[data-cy="createbtn"]').click()
1818
cy.visit('default/Assembly%20Election%202017.sqlite')
1919
cy.get('[data-cy="branchescnt"]').should('contain', '2')

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"cypress": "^12.3.0",
66
"react": "^18.2.0",
77
"react-dom": "^18.2.0",
8+
"react-tabs": "^6.0.0",
89
"yarn": "^1.22.19"
910
},
1011
"name": "dbhub.io",

webui/css/local.css

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,62 @@ textarea {
181181
width: 100%;
182182
padding: 6px;
183183
}
184+
185+
/***************
186+
* React-Tabs
187+
***************/
188+
189+
.react-tabs {
190+
-webkit-tap-highlight-color: transparent;
191+
}
192+
193+
.react-tabs__tab-list {
194+
border-bottom: 1px solid #aaa;
195+
margin: 0 0 10px;
196+
padding: 0;
197+
}
198+
199+
.react-tabs__tab {
200+
display: inline-block;
201+
border: 1px solid transparent;
202+
border-bottom: none;
203+
bottom: -1px;
204+
position: relative;
205+
list-style: none;
206+
padding: 6px 12px;
207+
cursor: pointer;
208+
}
209+
210+
.react-tabs__tab--selected {
211+
background: #fff;
212+
border-color: #aaa;
213+
color: black;
214+
border-radius: 5px 5px 0 0;
215+
}
216+
217+
.react-tabs__tab--disabled {
218+
color: GrayText;
219+
cursor: default;
220+
}
221+
222+
.react-tabs__tab:focus {
223+
outline: none;
224+
}
225+
226+
.react-tabs__tab:focus:after {
227+
content: '';
228+
position: absolute;
229+
height: 5px;
230+
left: -4px;
231+
right: -4px;
232+
bottom: -5px;
233+
background: #fff;
234+
}
235+
236+
.react-tabs__tab-panel {
237+
display: none;
238+
}
239+
240+
.react-tabs__tab-panel--selected {
241+
display: block;
242+
}

webui/js/app.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import ReactDOM from "react-dom/client";
33

44
import Auth from "./auth";
55
import DbHeader from "./db-header";
6+
import MarkdownEditor from "./markdown-editor";
67

78
{
89
const rootNode = document.getElementById("db-header-root");
@@ -19,3 +20,22 @@ import DbHeader from "./db-header";
1920
root.render(React.createElement(Auth));
2021
}
2122
}
23+
24+
{
25+
document.querySelectorAll('.markdown-editor').forEach((rootNode) => {
26+
const editorId = rootNode.dataset.id;
27+
const rows = rootNode.dataset.rows;
28+
const placeholder = rootNode.dataset.placeholder;
29+
const defaultIndex = rootNode.dataset.defaultIndex;
30+
const initialValue = rootNode.dataset.initialValue;
31+
32+
const root = ReactDOM.createRoot(rootNode);
33+
root.render(React.createElement(MarkdownEditor, {
34+
editorId: editorId,
35+
rows: rows,
36+
placeholder: placeholder,
37+
defaultIndex: defaultIndex,
38+
initialValue: initialValue
39+
}));
40+
});
41+
}

webui/jsx/markdown-editor.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
const React = require("react");
2+
const ReactDOM = require("react-dom");
3+
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
4+
5+
export default function MarkdownEditor({editorId, rows, placeholder, defaultIndex, initialValue}) {
6+
const [previewHtml, setPreviewHtml] = React.useState("");
7+
8+
if (rows === undefined) {
9+
rows = 10;
10+
}
11+
12+
if (defaultIndex === undefined) {
13+
defaultIndex = 0;
14+
}
15+
16+
function tabChanged(index) {
17+
// Preview tab selected?
18+
if (index === 1) {
19+
// Retrieve latest markdown text from the text area
20+
let txt = document.getElementById(editorId).value;
21+
22+
// Call the server, asking for a rendered version of the markdown
23+
fetch("/x/markdownpreview/", {
24+
method: "post",
25+
headers: {
26+
"Content-Type" : "application/x-www-form-urlencoded"
27+
},
28+
body: "mkdown=" + encodeURIComponent(txt)
29+
})
30+
.then((response) => response.text())
31+
.then((text) => {
32+
setPreviewHtml(text);
33+
});
34+
}
35+
}
36+
37+
return (
38+
<>
39+
<Tabs onSelect={(index) => tabChanged(index)} forceRenderTabPanel={true} defaultIndex={defaultIndex}>
40+
<TabList>
41+
<Tab data-cy={editorId + "-edit-tab"}>Edit</Tab>
42+
<Tab data-cy={editorId + "-preview-tab"}>Preview</Tab>
43+
</TabList>
44+
<TabPanel>
45+
<textarea id={editorId} name={editorId} rows={rows} placeholder={placeholder} data-cy={editorId}>
46+
{initialValue}
47+
</textarea>
48+
</TabPanel>
49+
<TabPanel>
50+
<div class="rendered minHeight" data-cy={editorId + "-preview"} dangerouslySetInnerHTML={{__html: previewHtml}} />
51+
</TabPanel>
52+
</Tabs>
53+
</>
54+
);
55+
}

webui/templates/createbranch.html

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,7 @@ <h2 style="text-align: center;" data-cy="createbranch">Create new branch</h2>
2525
<b>Branch description</b><br /><br />
2626
<i>Markdown (<a href="http://commonmark.org" target="_blank">CommonMark</a> format) is supported</i></td>
2727
<td>
28-
<div>
29-
<uib-tabset active="active">
30-
<uib-tab index="0" data-cy="edittab">
31-
<uib-tab-heading><span style="color: #555;">Edit</span></uib-tab-heading>
32-
<textarea id="branchdesc" name="branchdesc" rows="10" ng-attr-placeholder="A description for this branch" data-cy="desctext"></textarea>
33-
</uib-tab>
34-
<uib-tab index="1" select="getMarkdown()" data-cy="previewtab">
35-
<uib-tab-heading><span style="color: #555;">Preview</span></uib-tab-heading>
36-
<div class="rendered minHeight" ng-bind-html="markDownPreview" data-cy="previewdiv"></div>
37-
</uib-tab>
38-
</uib-tabset>
39-
</div>
28+
<div class="markdown-editor" data-id="branchdesc" data-rows="10" data-placeholder="A description for this branch" />
4029
</td>
4130
</tr>
4231
<tr>
@@ -61,20 +50,6 @@ <h2 style="text-align: center;" data-cy="createbranch">Create new branch</h2>
6150
<script>
6251
let app = angular.module('DBHub', ['ui.bootstrap', 'ngSanitize']);
6352
app.controller('createbranchView', function($scope, $http, $httpParamSerializerJQLike) {
64-
// Get rendered markdown from the server, for display in the Commit Message preview tab
65-
$scope.markDownPreview = "";
66-
$scope.getMarkdown = function() {
67-
// Retrieve latest markdown text from the text area
68-
let txt = document.getElementById("branchdesc").value;
69-
70-
// Call the server, asking for a rendered version of the markdown
71-
$http({
72-
method: "POST",
73-
url: "/x/markdownpreview/",
74-
data: $httpParamSerializerJQLike({"mkdown": encodeURIComponent(txt)}),
75-
headers: { "Content-Type" : "application/x-www-form-urlencoded" }
76-
}).then(function (response) { $scope.markDownPreview = response.data; });
77-
};
7853
});
7954
</script>
8055
</body>

0 commit comments

Comments
 (0)