Parcourir la source

Components : Loader, ResetAppButton, HostConfig

rigwild il y a 5 ans
Parent
commit
4b62c98931

+ 117 - 48
src/App.vue

@@ -1,64 +1,133 @@
 <template>
-  <v-app id="inspire" :dark="darkMode">
-    <!-- Sidebar menu -->
-    <v-navigation-drawer
-      v-model="drawer"
-      clipped
-      fixed
-      app
-    >
-      <v-list dense>
-        <v-list-tile to="/" exact>
-          <v-list-tile-action>
-            <v-icon>home</v-icon>
-          </v-list-tile-action>
-          <v-list-tile-content>
-            <v-list-tile-title>Home</v-list-tile-title>
-          </v-list-tile-content>
-        </v-list-tile>
+  <v-app :dark="darkMode">
+    <!-- Application cache reset button -->
+    <div class="reset-button">
+      <ResetAppButton />
+    </div>
+    <!--/ Application cache reset button -->
 
-        <v-list-tile to="/listScenes" exact>
-          <v-list-tile-action>
-            <v-icon>photo_library</v-icon>
-          </v-list-tile-action>
-          <v-list-tile-content>
-            <v-list-tile-title>List scenes</v-list-tile-title>
-          </v-list-tile-content>
-        </v-list-tile>
-      </v-list>
-    </v-navigation-drawer>
-    <!--/ Sidebar menu -->
+    <v-slide-y-transition mode="out-in">
+      <!-- Host connection configuration -->
+      <host-config v-if="!isHostConfigured" />
+      <!--/ Host connection configuration -->
 
-    <!-- Top bar -->
-    <v-toolbar app fixed clipped-left>
-      <v-toolbar-side-icon @click.stop="drawer = !drawer" />
-      <v-toolbar-title>Web experience</v-toolbar-title>
-    </v-toolbar>
-    <!--/ Top bar -->
+      <!-- Loading screen -->
+      <loader v-else-if="loadingMessage" :message="loadingMessage" />
+      <!--/ Loading screen -->
 
-    <!-- Pages content -->
-    <v-content>
-      <v-container fluid fill-height>
-        <v-layout justify-center align-center>
-          <v-scroll-x-reverse-transition mode="out-in">
-            <!-- View injected here -->
-            <router-view />
-            <!--/ View injected here -->
-          </v-scroll-x-reverse-transition>
-        </v-layout>
-      </v-container>
-    </v-content>
-    <!--/ Pages content -->
+      <div v-else>
+        <!-- Sidebar menu -->
+        <v-navigation-drawer
+          v-model="drawer"
+          clipped
+          fixed
+          app
+        >
+          <v-list dense>
+            <v-list-tile to="/" exact>
+              <v-list-tile-action>
+                <v-icon>home</v-icon>
+              </v-list-tile-action>
+              <v-list-tile-content>
+                <v-list-tile-title>Home</v-list-tile-title>
+              </v-list-tile-content>
+            </v-list-tile>
+
+            <v-list-tile to="/experiencesList" exact>
+              <v-list-tile-action>
+                <v-icon>photo_library</v-icon>
+              </v-list-tile-action>
+              <v-list-tile-content>
+                <v-list-tile-title>Experiences list</v-list-tile-title>
+              </v-list-tile-content>
+            </v-list-tile>
+          </v-list>
+        </v-navigation-drawer>
+        <!--/ Sidebar menu -->
+
+        <!-- Top bar -->
+        <v-toolbar app fixed clipped-left>
+          <v-toolbar-side-icon @click.stop="drawer = !drawer" />
+          <v-toolbar-title>Web experience</v-toolbar-title>
+        </v-toolbar>
+        <!--/ Top bar -->
+
+        <!-- Pages content -->
+        <v-content>
+          <v-container fluid fill-height>
+            <v-layout justify-center>
+              <v-scroll-x-reverse-transition mode="out-in">
+                <!-- View injected here -->
+                <router-view />
+                <!--/ View injected here -->
+              </v-scroll-x-reverse-transition>
+            </v-layout>
+          </v-container>
+        </v-content>
+        <!--/ Pages content -->
+      </div>
+    </v-slide-y-transition>
   </v-app>
 </template>
 
 <script>
