Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Frontend modules #279

Merged
merged 239 commits into from
Feb 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
239 commits
Select commit Hold shift + click to select a range
db09718
Rearranged files to separate the new Vue/Typescript client from the o…
wyattis Sep 25, 2019
1ab414e
Started work on supporting file-based editing of Steps.
disperse Sep 26, 2019
1b45b27
Basic graph layout is working in Vue within proper separation of styles.
wyattis Oct 2, 2019
223242c
All basic client functionality is working. Notably, named slots in th…
wyattis Oct 4, 2019
523534b
Made todo list. Start working on Gremlins
wyattis Oct 4, 2019
8c2affe
Gremlins working with similar behavior to original
wyattis Oct 10, 2019
4387b3d
Added slots to easily extend choices, timers and the graph. Passing c…
wyattis Oct 10, 2019
0c99235
Added comments for automatic documentation generation. Changed placem…
wyattis Oct 17, 2019
74a262a
Added sendChoice method to Breadboard core to simplify correct messag…
wyattis Oct 22, 2019
6d7eaee
Added missing material design icons for Vuetify. Updated some slots. …
wyattis Oct 23, 2019
da5906f
update frontend TODO
wyattis Oct 23, 2019
2a738e3
Added simple EventBus interface to ScriptBoard and global CustomEvent…
wyattis Oct 28, 2019
4e78175
Merge pull request #201 from human-nature-lab/event-bus
wyattis Oct 28, 2019
87b1cdd
Added database schema changes for v2.4.0. Added file_mode field to ex…
disperse Nov 5, 2019
1a0abb4
Added update method to Admin to manually trigger admin client update.
disperse Nov 5, 2019
1fa1304
Added action to toggle file mode for the currently selected experimen…
disperse Nov 5, 2019
6947cbe
Instantiate FileWatcher when script engine is started.
disperse Nov 5, 2019
88c4947
Design console changes to toggle file mode, disable step editing when…
disperse Nov 5, 2019
355f364
Moved WatchService and Map of WatchKeys to FileWatcher. Removed comme…
disperse Nov 5, 2019
e8fa4a3
Improved file watcher sensitivity to reduce latency. Now reloading st…
disperse Nov 5, 2019
d598cbb
Now reading Customize dialog (Style, Client Graph, Client HTML) from …
disperse Nov 6, 2019
6d3fb10
Now loading client style from file when in fileMode and automatically…
disperse Nov 6, 2019
bea51a1
Changed direct access to parameters to getParameters method call in c…
disperse Nov 7, 2019
0f5517d
Now disabling the customize dialog Save button when fileMode = true
disperse Nov 11, 2019
05243ef
Now reading content from file and making content read only when file …
disperse Nov 12, 2019
6123e7d
Hide delete buttons and modified status marker when in readOnly mode.
disperse Nov 12, 2019
c12ba11
Fixed error on load before selectedContent is defined.
disperse Nov 12, 2019
8893049
Now ContentFetcher will fetch content from filesystem when fileMode =…
disperse Nov 12, 2019
03a04b7
Fixed up the EventBus to add one-way, player scoped event handing in …
wyattis Nov 14, 2019
df44239
Added groovy -> client event interface. Can now send messages directl…
wyattis Nov 15, 2019
d2879f7
Removed automatic webpack server from play framework. Added configura…
wyattis Nov 25, 2019
3a27f5d
Updated dev info in the contributing guide
wyattis Nov 25, 2019
65d781c
Fixed an issue where a .DS_Store or similar file inside the dev/exper…
disperse Nov 26, 2019
2203e89
Made the EventBus thread-safe
wyattis Nov 26, 2019
0e30783
Fixed up vertex overload methods for EventBus
wyattis Nov 26, 2019
52b9850
Added tutorial backend/frontend components to assist with display and…
wyattis Nov 26, 2019
f4ea261
Added confirmation dialog when toggling file mode on / off
disperse Dec 4, 2019
81de3fe
Fixed issue where toggling file mode was not updating steps.
disperse Dec 4, 2019
1587123
Moved version number to application.conf
disperse Dec 4, 2019
2be8bb5
Now copying experiment from database to dev directory when toggling f…
disperse Dec 4, 2019
effece1
Now sorting EventData by name to keep order consistent in output files.
disperse Dec 4, 2019
134605f
Fixed some bugs with the chat. Rolled back some accidental changes.
wyattis Dec 5, 2019
bac55bb
EventBus might actually be threadsafe now. Fixed bug in client core p…
wyattis Dec 5, 2019
d5bd163
Fixed issue where client graph and client html were not being served …
disperse Dec 10, 2019
fa09329
Tutorial can now handle the readyUp sequence in a customizable fashion.
wyattis Dec 13, 2019
c807b87
Removed some debug statements and added chat event recording
wyattis Dec 13, 2019
5fdc822
Updated chat types and allow renaming of the chat property on the node
wyattis Dec 17, 2019
b34bc84
Added debug logging statements for loading groovy scripts. Added tuto…
wyattis Dec 17, 2019
96fb99f
Added arrows to buttons in tutorial
wyattis Dec 17, 2019
256fe9e
Allow extending the core Vue instance by passing in a mixin object. E…
wyattis Dec 17, 2019
e8ef2c8
Fixed issue where warning when turning on/off file mode was displayin…
disperse Dec 17, 2019
edc4f41
Fixed issue where fileMode was eing returned as false incorrectly. No…
disperse Dec 17, 2019
d394f00
Now importing experiment from file when toggling file mode off. Fixed…
disperse Dec 17, 2019
b0ffa1f
Fixed issue where modifying steps in file mode would change the curre…
disperse Dec 18, 2019
b1351b3
Moved parameters dialog to its own directive. Now serving parameters …
disperse Dec 18, 2019
809f5cd
Added socket abstraction to handle reconnection and message queuing
wyattis Dec 18, 2019
f995a29
Added 'ready up' sequence to tutorial.
wyattis Dec 18, 2019
6511972
Disconnecting clients when the script engine reloads. Added Connectio…
wyattis Dec 18, 2019
1389aed
Added backwards compatibility with legacy angular client
wyattis Dec 19, 2019
09f0ee5
Wrote ParametersController to handle creating and deleting parameters…
disperse Dec 19, 2019
ffb64b2
Added route for retrieving image by filename and experiment ID. Now c…
disperse Dec 20, 2019
7d99a9c
Moved image dialog to its own directive. Moved server-side code to Im…
disperse Dec 20, 2019
7d161ef
upgrade dependency
wyattis Dec 20, 2019
00c2f25
Added crossword component
wyattis Dec 20, 2019
5398685
updated chat styles
wyattis Dec 20, 2019
165436a
Added a few base styles to client
wyattis Dec 20, 2019
5e64740
Now allow result closure to be omitted for a choice where no result i…
disperse Jan 2, 2020
34f9b20
Fixed incorrect handling of websocket in Firefox
wyattis Jan 2, 2020
2c47089
Now getting selection in script window using CodeMirror's getSelectio…
disperse Jan 2, 2020
93a24a9
On successful HIT creation save form to localStorage. Implements #183
disperse Jan 2, 2020
81ef07b
Basic structure of breadboard forms
wyattis Jan 3, 2020
80509e0
Updated graph algorithms to take an optional map of options to determ…
disperse Jan 3, 2020
69d6bde
Append experiment ID to downloaded event CSV to prevent name collisio…
disperse Jan 3, 2020
e6b160f
Changed tab fonts from 1.1em to 0.9em to make tabs smaller. Fixes #76
disperse Jan 3, 2020
e50b53b
Moved a bunch of logger messages from info to debug. Fixes #173
disperse Jan 3, 2020
9b78a57
Added confirmation box when posting HIT to AMT in production mode. Fi…
disperse Jan 3, 2020
c468838
Added Clear Form button to the Create HIT form to clear local storage…
disperse Jan 3, 2020
b72268a
Added Refresh assignments button to Manage HITs component. Implements…
disperse Jan 3, 2020
7ba7114
Add basic forms functionality. Basic html, choice, scale and text que…
wyattis Jan 10, 2020
3a86854
Update Vuetify. Removed unecessary socket lifecycle logging. Reduced …
wyattis Jan 10, 2020
b9d754e
Added _system variable to nodes on join. Added ready up sequence class.
wyattis Jan 13, 2020
c68d222
Added scoring support for form questions. Added simple randomized sub…
wyattis Jan 15, 2020
522dfe6
Added frontend validation rules and error messages for 'required' que…
wyattis Jan 15, 2020
3d35488
Added BBTimer class with timer management so that timers can be clean…
wyattis Jan 21, 2020
090f7a1
Removed old content fetching code in favor of BreadboardBase class
wyattis Jan 21, 2020
1a8a862
Changed timer name to SharedTimer. Removed tutorial class. Moved some…
wyattis Jan 22, 2020
1b3e0f9
Added several docstrings. Updated ready up sequence to use the Shared…
wyattis Jan 22, 2020
e9ea33c
Modified client form to hide stepper and previous button for single p…
wyattis Jan 22, 2020
4fed5c9
Some crossword changes
wyattis Jan 23, 2020
e8a7480
Updated form stepper to start from 1 instead of 0
wyattis Jan 23, 2020
63fe723
Removed old client-graph.js exclusion
wyattis Jan 23, 2020
df27183
Fixed assets root in production build
wyattis Jan 23, 2020
941b8a3
Added ability to remove players from shared timers
wyattis Jan 24, 2020
bfc0669
Saving any final data before component is destroyed in crossword
wyattis Jan 24, 2020
ac68683
Updated strategy for scoring forms
wyattis Jan 24, 2020
202a257
Deleted TODO.
wyattis Jan 24, 2020
5caedba
Resolved conflicts
wyattis Jan 24, 2020
87db9f1
Merge branch '2.4-merged' into v2.4
wyattis Jan 24, 2020
c13b1b6
Fixed default assets root for client view
wyattis Jan 24, 2020
a3a5942
Client correctly handles 'assetsRoot' parameter
wyattis Jan 27, 2020
8f88cb8
Added crossword input support for backspace/del and HOME/END. Fixed l…
wyattis Jan 27, 2020
44e1db1
Fixed randomization bug by dereferencing arrays. Removed unused deps …
wyattis Jan 27, 2020
616c573
Now tracking SharedTimers so they can be exposed to the admins. Added…
wyattis Jan 28, 2020
8e45d34
Added some more utility CSS classes
wyattis Jan 28, 2020
b258aa4
Removed unnecessary debugging statement. Fixed experiment import.
wyattis Jan 31, 2020
6d51b9a
Converted existing Timer usages into BBTimer and made g.addTimer use …
wyattis Jan 31, 2020
74a7d00
Fixed a bug with chat when hiding respondents. Fixed some sizing issu…
wyattis Jan 31, 2020
b3716e0
Added client side interpolation for the timers. This creates smooth b…
wyattis Jan 31, 2020
45de320
Sort timers by 'order' prop. Closes #195. Added an empty chat message…
wyattis Jan 31, 2020
062e8bf
Preventing untrusted clicks to choices and the graph in Vue client. C…
wyattis Jan 31, 2020
d803c6d
Loading steps in alphabetical order. Closes #211.
wyattis Feb 3, 2020
1a3365a
Emitting socket errors from the Breadboard global as well
wyattis Feb 10, 2020
4c2f947
Added a time to the reconnection message.
wyattis Feb 10, 2020
b56276a
Added fractional width/height classes
wyattis Feb 10, 2020
e2cab17
Removed duplicate classes. Cleaning up socket and disconnecting corre…
wyattis Feb 10, 2020
007cb0d
Updated BreadboardCrossword classes
wyattis Feb 10, 2020
6319d62
Validating clientId for breadboard events to prevent impersonation. A…
wyattis Feb 10, 2020
7231c60
Added slots for client text component
wyattis Feb 10, 2020
daf0536
Passing client info to the groovy engine along with event data
wyattis Feb 10, 2020
2002362
Added ConnectionStatus component to default template
wyattis Feb 10, 2020
e2542a5
Add support for disabling choice questions and input type for text qu…
wyattis Feb 11, 2020
0f19228
Added support for efficient loading of forms.
wyattis Feb 11, 2020
b2827f0
remove unused space from default components
wyattis Feb 11, 2020
bf2f3fb
support importing 2.4 version as well
wyattis Feb 11, 2020
30b9c4d
Fixed order issue when storing results of randomized scale questions …
wyattis Feb 18, 2020
d966909
Made fileMode work with experiments that lack images and content
wyattis Feb 20, 2020
bb07803
Reset socket wait time once a connection is made successfully. Change…
wyattis Feb 24, 2020
533a51a
Removed 'synchronized' blocks from EventBus and changed synchronizati…
wyattis Feb 24, 2020
5a28b46
Changed global 'timers' name
wyattis Feb 24, 2020
72d430f
Fixed default styles to better align with tailwindcss conventions
wyattis Feb 24, 2020
9f82435
Form no longer fetching data when not in 'efficient' mode. Socket rec…
wyattis Feb 25, 2020
8d10ae0
Changed order of constructor options to fix error
wyattis Feb 25, 2020
6b668e0
Fixed concurrency bug in shared timers. Improved memory and processin…
wyattis Mar 1, 2020
7c87ad7
moved chat into a modal. Fixed up some styles with chat, and other cl…
wyattis Mar 3, 2020
bd759d9
Functional Vue instance for the players dialog
wyattis Mar 3, 2020
903e67a
Added support for simple filter expressions
wyattis Mar 3, 2020
5b08d1b
Added vue-json-pretty for viewing player data
wyattis Mar 3, 2020
9fb264e
Now syncing with graph correctly
wyattis Mar 3, 2020
ded4cd8
Added 'like' operator with '~'
wyattis Mar 4, 2020
2293437
Sending edge prop changes to admins in a way that can be queried by c…
wyattis Mar 9, 2020
e60b319
Updated crossword clues to allow fake unlocking. Added blacklist prop…
wyattis Mar 10, 2020
499be98
Added pause/resume methods to SharedTimer class
wyattis Mar 13, 2020
24d51d2
Handling paused timers with client-side interpolation now
wyattis Mar 13, 2020
5f944ee
Added support for clicking player choices in new players dialog
wyattis Mar 13, 2020
99bf1b1
Removed dead code. Updated crossword components to fix practice view.
wyattis Mar 13, 2020
600c72d
Upgrade vue and vuetify versions
wyattis Aug 6, 2020
a7d26f5
Add .once method to the Breadboard EventBus
wyattis Aug 6, 2020
f2c8d65
Add a slot to the Chat
wyattis Sep 4, 2020
6428b2e
fix `vertex.once` method so that closures are removed properly after …
wyattis Sep 14, 2020
b809def
added llpg components. fixed bugs
wyattis Sep 23, 2020
c862e1e
functioning llpg
wyattis Oct 5, 2020
2740146
updates for llpg
wyattis Oct 20, 2020
092b199
use equidistant layout
wyattis Oct 21, 2020
e32ce7c
fix player layout. Add hover effects. Add growing animation.
wyattis Oct 22, 2020
aca2c6e
fix things
wyattis Oct 22, 2020
8327d32
Reset wallet to 0 when starting round
wyattis Oct 23, 2020
d570536
delay wallet money increase and hide box money once it opens
wyattis Oct 26, 2020
366bc94
removed end of game modal
wyattis Nov 23, 2020
2c40206
changed API for drag and drop
wyattis Nov 23, 2020
99579d3
Preload images. Other UI updates.
wyattis Dec 1, 2020
c237240
Fix concurrent modification error when removing event listeners
wyattis Dec 1, 2020
cf695fa
fixing bugs
wyattis Dec 1, 2020
db03a54
fix double counting of money in wallet
wyattis Dec 1, 2020
3c6b3d0
missing change
wyattis Dec 1, 2020
9a918a3
fix dragging issues
wyattis Dec 2, 2020
76dfa2a
fix up dragging. change layout for mobile
wyattis Dec 3, 2020
ff87912
allow admin to continue game with inactive players
wyattis Dec 9, 2020
6037132
remove 0's from transition page
wyattis Dec 9, 2020
bd96191
Fix hanging delays during wallet transitions. Show envelope when the …
wyattis Dec 9, 2020
6112702
slight changes
wyattis Dec 9, 2020
5fcea8f
better emulate breadboard 2.3 behavior with custom actions by sending…
wyattis Dec 17, 2020
80406e3
move custom params logic into core Breadboard lib
wyattis Dec 18, 2020
e9f0d49
remove automatic loading of game components
wyattis Feb 23, 2021
f0ea734
move game specific JS to modules
wyattis Feb 23, 2021
675e4ce
move frontend code into modules. Add practice step to llpg
wyattis Feb 24, 2021
deefccd
open/closed wallet. Fixed arrows and practice layout on tablet
wyattis Feb 25, 2021
7a75b7d
fix issues caused by alignment updates
wyattis Feb 25, 2021
aef6342
fix large group layout
wyattis Feb 25, 2021
1e66565
modify webpack and dependencies to move everything offline
wyattis Mar 24, 2021
7c39aa3
remove old webpack configs. fix chunks publicPath
wyattis Mar 24, 2021
10964ec
remove unnecessary change
wyattis Mar 24, 2021
590670f
fix overflow issue with admin screen
wyattis Apr 12, 2021
1956b8b
added static file serving from a directory outside of the bundle
wyattis May 18, 2021
bd5f2c1
fix build for angular
wyattis Jun 11, 2021
f3ae5c3
merge frontend docs changes from groovy-docs
wyattis Jun 15, 2021
2ff5a9b
Merge branch 'vue-groovy-merge' into vue-players
wyattis Jun 15, 2021
9b12278
fix build with llpg
wyattis Jun 17, 2021
f2b4220
add custom class for choices
wyattis Jul 16, 2021
b432345
update admin UI in llpg
wyattis Nov 11, 2021
e9de5b2
fix webpack build that broke for some unknown reason
wyattis Dec 1, 2021
a7ddc4a
update llpg to keep everything offline
wyattis Mar 23, 2022
2406d98
split frontend into independent modules
wyattis Mar 23, 2022
98c0373
separate libs are working
wyattis Mar 23, 2022
1cba6f3
client building as lib
wyattis Mar 24, 2022
74de5d2
patch core
wyattis Mar 24, 2022
950d9c5
make breadboard-client public
wyattis Mar 24, 2022
f790bc6
update exports and main in breadboard-client
wyattis Mar 24, 2022
8fcec59
update breadboard-client version
wyattis Mar 24, 2022
d714967
change ts target
wyattis Mar 24, 2022
3af934d
minor changes to import correctly
wyattis Mar 24, 2022
83ffee1
change output module
wyattis Mar 24, 2022
49dcfbc
don't assign to window by default
wyattis Mar 25, 2022
a0b7869
bump version
wyattis Mar 25, 2022
74722bc
update breadboard-core
wyattis Mar 25, 2022
120e56f
bump breadboard-client version
wyattis Mar 25, 2022
1009e3c
fix component dependencies
wyattis Apr 4, 2022
c855a97
breadboard-client v1.0.5
wyattis Apr 4, 2022
6099cff
export the Form component
wyattis Jul 15, 2022
3a9e866
v1.0.8
wyattis Jul 29, 2022
59516c1
change exports
wyattis Jul 29, 2022
17c7954
v1.0.9
wyattis Jul 29, 2022
31b8a4c
trying to fix build issues
wyattis Aug 11, 2022
cb4db43
core: v1.0.4
wyattis Aug 11, 2022
de39201
client: upgrade core and back package.json exports field
wyattis Aug 11, 2022
e32665b
client: v1.0.10
wyattis Aug 11, 2022
5c748c2
core: change target to es6
wyattis Aug 11, 2022
fe89d7e
client: v1.0.11 upgrade core
wyattis Aug 11, 2022
9eec4fb
client: try to include type declarations as well
wyattis Aug 15, 2022
13e21cb
client: v1.0.12
wyattis Aug 15, 2022
3768b9e
client: v1.0.13 upgrade vuetify
wyattis Aug 15, 2022
ee9c331
client: pass through attributes and listeners
wyattis Aug 15, 2022
4ee8574
client: v1.0.14
wyattis Aug 15, 2022
96c5c52
client: remove container components
wyattis Aug 15, 2022
485b185
core: v1.0.5
wyattis Aug 15, 2022
914bb64
core: v1.0.6 simplify choice slots
wyattis Aug 15, 2022
501566e
client: change styles some more and remove needless v-binds
wyattis Aug 16, 2022
744e8c3
client: v1.0.15
wyattis Aug 16, 2022
16aa625
client: fix regression
wyattis Aug 16, 2022
feeb9ea
client: v1.0.16
wyattis Aug 16, 2022
7adf4f5
client: v1.0.17
wyattis Aug 16, 2022
a89bb5b
client: v1.0.18
wyattis Aug 17, 2022
6218a36
add npm info
wyattis Aug 17, 2022
6837b80
don't automatically connect with socket
wyattis Dec 16, 2022
a126df7
version v1.0.7
wyattis Dec 16, 2022
f426dd3
client: update core dependency
wyattis Dec 16, 2022
acfd1f3
client: version v1.0.19
wyattis Dec 16, 2022
89976eb
client: don't import Breadboard directly
wyattis Dec 16, 2022
4082ff1
client: version v1.0.20
wyattis Dec 16, 2022
76220d0
Merge branch 'master' into frontend-modules
wyattis Feb 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ docs
logo
logs
db
dev
project/project
project/target
conf/generated.keystore
Expand All @@ -30,6 +31,8 @@ experiments
dev.bat
dev.sh
node_modules
client-graph.js
client-html.html
csv

