Skip to content

Commit f251eb7

Browse files
author
merhoo
committed
finished preliminary web front-end for secrets
1 parent d9aa312 commit f251eb7

File tree

23 files changed

+617
-172
lines changed

23 files changed

+617
-172
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
backend/target/*
22
admin/target/*
33
backend/src/main/resources/*
4+
web/node_modules

web/app.css

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/* switch the default font for the body, and remove top/bottom/left/right margin */
2+
body {
3+
font-family: 'Fresca', sans-serif;
4+
margin: 0;
5+
}
6+
7+
/* font, color, and alignment for the titles of the three displayable regions */
8+
h3 {
9+
background-color: #DDD;
10+
font-size: 24pt;
11+
font-weight: bold;
12+
height: 42px;
13+
text-align: center;
14+
}
15+
16+
/* Make the button for adding a message hover in the top right */
17+
#showFormButton {
18+
position: absolute;
19+
top: 5px;
20+
right: 5px;
21+
}
22+
23+
/* The main screen table should have some space to the left */
24+
#messageList {
25+
margin-left: 15px;
26+
}
27+
28+
/* The table should be wider than it absolutely needs to be */
29+
table {
30+
width: 500px;
31+
}
32+
33+
/* alternate color of table rows */
34+
tr:nth-child(even) {background: #CCC}
35+
tr:nth-child(odd) {background: #888}
36+
37+
/* make table row height a bit bigger than necessary */
38+
tr {
39+
height: 15px;
40+
}
41+
42+
/* make the first column of the table wide */
43+
td:first-child {width: 75%;}
44+
45+
/* make the form elements wide, and force a line break after each */
46+
input, label, textarea {
47+
display: block;
48+
width: 200px;
49+
}
50+
51+
/* put some space between textareas and the buttons that follow them */
52+
textarea {
53+
margin-bottom: 5px;
54+
}
55+
56+
/* put some left space before form elements */
57+
label, input, textarea, #addButton, #editButton {
58+
margin-left: 15px;
59+
}
60+
61+
/* custom formatting for the span where we put the creation date */
62+
#editCreated {
63+
display: block;
64+
margin-bottom: 5px;
65+
margin-left: 15px;
66+
}