+import ResetAppButton from '@/components/ResetAppButton.vue'
+import Loader from '@/components/Loader.vue'
+import HostConfig from '@/components/HostConfig.vue'
+import { mapGetters, mapActions } from 'vuex'
+
 export default {
+  components: {
+    ResetAppButton,
+    Loader,
+    HostConfig
+  },
   data() {
     return {
       darkMode: true,
-      drawer: false
+      drawer: false,
+
+      hostConfigured: false,
+      loadingMessage: null
+    }
+  },
+  computed: {
+    ...mapGetters(['isHostConfigured', 'areScenesLoaded'])
+  },
+  watch: {
+    isHostConfigured(value) {
+      if (!this.areScenesLoaded && value) this.loadAppData()
+    }
+  },
+  mounted() {
+    if (this.isHostConfigured && !this.areScenesLoaded) this.loadAppData()
+  },
+  methods: {
+    ...mapActions(['loadScenesList']),
+    async loadAppData() {
+      if (this.isHostConfigured && !this.areScenesLoaded) {
+        this.loadingMessage = 'Loading scenes list...'
+        try {
+          await this.loadScenesList()
+        }
+        catch (err) {
+          this.loadingErrorMessage = err.message
+          return
+        }
+        finally {
+          this.loadingMessage = null
+        }
+      }
     }
   }
 }
 </script>
+
+<style scoped>
+.reset-button {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  z-index: 999;
+}
+</style>

+ 96 - 0
src/components/HostConfig.vue

@@ -0,0 +1,96 @@
+<template>
+  <v-layout justify-center align-center>
+    <v-flex xs12 sm5>
+      <v-card>
+        <v-content>
+          <v-container fluid fill-height>
+            <v-layout style="flex-direction: column; text-align: center">
+              <h1>Host configuration</h1>
+
+              <v-slide-y-transition mode="out-in">
+                <loader v-if="loadingMessage" :message="loadingMessage" />
+                <v-form v-else ref="form">
+                  <v-text-field
+                    v-model="config.host"
+                    label="Host IP address or hostname"
+                    :rules="[v => !!v || 'Host is required']"
+                    required
+                  />
+
+                  <v-text-field
+                    v-model="config.port"
+                    label="Port"
+                    type="number"
+                    :rules="[v => !!v || 'Port is required']"
+                    required
+                  />
+
+                  <v-btn color="error" @click="reset">Reset Form</v-btn>
+
+                  <v-btn color="success" @click="validate">Submit</v-btn>
+
+                  <v-slide-y-transition mode="out-in">
+                    <v-alert v-if="configErrorMessage" :value="true" type="error" v-text="configErrorMessage" />
+                  </v-slide-y-transition>
+                </v-form>
+              </v-slide-y-transition>
+            </v-layout>
+          </v-container>
+        </v-content>
+      </v-card>
+    </v-flex>
+  </v-layout>
+</template>
+
+<script>
+import Loader from '@/components/Loader.vue'
+import { mapActions } from 'vuex'
+
+export default {
+  name: 'HostConfig',
+  components: {
+    Loader
+  },
+  data() {
+    return {
+      config: {
+        protocol: 'HTTP',
+        host: 'diran.univ-littoral.fr',
+        port: '80'
+      },
+
+      loadingMessage: null,
+      configErrorMessage: null
+    }
+  },
+
+  methods: {
+    ...mapActions(['setHostConfig']),
+    reset() {
+      this.config.protocol = 'HTTP'
+      this.config.host = ''
+      this.config.port = null
+      this.configErrorMessage = null
+      this.$refs.form.reset()
+    },
+    async validate() {
+      if (!this.$refs.form.validate()) return
+
+      this.loadingMessage = 'Checking host configuration...'
+      this.configErrorMessage = null
+      try {
+        await this.setHostConfig(this.config)
+      }
+      catch (err) {
+        this.configErrorMessage = err.message
+        return
+      }
+      finally {
+        this.loadingMessage = null
+      }
+
+      // Success while configuring the project's host
+    }
+  }
+}
+</script>

+ 26 - 0
src/components/Loader.vue

