Port Backend to SQLite/Sequelize (removes MongoDB), Support Electron (#14)
* The MongoDB/Mongoose data storage is removed in favor of Sequelize. This abstracts over SQLite or RDBMs like PostgreSQL and MSSQL. The default is SQLite, which significantly simplifies deployments in end-user environments. * As Spacedeck now has no more mandatory server dependencies, we can wrap it in Electron and ship it as a desktop application. * Removes docker-compose.yml * First version of import UI
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<div id="team" class="dialog in" style="padding:100px;z-index:20000;position:absolute;width:100%;min-height:100%;background-color:#eee" v-if="active_view == 'account' && user" v-cloak>
|
||||
|
||||
<a href="/spaces" class="btn btn-round btn-icon btn-stroke-darken btn-md pull-right" style="position:absolute;top:30px;right:30px"><span class="icon icon-cross-0"></span></a>
|
||||
<a href="/spaces" class="btn btn-round btn-icon btn-dark btn-md pull-right" style="position:absolute;top:30px;right:30px"><span class="icon icon-cross-0"></span></a>
|
||||
|
||||
<div class="dialog-tabs" style="margin:auto">
|
||||
<div class="dialog-tab" v-bind:class="{open:account=='profile'}" v-on:click="account='profile'"><span>[[__("profile_caption")]]</span></div>
|
||||
@@ -80,21 +80,29 @@
|
||||
<span class="icon icon-check"></span> <span>[[__("confirmation_sent_another")]]</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="label">Spacedeck.com Data Import</label>
|
||||
<p v-if="!importables">No .ZIP files found in Spacedeck application folder.</p>
|
||||
<ul>
|
||||
<li v-for="f in importables">{{f}} <button v-on:click="start_zip_import(f)">Start Import</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="collapse" v-bind:class="{in:account=='language'}">
|
||||
<div class="modal-section">
|
||||
<label class="radio" v-bind:class="{checked
|
||||
: user.preferences.language=='en'}" v-on:click="save_user_language('en')">
|
||||
: user.prefs_language=='en'}" v-on:click="save_user_language('en')">
|
||||
<input type="radio" id="user-preferences_language" name="language" value="en"><span>English</span>
|
||||
</label>
|
||||
<hr/>
|
||||
<label class="radio" v-bind:class="{checked: user.preferences.language=='de'}" v-on:click="save_user_language('de')">
|
||||
<label class="radio" v-bind:class="{checked: user.prefs_language=='de'}" v-on:click="save_user_language('de')">
|
||||
<input type="radio" id="user-preferences_language" name="language" value="de"><span>Deutsch</span>
|
||||
</label>
|
||||
<hr/>
|
||||
<label class="radio" v-bind:class="{checked: user.preferences.language=='fr'}" v-on:click="save_user_language('fr')">
|
||||
<label class="radio" v-bind:class="{checked: user.prefs_language=='fr'}" v-on:click="save_user_language('fr')">
|
||||
<input type="radio" id="user-preferences_language" name="language" value="fr"><span>Français</span>
|
||||
</label>
|
||||
</div>
|
||||
@@ -104,8 +112,8 @@
|
||||
<div class="modal-section labels-inline">
|
||||
<div class="form-group">
|
||||
<label class="checkbox"
|
||||
v-bind:class="{checked: user.preferences.email_notifications}"
|
||||
v-on:click="account_save_user_notifications(!user.preferences.email_notifications);">
|
||||
v-bind:class="{checked: user.prefs_email_notifications}"
|
||||
v-on:click="account_save_user_notifications(!user.prefs_email_notifications);">
|
||||
<span>[[__('notifications_option_chat')]]</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<div id="space" class="section board active mouse-{{mouse_state}} tool-{{active_tool}}">
|
||||
|
||||
<div class="space-bounds" style="width:{{active_space.advanced.width*bounds_zoom}}px;height:{{active_space.advanced.height*bounds_zoom}}px;"></div>
|
||||
<div class="space-bounds" style="width:{{active_space.width*bounds_zoom}}px;height:{{active_space.height*bounds_zoom}}px;"></div>
|
||||
|
||||
<div class="wrapper"
|
||||
style="transform:scale({{viewport_zoom}});transform-origin:0 0;width:{{active_space.advanced.width}}px;height:{{active_space.advanced.height}}px;background-image:url('{{active_space.advanced.background_uri}}');background-color:{{active_space.advanced.background_color}};margin-left:{{bounds_margin_horiz}}px;margin-top:{{bounds_margin_vert}}px" >
|
||||
style="transform:scale({{viewport_zoom}});transform-origin:0 0;width:{{active_space.width}}px;height:{{active_space.height}}px;background-image:url('{{active_space.background_uri}}');background-color:{{active_space.background_color}};margin-left:{{bounds_margin_horiz}}px;margin-top:{{bounds_margin_vert}}px" >
|
||||
|
||||
<div v-repeat="a : active_space_artifacts"
|
||||
v-class="text-editing:(editing_artifact_id==a._id && (a.view.major_type=='text' || a.view.major_type=='shape'))"
|
||||
@@ -81,7 +81,7 @@
|
||||
</div>
|
||||
|
||||
<div class="tl-controls">
|
||||
<div class="btn btn-md btn-toggle btn-round" v-class="alt:a.player_view.state=='playing'" v-show="a.board.w>=200 || a.player_view.state!='playing'">
|
||||
<div class="btn btn-md btn-toggle btn-round" v-class="alt:a.player_view.state=='playing'" v-show="a.w>=200 || a.player_view.state!='playing'">
|
||||
<span class="btn-option play">
|
||||
<span class="icon icon-controls-play"></span>
|
||||
</span>
|
||||
@@ -95,8 +95,8 @@
|
||||
<span class="icon icon-controls-stop"></span>
|
||||
</span>
|
||||
|
||||
<span class="tl-title" v-show="a.board.w>=250 && a.board.h>=150">{{a.view.filename}}</span>
|
||||
<span class="tl-times" class="btn-group" v-show="a.board.w>=400 && a.board.h>=150">
|
||||
<span class="tl-title" v-show="a.w>=250 && a.h>=150">{{a.view.filename}}</span>
|
||||
<span class="tl-times" class="btn-group" v-show="a.w>=400 && a.h>=150">
|
||||
<span class="btn btn-md btn-transparent no-p set-inpoint">{{a.player_view.current_time_string}} /</span>
|
||||
<span class="btn btn-md btn-transparent no-p set-outpoint">{{a.player_view.total_time_string}}</span>
|
||||
</span>
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
<div id="space" v-cloak
|
||||
v-if="active_view == 'space' && active_space_loaded"
|
||||
class="section board active mouse-{{mouse_state}} tool-{{active_tool}}"
|
||||
v-bind:style="{'background-color': active_space.advanced.background_color}"
|
||||
v-bind:style="{'background-color': active_space.background_color}"
|
||||
v-sd-droppable="handle_data_drop;active_space"
|
||||
v-sd-whiteboard
|
||||
v-on:scroll="handle_scroll"
|
||||
@@ -206,16 +206,16 @@
|
||||
|
||||
<div id="space-clipboard" style="position:fixed;top:0;left:0;z-index:0;opacity:0;background-color:white"><textarea v-model="selected_artifacts_json" cols="2" rows="2" id="clipboard-ta" class="mousetrap"></textarea></div>
|
||||
|
||||
<div class="space-bounds" v-bind:style="{width: active_space.advanced.width*bounds_zoom + 'px', height: active_space.advanced.height*bounds_zoom + 'px', 'background-color': active_space.advanced.background_color}"></div>
|
||||
<div class="space-bounds" v-bind:style="{width: active_space.width*bounds_zoom + 'px', height: active_space.height*bounds_zoom + 'px', 'background-color': active_space.background_color}"></div>
|
||||
|
||||
<div class="wrapper"
|
||||
v-bind:style="{
|
||||
transform: 'scale('+viewport_zoom+')',
|
||||
'transform-origin': '0 0',
|
||||
width: active_space.advanced.width + 'px',
|
||||
height: active_space.advanced.height + 'px',
|
||||
'background-image': (active_space.advanced.background_uri)?'url(' + active_space.advanced.background_uri + ')':'',
|
||||
'background-color': ''+active_space.advanced.background_color,
|
||||
width: active_space.width + 'px',
|
||||
height: active_space.height + 'px',
|
||||
'background-image': (active_space.background_uri)?'url(' + active_space.background_uri + ')':'',
|
||||
'background-color': ''+active_space.background_color,
|
||||
'margin-left': bounds_margin_horiz + 'px',
|
||||
'margin-top': bounds_margin_vert + 'px'}" >
|
||||
|
||||
@@ -331,7 +331,7 @@
|
||||
<source v-bind:src="a.payload_uri" v-bind:type="a.mime" v-if="a.payload_uri"/>
|
||||
</audio>
|
||||
|
||||
<div class="timeline" v-show="a.board.h>=64 && a.board.w>=170" v-bind:style="{'background-image': 'url(' + a.payload_thumbnail_web_uri +')'}">
|
||||
<div class="timeline" v-show="a.h>=64 && a.w>=170" v-bind:style="{'background-image': 'url(' + a.payload_thumbnail_web_uri +')'}">
|
||||
<div class="tl-current-time" v-bind:style="{width: a.player_view.current_time_float*100 + '%'}"></div>
|
||||
<div class="tl-inpoint" v-bind:style="{left: a.player_view.inpoint_float*100 + '%'}" v-if="a.player_view.inpoint_float>0.0"></div>
|
||||
<div class="tl-outpoint" v-bind:style="{left: a.player_view.outpoint_float*100 + '%'}"></div>
|
||||
@@ -352,13 +352,13 @@
|
||||
<span class="icon icon-controls-stop"></span>
|
||||
</span>
|
||||
|
||||
<span class="tl-title" v-show="a.board.w>=400">{{a.view.filename}}</span>
|
||||
<span class="tl-title" v-show="a.w>=400">{{a.view.filename}}</span>
|
||||
<span class="tl-times" class="btn-group">
|
||||
<span class="btn btn-md btn-transparent no-p">{{a.player_view.current_time_string}}</span>
|
||||
<span class="btn btn-md btn-transparent no-p" v-show="a.board.w>=170"> / {{a.player_view.total_time_string}}</span>
|
||||
<span class="btn btn-md btn-transparent no-p" v-show="a.w>=170"> / {{a.player_view.total_time_string}}</span>
|
||||
</span>
|
||||
|
||||
<span v-show="logged_in && a.board.w>=310">
|
||||
<span v-show="logged_in && a.w>=310">
|
||||
<a class="btn btn-xs btn-round btn-icon set-inpoint" title="Set Inpoint at Playhead">
|
||||
<span class="icon icon-edge-left"></span>
|
||||
</a>
|
||||
@@ -464,7 +464,7 @@
|
||||
|
||||
<div v-if="active_space_loaded" v-cloak>
|
||||
<div id="minimap"
|
||||
v-bind:style="{width: ''+(active_space.advanced.width/minimap_scale)+'px', height: ''+(active_space.advanced.height/minimap_scale)+'px', bottom: '66px', right: '20px'}"
|
||||
v-bind:style="{width: ''+(active_space.width/minimap_scale)+'px', height: ''+(active_space.height/minimap_scale)+'px', bottom: '66px', right: '20px'}"
|
||||
v-if="active_space"
|
||||
v-on:mousedown="handle_minimap_mousedown($event)"
|
||||
v-on:touchstart="handle_minimap_mousedown($event)"
|
||||
@@ -473,7 +473,7 @@
|
||||
v-on:mouseleave="handle_minimap_mouseup($event)"
|
||||
v-on:touchend="handle_minimap_mouseup($event)"
|
||||
v-on:mouseup="handle_minimap_mouseup($event)">
|
||||
<div v-for="a in active_space_artifacts" v-bind:style="{left: ''+(a.board.x/minimap_scale)+ 'px', top: ''+(a.board.y/minimap_scale) + 'px', width: ''+(a.board.w/minimap_scale)+ 'px', height: ''+(a.board.h/minimap_scale) + 'px'}"></div>
|
||||
<div v-for="a in active_space_artifacts" v-bind:style="{left: ''+(a.x/minimap_scale)+ 'px', top: ''+(a.y/minimap_scale) + 'px', width: ''+(a.w/minimap_scale)+ 'px', height: ''+(a.h/minimap_scale) + 'px'}"></div>
|
||||
<div class="window" v-bind:style="{left: ''+(scroll_left/minimap_scale) + 'px', top: ''+(scroll_top/minimap_scale)+ 'px', width: ''+(window_width/minimap_scale)+ 'px', height: ''+(window_height/minimap_scale) + 'px'}"></div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -79,14 +79,14 @@
|
||||
</div-->
|
||||
|
||||
<div class="" v-show="background_mode=='image'" v-if="active_space">
|
||||
<div class="background-image" v-bind:style="{height: '233px', 'background-image':'url('+active_space.advanced.background_uri+')', 'margin': '6px', 'border-radius': '3px'}" v-if="active_space.advanced.background_uri && !space_background_uploading">
|
||||
<div class="background-image" v-bind:style="{height: '233px', 'background-image':'url('+active_space.background_uri+')', 'margin': '6px', 'border-radius': '3px'}" v-if="active_space.background_uri && !space_background_uploading">
|
||||
</div>
|
||||
|
||||
<div class="progress state-processing" v-if="space_background_uploading">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-section no-b adapt" v-if="!active_space.advanced.background_uri && !space_background_uploading" v-on:touchstart="handle_touch_select_background_image()">
|
||||
<div class="dialog-section no-b adapt" v-if="!active_space.background_uri && !space_background_uploading" v-on:touchstart="handle_touch_select_background_image()">
|
||||
<label class="btn btn-xxl btn-transparent btn-icon">
|
||||
<span class="icon icon-picture-upload"></span>
|
||||
<input id="background-uploader" type="file" accept="image/*" v-on:change="handle_section_background_upload($event)">
|
||||
@@ -94,9 +94,9 @@
|
||||
<p>[[__("upload_background_caption")]]</p>
|
||||
</div>
|
||||
|
||||
<div class="dialog-section no-p no-flex" v-if="active_space.advanced.background_uri">
|
||||
<div class="dialog-section no-p no-flex" v-if="active_space.background_uri">
|
||||
<div class="btn-cluster">
|
||||
<label class="btn btn-transparent btn-block text-center" v-if="active_space.advanced.background_uri" v-on:touchstart="handle_touch_select_background_image()">
|
||||
<label class="btn btn-transparent btn-block text-center" v-if="active_space.background_uri" v-on:touchstart="handle_touch_select_background_image()">
|
||||
<input id="background-uploader" type="file" accept="image/*" v-on:chang="handle_section_background_upload($event)">
|
||||
<span class="icon icon-picture-upload"></span>
|
||||
<!-- Upload -->
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div id="pick-mobile" v-if="active_space" class="dialog-section" v-show="opened_dialog=='mobile'">
|
||||
<h4 class="dialog-title">Mobile Upload</h4>
|
||||
|
||||
<img v-if="active_space.edit_hash" v-bind:src="'/api/helper/qrcode/'+ active_space._id" />
|
||||
<!--img v-if="active_space.edit_hash" v-bind:src="'/api/helper/qrcode/'+ active_space._id"-->
|
||||
|
||||
<p class="text-center">
|
||||
Install the Spacedeck App on your phone and scan this QR code to upload photos, sound, video or text.
|
||||
|
||||
@@ -76,20 +76,7 @@
|
||||
{% include "./zones.html" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="mobile-dialog" class="dropdown bottom light center static" v-bind:class="{open:opened_dialog=='mobile'}">
|
||||
<div class="btn-collapse in">
|
||||
<button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='mobile'}" v-on:click="open_dialog('mobile')" >
|
||||
<span class="icon icon-device-mobile"></span>
|
||||
<span class="icon-label">[[__("mobile")]]</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="dialog mobile-search">
|
||||
{% include "./pick-mobile.html" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<button class="btn btn-divider" v-show="logged_in"></button>
|
||||
|
||||
<div class="dropdown bottom light center" v-show="logged_in" v-bind:class="{open:opened_dialog=='background'}">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<button v-on:click="add_zone()" class="btn btn-sm btn-primary">[[__("add_zone")]]</button>
|
||||
</div>
|
||||
|
||||
<div class="dialog-section no-p" v-for="z in zones | orderBy 'style.order'" style="white-space: nowrap;text-align:left;cursor:pointer" v-on:click="zoom_to_zone(z)">
|
||||
<div class="dialog-section no-p" v-for="z in zones | orderBy 'order'" style="white-space: nowrap;text-align:left;cursor:pointer" v-on:click="zoom_to_zone(z)">
|
||||
<button class="btn btn-sm btn-transparent">{{{z.description}}}</button>
|
||||
<button v-if="$index==current_zone_idx" v-on:click="sort_zone_up(z)" class="btn btn-sm btn-round btn-transparent btn-icon"><span class="icon icon-triangle-up"></span></button>
|
||||
<button v-if="$index==current_zone_idx" v-on:click="sort_zone_down(z)" class="btn btn-sm btn-round btn-transparent btn-icon"><span class="icon icon-triangle-down"></span></button>
|
||||
|
||||
Reference in New Issue
Block a user