web/app.ts

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
// Prevent compiler errors when using jQuery. "$" will be given a type of
2+
// "any", so that we can use it anywhere, and assume it has any fields or
3+
// methods, without the compiler producing an error.
4+
var $: any;
5+
6+
// a global for the main ElementList of the program. See newEntryForm for
7+
// explanation
8+
var mainList: ElementList;
9+
10+
/**
11+
* ElementList provides a way of seeing all of the data stored on the server.
12+
*/
13+
class ElementList {
14+
/**
15+
* refresh is the public method for updating messageList
16+
*/
17+
refresh() {
18+
// Issue a GET, and then pass the result to update()
19+
$.ajax({
20+
type: "GET",
21+
url: "/messages",
22+
dataType: "json",
23+
success: mainList.update
24+
});
25+
}
26+
27+
/**
28+
* update is the private method used by refresh() to update messageList
29+
*/
30+
private update(data: any) {
31+
$("#messageList").html("<table>");
32+
for (let i = 0; i < data.mData.length; ++i) {
33+
$("#messageList").append("<tr><td>" + data.mData[i].mTitle +
34+
"</td>" + mainList.buttons(data.mData[i].mId) + "</tr>");
35+
}
36+
$("#messageList").append("</table>");
37+
// Find all of the delete buttons, and set their behavior
38+
$(".delbtn").click(mainList.clickDelete);
39+
// Find all of the Edit buttons, and set their behavior
40+
$(".editbtn").click(mainList.clickEdit);
41+
}
42+
43+
/**
44+
* buttons() adds a 'delete' button and an 'edit' button to the HTML for each
45+
* row
46+
*/
47+
private buttons(id: string): string {
48+
return "<td><button class='editbtn' data-value='" + id
49+
+ "'>Edit</button></td>"
50+
+ "<td><button class='delbtn' data-value='" + id
51+
+ "'>Delete</button></td>";
52+
}
53+
54+
/**
55+
* clickEdit is the code we run in response to a click of a delete button
56+
*/
57+
private clickEdit() {
58+
// as in clickDelete, we need the ID of the row
59+
let id = $(this).data("value");
60+
$.ajax({
61+
type: "GET",
62+
url: "/messages/" + id,
63+
dataType: "json",
64+
success: editEntryForm.init
65+
});
66+
}
67+
68+
/**
69+
* clickDelete is the code we run in response to a click of a delete button
70+
*/
71+
private clickDelete() {
72+
// TODO: check the response
73+
let id = $(this).data("value");
74+
$.ajax({
75+
type: "DELETE",
76+
url: "/messages/" + id,
77+
dataType: "json",
78+
// TODO: we should really have a function that looks at the return
79+
// value and possibly prints an error message.
80+
success: mainList.refresh
81+
})
82+
}
83+
} // end class ElementList
84+
85+
86+
// a global for the EditEntryForm of the program. See newEntryForm for
87+
// explanation
88+
var editEntryForm: EditEntryForm;
89+
90+
/**
91+
* EditEntryForm encapsulates all of the code for the form for editing an entry
92+
*/
93+
class EditEntryForm {
94+
/**
95+
* To initialize the object, we say what method of EditEntryForm should be
96+
* run in response to each of the form's buttons being clicked.
97+
*/
98+
constructor() {
99+
$("#editCancel").click(this.clearForm);
100+
$("#editButton").click(this.submitForm);
101+
}
102+
103+
/**
104+
* init() is called from an AJAX GET, and should populate the form if and
105+
* only if the GET did not have an error
106+
*/
107+
init(data: any) {
108+
if (data.mStatus === "ok") {
109+
$("#editTitle").val(data.mData.mTitle);
110+
$("#editMessage").val(data.mData.mContent);
111+
$("#editId").val(data.mData.mId);
112+
$("#editCreated").text(data.mData.mCreated);
113+
// show the edit form
114+
$("#addElement").hide();
115+
$("#editElement").show();
116+
$("#showElements").hide();
117+
}
118+
else if (data.mStatus === "error") {
119+
window.alert("Error: " + data.mMessage);
120+
}
121+
else {
122+
window.alert("An unspecified error occurred");
123+
}
124+
}
125+
126+
/**
127+
* Clear the form's input fields
128+
*/
129+
clearForm() {
130+
$("#editTitle").val("");
131+
$("#editMessage").val("");
132+
$("#editId").val("");
133+
$("#editCreated").text("");
134+
// reset the UI
135+
$("#addElement").hide();
136+
$("#editElement").hide();
137+
$("#showElements").show();
138+
}
139+
140+
/**
141+
* Check if the input fields are both valid, and if so, do an AJAX call.
142+
*/
143+
submitForm() {
144+
// get the values of the two fields, force them to be strings, and check
145+
// that neither is empty
146+
let title = "" + $("#editTitle").val();
147+
let msg = "" + $("#editMessage").val();
148+
// NB: we assume that the user didn't modify the value of #editId
149+
let id = "" + $("#editId").val();
150+
if (title === "" || msg === "") {
151+
window.alert("Error: title or message is not valid");
152+
return;
153+
}
154+
// set up an AJAX post. When the server replies, the result will go to
155+
// onSubmitResponse
156+
$.ajax({
157+
type: "PUT",
158+
url: "/messages/" + id,
159+
dataType: "json",
160+
data: JSON.stringify({ mTitle: title, mMessage: msg }),
161+
success: editEntryForm.onSubmitResponse
162+
});
163+
}
164+
165+
/**
166+
* onSubmitResponse runs when the AJAX call in submitForm() returns a
167+
* result.
168+
*
169+
* @param data The object returned by the server
170+
*/
171+
private onSubmitResponse(data: any) {
172+
// If we get an "ok" message, clear the form and refresh the main
173+
// listing of messages
174+
if (data.mStatus === "ok") {
175+
editEntryForm.clearForm();
176+
mainList.refresh();
177+
}
178+
// Handle explicit errors with a detailed popup message
179+
else if (data.mStatus === "error") {
180+
window.alert("The server replied with an error:\n" + data.mMessage);
181+
}
182+
// Handle other errors with a less-detailed popup message
183+
else {
184+
window.alert("Unspecified error");
185+
}
186+
}
187+
} // end class EditEntryForm
188+
189+
// The 'this' keyword does not behave in JavaScript/TypeScript like it does in
190+
// Java. Since there is only one NewEntryForm, we will save it to a global, so
191+
// that we can reference it from methods of the NewEntryForm in situations where
192+
// 'this' won't work correctly.
193+
var newEntryForm: NewEntryForm;
194+
195+
/**
196+
* NewEntryForm encapsulates all of the code for the form for adding an entry
197+
*/
198+
class NewEntryForm {
199+
/**
200+
* To initialize the object, we say what method of NewEntryForm should be
201+
* run in response to each of the form's buttons being clicked.
202+
*/
203+
constructor() {
204+
$("#addCancel").click(this.clearForm);
205+
$("#addButton").click(this.submitForm);
206+
}
207+
208+
/**
209+
* Clear the form's input fields
210+
*/
211+
clearForm() {
212+
$("#newTitle").val("");
213+
$("#newMessage").val("");
214+
}
215+
216+
/**
217+
* Check if the input fields are both valid, and if so, do an AJAX call.
218+
*/
219+
submitForm() {
220+
// get the values of the two fields, force them to be strings, and check
221+
// that neither is empty
222+
let title = "" + $("#newTitle").val();
223+
let msg = "" + $("#newMessage").val();
224+
if (title === "" || msg === "") {
225+
window.alert("Error: title or message is not valid");
226+
return;
227+
}
228+
// set up an AJAX post. When the server replies, the result will go to
229+
// onSubmitResponse
230+
$.ajax({
231+
type: "POST",
232+
url: "/messages",
233+
dataType: "json",
234+
data: JSON.stringify({ mTitle: title, mMessage: msg }),
235+
success: newEntryForm.onSubmitResponse
236+
});
237+
console.log("Sent.");
238+
mainList.refresh();
239+
}
240+
241+
/**
242+
* onSubmitResponse runs when the AJAX call in submitForm() returns a
243+
* result.
244+
*
245+
* @param data The object returned by the server
246+
*/
247+
private onSubmitResponse(data: any) {
248+
// If we get an "ok" message, clear the form
249+
if (data.mStatus === "ok") {
250+
newEntryForm.clearForm();
251+
mainList.refresh();
252+
}
253+
// Handle explicit errors with a detailed popup message
254+
else if (data.mStatus === "error") {
255+
window.alert("The server replied with an error:\n" + data.mMessage);
256+
}
257+
// Handle other errors with a less-detailed popup message
258+
else {
259+
window.alert("Unspecified error");
260+
}
261+
}
262+
} // end class NewEntryForm
263+
264+
// Run some configuration code when the web page loads
265+
$(document).ready(function () {
266+
// Create the object that controls the "New Entry" form
267+
newEntryForm = new NewEntryForm();
268+
// Create the object for the main data list, and populate it with data from
269+
// the server
270+
// Create the object that controls the "Edit Entry" form
271+
editEntryForm = new EditEntryForm();
272+
273+
mainList = new ElementList();
274+
mainList.refresh();
275+
276+
// set up initial UI state
277+
$("#editElement").hide();
278+
$("#addElement").hide();
279+
$("#showElements").show();
280+
281+
// set up the "Add Message" button
282+
$("#showFormButton").click(function () {
283+
$("#addElement").show();
284+
$("#showElements").hide();
285+
});
286+
});

web/deploy.sh

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ mkdir $TARGETFOLDER/$WEBFOLDERNAME
2020
# there are many more steps to be done. For now, we will just copy an HTML file
2121
cp -r * $TARGETFOLDER/$WEBFOLDERNAME
2222
rm $TARGETFOLDER/$WEBFOLDERNAME/deploy.sh
23-
rm -r $TARGETFOLDER/$WEBFOLDERNAME/exper
23+
# rm -r $TARGETFOLDER/$WEBFOLDERNAME/exper
24+
25+
# step 2: update our npm dependencies
26+
npm update
27+
28+
# step 3: copy javascript files
29+
cp node_modules/jquery/dist/jquery.min.js $TARGETFOLDER/$WEBFOLDERNAME
30+
31+
# step 4: compile TypeScript files
32+
node_modules/typescript/bin/tsc app.ts --strict --outFile $TARGETFOLDER/$WEBFOLDERNAME/app.js
33+
34+
# step 5: copy css files
35+
cp app.css $TARGETFOLDER/$WEBFOLDERNAME
2436

2537
echo fin

0 commit comments

Comments
 (0)