@@ -0,0 +1,26 @@
+<template>
+  <v-content>
+    <v-container fluid fill-height>
+      <v-layout align-center justify-center style="flex-direction: column">
+        <v-progress-circular
+          :size="50"
+          color="primary"
+          indeterminate
+        />
+        <div class="mt-3">{{ message }}</div>
+      </v-layout>
+    </v-container>
+  </v-content>
+</template>
+
+<script>
+export default {
+  name: 'Loader',
+  props: {
+    message: {
+      type: String,
+      default: 'Loading...'
+    }
+  }
+}
+</script>

+ 66 - 0
src/components/ResetAppButton.vue

@@ -0,0 +1,66 @@
+<template>
+  <div class="text-xs-center">
+    <v-dialog
+      v-model="dialog"
+      width="600"
+      :fullscreen="$vuetify.breakpoint.smAndDown"
+    >
+      <template v-slot:activator="{ on }">
+        <v-btn small dark v-on="on">Reset app</v-btn>
+      </template>
+
+      <v-card>
+        <v-card-title class="headline" primary-title>Reset app</v-card-title>
+
+        <v-card-text>
+          Resetting the app will purge the configuration, any cached data, progression or any other data stored client-side.<br><br>
+          This action is not reversible.
+        </v-card-text>
+
+        <v-divider />
+
+        <v-card-actions v-if="$vuetify.breakpoint.smAndDown">
+          <v-flex xs12 text-xs-center>
+            <div>
+              <v-btn color="primary" block flat @click="reset({ hostConfig: true })">Reset configuration</v-btn>
+            </div>
+            <div>
+              <v-btn color="primary" block flat @click="reset({ hostConfig: true, scenesList: true })">Reset everything</v-btn>
+            </div>
+
+            <div class="mt-4">
+              <v-btn color="secondary" block flat @click="dialog = false">Cancel</v-btn>
+            </div>
+          </v-flex>
+        </v-card-actions>
+
+        <v-card-actions v-else>
+          <v-btn color="secondary" flat @click="dialog = false">Cancel</v-btn>
+          <v-spacer />
+          <v-btn color="primary" flat @click="reset({ hostConfig: true })">Reset configuration</v-btn>
+          <v-btn color="primary" flat @click="reset({ hostConfig: true, scenesList: true })">Reset everything</v-btn>
+        </v-card-actions>
+      </v-card>
+    </v-dialog>
+  </div>
+</template>
+
+<script>
+import { mapActions } from 'vuex'
+
+export default {
+  name: 'ResetAppButton',
+  data() {
+    return {
+      dialog: false
+    }
+  },
+  methods: {
+    ...mapActions(['resetApp']),
+    reset(toResetObj) {
+      this.resetApp(toResetObj)
+      this.dialog = false
+    }
+  }
+}
+</script>

+ 21 - 0
src/functions.js

@@ -1 +1,22 @@
+export const API_PREFIX = '/api'
+export const API_ROUTES = {
+  ping: () => `${API_PREFIX}/ping`,
+
+  listScenes: () => `${API_PREFIX}/listScenes`,
+
+  listSceneQualities: sceneName => `${API_PREFIX}/listSceneQualities?sceneName=${new URLSearchParams({ sceneName })}`,
+
+  getImage: (sceneName, imageQuality) => `${API_PREFIX}/getImage?${new URLSearchParams({ sceneName, imageQuality })}`,
+
+  getImageExtracts: (sceneName, imageQuality, horizontalExtractCount, verticalExtractCount) =>
+    `${API_PREFIX}/getImage?${new URLSearchParams({
+      sceneName,
+      imageQuality,
+      horizontalExtractCount,
+      verticalExtractCount
+    })}`
+}
+
 export const delay = ms => new Promise(res => setTimeout(res, ms))
+
+export const buildURI = (protocol, host, port, route = '') => `${protocol}://${host}:${port}${route}`

+ 3 - 3
src/router.js

@@ -12,9 +12,9 @@ export default new Router({
       component: Home
     },
     {
-      path: '/listScenes',
-      name: 'ListScenes',
-      component: () => import('./views/ListScenes.vue')
+      path: '/experiencesList',
+      name: 'ExperiencesList',
+      component: () => import('./views/ExperiencesList.vue')
     }
   ]
 })

+ 0 - 12
src/views/ListScenes.vue

@@ -1,12 +0,0 @@
-<template>
-  <div>
-    List available scenes
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'ListScenes',
-  components: {}
-}
-</script>