diff --git a/core/Dockerfile b/core/Dockerfile index bebec2b838..8dad8898e5 100644 --- a/core/Dockerfile +++ b/core/Dockerfile @@ -10,6 +10,8 @@ RUN [ -z "$VUE_APP_GIT_DESCRIBE" ] \ COPY frontend /home/pi/frontend RUN --mount=type=cache,target=/home/pi/frontend/node_modules yarn --cwd /home/pi/frontend install --network-timeout=300000 --ignore-engines RUN --mount=type=cache,target=/home/pi/frontend/node_modules yarn --cwd /home/pi/frontend build --skip-plugins @vue/cli-plugin-eslint --ignore-engines +# Copy some static files not consumed by webpack +COPY frontend/src/assets/vehicles /home/pi/frontend/dist/vehicles # Download binaries FROM bluerobotics/blueos-base:v0.0.8 as downloadBinaries diff --git a/core/frontend/src/App.vue b/core/frontend/src/App.vue index f4a722dd21..ee91f6bcc4 100644 --- a/core/frontend/src/App.vue +++ b/core/frontend/src/App.vue @@ -50,6 +50,13 @@ width="70%" /> + + + + \ No newline at end of file diff --git a/core/frontend/src/components/app/ImagePicker.vue b/core/frontend/src/components/app/ImagePicker.vue new file mode 100755 index 0000000000..4be07fcd7c --- /dev/null +++ b/core/frontend/src/components/app/ImagePicker.vue @@ -0,0 +1,295 @@ + + + + diff --git a/core/frontend/src/components/app/VehicleBanner.vue b/core/frontend/src/components/app/VehicleBanner.vue new file mode 100755 index 0000000000..270b2ce617 --- /dev/null +++ b/core/frontend/src/components/app/VehicleBanner.vue @@ -0,0 +1,176 @@ + + + + diff --git a/core/frontend/src/components/wizard/Wizard.vue b/core/frontend/src/components/wizard/Wizard.vue index b2ad40bdac..7799476be1 100644 --- a/core/frontend/src/components/wizard/Wizard.vue +++ b/core/frontend/src/components/wizard/Wizard.vue @@ -151,7 +151,7 @@ import beacon from '@/store/beacon' import wifi from '@/store/wifi' import back_axios from '@/utils/api' -const WIZARD_VERSION = 3 +const WIZARD_VERSION = 4 const models = require.context( '/src/assets/vehicles/models/', @@ -194,6 +194,7 @@ export default Vue.extend({ sub_model: models('./bluerov.glb'), vehicle_name: 'blueos', vehicle_type: VehicleType.Sub, + vehicle_image: null as string | null, wait_configuration: false, // Final configuration configurations: [] as Configuration[], @@ -253,6 +254,13 @@ export default Vue.extend({ message: undefined, done: false, }, + { + title: 'Set vehicle image', + summary: 'Set image to be used for vehicle thumbnail', + promise: this.setVehicleImage(), + message: undefined, + done: false, + }, ...this.setup_configurations, { title: 'Update wizard version', @@ -276,6 +284,7 @@ export default Vue.extend({ setupBoat() { this.vehicle_type = VehicleType.Boat this.vehicle_name = 'BlueBoat' + this.vehicle_image = '/vehicles/images/bb120.png' this.step_number += 1 this.setup_configurations = [ @@ -302,6 +311,7 @@ export default Vue.extend({ setupROV() { this.vehicle_type = VehicleType.Sub this.vehicle_name = 'BlueROV' + this.vehicle_image = '/vehicles/images/bluerov2.png' this.step_number += 1 }, async setWizardVersion(): Promise { @@ -317,6 +327,14 @@ export default Vue.extend({ .then(() => undefined) .catch(() => 'Failed to set vehicle hostname for mDNS') }, + async setVehicleImage(): Promise { + const failed = 'Failed to set vehicle Image.' + const payload = { url: this.vehicle_image } + return bag.setData('vehicle.image_path', payload) + // eslint-disable-next-line no-confusing-arrow + .then((result) => result ? undefined : failed) + .catch(() => failed) + }, async setVehicleName(): Promise { return beacon.setVehicleName(this.vehicle_name) .then(() => undefined) diff --git a/core/frontend/src/store/beacon.ts b/core/frontend/src/store/beacon.ts index b59e8b5333..23b4641434 100644 --- a/core/frontend/src/store/beacon.ts +++ b/core/frontend/src/store/beacon.ts @@ -35,7 +35,7 @@ class BeaconStore extends VuexModule { hostname: undefined | string = undefined - vehicle_name: undefined | string = undefined + vehicle_name = '' // eslint-disable-next-line @Mutation @@ -193,7 +193,7 @@ class BeaconStore extends VuexModule { }) } - if (this.vehicle_name === undefined) { + if (this.vehicle_name === '') { back_axios({ method: 'get', url: `${this.API_URL}/vehicle_name`, @@ -208,8 +208,8 @@ class BeaconStore extends VuexModule { }) } - if (this.hostname !== undefined && this.vehicle_name !== undefined) { - prefetched_names = false + if (this.hostname !== undefined && this.vehicle_name !== '') { + prefetched_names = true } } diff --git a/core/frontend/vue.config.js b/core/frontend/vue.config.js index 42115cfebb..31e2b9733e 100644 --- a/core/frontend/vue.config.js +++ b/core/frontend/vue.config.js @@ -39,6 +39,9 @@ module.exports = { '^/helper': { target: SERVER_ADDRESS, }, + '^/upload': { + target: SERVER_ADDRESS, + }, '^/kraken': { target: SERVER_ADDRESS, selfHandleResponse: true, @@ -78,6 +81,9 @@ module.exports = { '^/userdata': { target: SERVER_ADDRESS, }, + '^/vehicles': { + target: SERVER_ADDRESS, + }, '^/version-chooser': { target: SERVER_ADDRESS, selfHandleResponse: true, diff --git a/core/tools/blueos_startup_update/blueos_startup_update b/core/tools/blueos_startup_update/blueos_startup_update index b13516d078..ea82813ddc 100755 --- a/core/tools/blueos_startup_update/blueos_startup_update +++ b/core/tools/blueos_startup_update/blueos_startup_update @@ -89,6 +89,21 @@ def update_dwc2() -> None: )' ''' print(run_command(command, False)) +def ensure_nginx_permissions() -> None: + # ensure nginx can read the userdata directory + command = "sudo chown -R www-data:www-data /usr/blueos/userdata" + print(run_command(command, False)) + +def ensure_user_data_structure_is_in_place() -> None: + # ensures we have all base folders in userdata + commands = [ + "sudo mkdir -p /usr/blueos/userdata/images/vehicle", + "sudo mkdir -p /usr/blueos/userdata/images/logo", + "sudo mkdir -p /usr/blueos/userdata/styles", + ] + for command in commands: + print(run_command(command, False)) + def main() -> None: current_git_version = os.getenv('GIT_DESCRIBE_TAGS') @@ -99,6 +114,8 @@ def main() -> None: update_startup() update_cgroups() update_dwc2() + ensure_user_data_structure_is_in_place() + ensure_nginx_permissions() if __name__ == "__main__": main() \ No newline at end of file diff --git a/core/tools/nginx/nginx.conf b/core/tools/nginx/nginx.conf index 0f73964a57..a3eb0ee401 100644 --- a/core/tools/nginx/nginx.conf +++ b/core/tools/nginx/nginx.conf @@ -193,15 +193,34 @@ http { location / { root /home/pi/frontend; try_files $uri $uri/ /index.html; + autoindex on; + # allow frontend to see files using json + autoindex_format json; + } + + location ~ ^/upload(/.*)$ { + client_max_body_size 100M; + alias /usr/blueos$1; + + # Change the access permissions of the uploaded file + dav_access group:rw all:r; + create_full_put_path on; + + # Configure the allowed HTTP methods + dav_methods PUT DELETE MKCOL COPY MOVE; } location /userdata { root /usr/blueos; autoindex on; + # use json as it is easily consumed by the frontend + # users already have access through the file browser + autoindex_format json; # disable cache to improve developer experience # this should have very little impact for users expires -1; add_header Cache-Control no-store; + add_header Access-Control-Allow-Origin *; } location ~* \.html$ {