.vscode
generated
33 changes: 33 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Contributing
There are many different ways to contribute to the Breadboard project. We welcome issues, code, documentation
and examples.

## Development

### Environment setup
Breadboard works with Java 7+. Make sure the Java SDK is installed before beginning development.

- `cd frontend`
- `npm install`

### Running
#### Backend development
If modifications will be made to files in the **frontend** directory, use the frontend development instructions instead
- Start the play framework server using `sbt "run -Dconfig.file=conf/application-prod.conf"`

#### Frontend development
This uses a slightly different configuration to allow hot module replacement via webpack on frontend files.
- Start the webpack server using `cd frontend && npm start`
- Start the play framework server using `sbt "run -Dconfig.file=conf/application-dev.conf"`


From a terminal run . This will start a dev server which will
automatically rebuild the frontend files whenever a file changes.


## Production

### Compile jars
- `cd frontend && npm run build` to build frontend assets if this code has changed
- `sh create_prod_dist.sh` to compile distributable files
- In many cases, only copying the compiled **breadboard.jar** file is enough to update existing Breadboard applications.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ breadboard is built using:
* [CodeMirror](https://codemirror.net/)

Also [Apache Commons](https://commons.apache.org/), [imgscalr](https://github.com/thebuzzmedia/imgscalr), [JUNG](http://jung.sourceforge.net/), [jQuery](https://jquery.com/), [Modernizr](https://modernizr.com/), [Underscore](http://underscorejs.org/), and [Bootstrap](http://getbootstrap.com/).

### Contributing
See the [contributing guide](CONTRIBUTING.md)
37 changes: 19 additions & 18 deletions app/Global.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ public void onStart(Application app) {
SqlRow versionTableCount = Ebean.createSqlQuery(sql).findUnique();
String count = versionTableCount.getString("table_count");

// If the breadboard_version table doesn't exist we're < v2.3
if (count.equals("0")) {

// Create the breadboard_version table
sql = "create table breadboard_version ( version varchar(255) ); ";
Ebean.createSqlUpdate(sql).execute();
// Update the version
sql = "insert into breadboard_version values ('v2.3.1'); ";
String version = play.Play.application().configuration().getString("application.version");
sql = "insert into breadboard_version values ('" + version + "'); ";
Ebean.createSqlUpdate(sql).execute();

// Create the languages table
Expand Down Expand Up @@ -155,25 +157,24 @@ public void onStart(Application app) {
// TODO: Add message telling user what was done
// TODO: Load v2.3 version notes as message from file system

// Upgrade to version 2.4.0
version2Point4Upgrade();
} else {
// The breadboard_version table exists, let's check if we're v2.3 or v2.4
sql = "select version from breadboard_version limit 1;";
SqlRow versionString = Ebean.createSqlQuery(sql).findUnique();
String version = versionString != null ? versionString.getString("version") : "";
if (version.equals("v2.3.0") || version.equals("v2.3.1")) {
// Add v2.4.0 fields
version2Point4Upgrade();
} // Otherwise, no upgrade needed
}
}

//InitialData.insert(app);
boolean isWin = System.getProperty("os.name").toUpperCase().indexOf("WIN") >= 0;
String cwd = System.getProperty("user.dir");
// TODO: If omitted, this should default to PROD
String mode = play.Play.application().configuration().getString("application.mode");
if(mode.toUpperCase().equals("DEV")) {
// Try to start the assets server
try {
ProcessBuilder pb = new ProcessBuilder("node", cwd + "/frontend/webpack/webpack.server.js");
pb.directory(new File(cwd + "/frontend"));
pb.inheritIO();
process = pb.start();
} catch (Exception e) {
e.printStackTrace();
}
}
// TODO: We could build the production resources when the framework starts instead of having to build them manually
private void version2Point4Upgrade() {
// Changes to support Experiment fileMode
String sql = "alter table experiments add column if not exists file_mode bit default 0;";
Ebean.createSqlUpdate(sql).execute();
}

@Override
Expand Down
106 changes: 106 additions & 0 deletions app/actors/FileWatcherActor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package actors;

import actors.FileWatcherActorProtocol.FileWatch;
import akka.actor.UntypedActor;
import models.Admin;
import models.FileWatcher;
import org.apache.commons.io.FileUtils;
import play.Logger;

import java.io.IOException;
import java.nio.file.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;

public class FileWatcherActor extends UntypedActor {
private static DateFormat dateFormat;

public FileWatcherActor() {
dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}


@Override
public void onReceive(Object message) {
if (message instanceof FileWatch) {
FileWatcher fileWatcher = ((FileWatch) message).fileWatcher;

// If fileMode for the selected experiment is false, do nothing
/* TODO: if there are multiple admins listening, they could each be watching different experiments which is weird in the context of a single file watcher */
// if ( fileWatcher.getAdminListeners().isEmpty() || fileWatcher.getAdminListeners().get(0).getUser().selectedExperiment == null || (! fileWatcher.getAdminListeners().get(0).getUser().selectedExperiment.getFileMode()) ) {
// return;
//}
fileWatcher.incrementUpdateIteration();
Long updateIteration = fileWatcher.getUpdateIteration();
if (updateIteration % 100 == 0) {
Logger.debug(dateFormat.format(new Date()) + " - FileWatch:" + updateIteration);
}

WatchKey watchKey;
boolean changed = false;
watchKey = fileWatcher.getWatcher().poll();
if (watchKey == null) {
return;
}

Path dir = fileWatcher.getWatchKeys().get(watchKey);
if (dir == null) {
Logger.error("Event triggered from watchKey not registered properly.");
return;
}

for (WatchEvent<?> event: watchKey.pollEvents()) {
WatchEvent<Path> ev = (WatchEvent<Path>) event;
Path name = ev.context();
Path child = dir.resolve(name);
Logger.debug(child.toString());
String selectedExperimentDirectory = (fileWatcher.getAdminListeners().get(0).getUser().selectedExperiment == null) ? "" : fileWatcher.getAdminListeners().get(0).getUser().selectedExperiment.getDirectoryName();
boolean selectedExperimentChanged = child.toString().contains(selectedExperimentDirectory);

if (ev.kind() == ENTRY_CREATE && child.toFile().isDirectory()) {
// new directory, need to watch it
try {
fileWatcher.registerRecursive(child);
} catch (IOException ioe) {
Logger.error("Unable to watch directory " + child.toFile().getPath() + " check the permissions.");
}
Logger.debug("DIRECTORY ENTRY_CREATE");
} else if ((ev.kind() == ENTRY_CREATE || ev.kind() == ENTRY_MODIFY) && child.toFile().isFile() && selectedExperimentChanged) {
// A file was modified or created in the selected experiment directory, update the admin
changed = true;
if (child.toFile().getParent().endsWith("/Steps")) {
// Step was modified or created, send to ScriptEngine
try {
String stepContents = FileUtils.readFileToString(child.toFile());
fileWatcher.loadStep(stepContents, fileWatcher.getAdminListeners().get(0).getOut(), child.getFileName().toString());
} catch (IOException ioe) {
Logger.error("Unable to read contents of Step " + child.getFileName().toString() + " check your permissions.");
}
}
Logger.debug("FILE ENTRY_MODIFY || ENTRY_CREATE");
} else if (ev.kind() == ENTRY_DELETE) {
Logger.debug("ENTRY_DELETE");
}
}

if (changed) {
// Something was changed, let's update all admin listeners
for(Admin a : fileWatcher.getAdminListeners()) {
a.update();
}
}

boolean valid = watchKey.reset();
if (!valid) {
fileWatcher.getWatchKeys().remove(watchKey);
Logger.debug("Watched directory was deleted.");
}
}
}
}

13 changes: 13 additions & 0 deletions app/actors/FileWatcherActorProtocol.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package actors;

import models.FileWatcher;

public class FileWatcherActorProtocol {
public static class FileWatch {
final FileWatcher fileWatcher;
public FileWatch(FileWatcher fileWatcher) {
this.fileWatcher = fileWatcher;
}
}
}

85 changes: 5 additions & 80 deletions app/controllers/Application.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
package controllers;

import models.*;
import org.apache.commons.io.FileUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.mindrot.jbcrypt.BCrypt;
import play.Logger;
import play.data.Form;
import play.libs.Json;
import play.mvc.*;
import play.mvc.Http.MultipartFormData;
import play.mvc.Http.MultipartFormData.FilePart;
import views.html.*;
import java.io.*;
import java.text.SimpleDateFormat;
Expand Down Expand Up @@ -84,7 +81,7 @@ public static Result authenticate() {
User user = User.findByEmail(email);

if (user != null) {
Logger.info("authenticate: uid = " + uid);
Logger.debug("authenticate: uid = " + uid);
user.uid = uid;
user.update();
result = Json.newObject();
Expand All @@ -103,9 +100,10 @@ public static Result logout() {
return unauthorized();
}

public static Result index() {
final File file = play.Play.application().getFile("assets/templates/breadboard.html");
return ok(file, true);
public static Result index () {
// final File file = play.Play.application().getFile("assets/templates/breadboard.html");
String assetsRoot = play.Play.application().configuration().getString("breadboard.assetsRoot", "/assets");
return ok(main.render(assetsRoot));
}

@Security.Authenticated(Secured.class)
Expand All @@ -115,82 +113,9 @@ public static Result getState() {
result.put("juid", session("juid"));
result.put("email", session("email"));
result.put("connectSocket", play.Play.application().configuration().getString("breadboard.wsUrl"));
result.put("imageUploadRoute", routes.Application.uploadImage().toString());
return ok(result);
}

@Security.Authenticated(Secured.class)
public static Result uploadImage() {
MultipartFormData body = request().body().asMultipartFormData();
FilePart picture = body.getFile("picture");
if (picture != null) {
String fileName = picture.getFilename();
String contentType = picture.getContentType();
File file = picture.getFile();

Map<String, String[]> values = body.asFormUrlEncoded();

try {
String experimentId = values.get("experimentId")[0];
Long eid = Long.parseLong(experimentId);
Experiment experiment = Experiment.findById(eid);
Image image = new Image();
image.fileName = fileName;
image.file = FileUtils.readFileToByteArray(file);
image.contentType = contentType;
experiment.images.add(image);
experiment.save();
} catch (NullPointerException npe) {
Logger.error("IOException in uploadImage(): " + npe.getMessage());
return ok("Error uploading");
} catch (NumberFormatException nfe) {
Logger.error("IOException in uploadImage(): " + nfe.getMessage());
return ok("Error uploading");
} catch (IOException ioe) {
Logger.error("IOException in uploadImage(): " + ioe.getMessage());
return ok("Error uploading");
}


//TODO: For web deployment consider storing images to filesystem
//Integer nextId = (Integer)Ebean.nextId(Image.class);
//String uniqueFileName = nextId.toString() + "_" + fileName;
//Logger.info("uniquefileName = " + uniqueFileName);
//String uploadPath = "";


return ok("File uploaded");
} else {
return ok("Error uploading");
}
}

public static Result getImage(Long imageId) {
Image image = Image.findById(imageId);

if (image != null) {
if (image.contentType != null && image.file != null) {
response().setContentType(image.contentType);
return ok(image.file);
}
}

return notFound();
}

public static Result getImageThumb(Long imageId) {
Image image = Image.findById(imageId);

if (image != null) {
if (image.contentType != null && image.thumbFile != null && image.thumbFile.length > 0) {
response().setContentType(image.contentType);
return ok(image.thumbFile);
}
}

return notFound();
}

@Security.Authenticated(Secured.class)
public static Result saveUserSettings() {
Form<UserSettings> userSettingsForm = Form.form(UserSettings.class);
Expand Down
Loading