Skip to content

Commit

Permalink
Merge pull request #2 from TDu/mobile_app_controller
Browse files Browse the repository at this point in the history
Mobile app front router and controller
  • Loading branch information
simahawk authored Feb 13, 2020
2 parents 92fa026 + cec21e5 commit 8ca8fec
Show file tree
Hide file tree
Showing 15 changed files with 3,049 additions and 88 deletions.
1 change: 1 addition & 0 deletions shopfloor_mobile/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import controllers
1 change: 1 addition & 0 deletions shopfloor_mobile/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import main
22 changes: 22 additions & 0 deletions shopfloor_mobile/controllers/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import os

from odoo import http


class ShopfloorMobileAppController(http.Controller):

module_path = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0]

@http.route(
["/shopfloormobile/scanner/<path:path_fragment>", "/shopfloormobile/scanner"],
auth="public",
)
def load_app_and_assets(self, path_fragment=""):
# TODO Should be authorized via api.key except for the login ?
if path_fragment.startswith("src/"):
# Serving an asset
payload = os.path.join(self.module_path, "static", "wms", path_fragment)
else:
# Serving the app
payload = os.path.join(self.module_path, "static", "wms", "index.html")
return http.send_file(payload)
9 changes: 5 additions & 4 deletions shopfloor_mobile/static/wms/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<script src="src/vendor/popper.min.js"></script>
<script src="src/vendor/lodash.js"></script>
<script src="src/vendor/vue.js"></script>
<script src="src/vendor/vue-router.js"></script>
<script src="src/vendor/vuetify/vuetify.js"></script>
<script src="src/services/fake.js"></script>
<script src="src/services/odoo.js" type="module"></script>
Expand All @@ -46,11 +47,11 @@
<noscript>
<strong>We're sorry but wms doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app">
<div id="app">
<v-app>
<v-content>
<v-container>Hello world</v-container>
</v-content>
<v-container>
<router-view></router-view>
</v-container>
</v-app>
</div>
<!-- built files will be auto injected -->
Expand Down
6 changes: 3 additions & 3 deletions shopfloor_mobile/static/wms/src/components/screen.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ Vue.component('Screen', {
<v-list-item
v-for="item in navigation"
:key="item.name"
:href="'#' + $root.make_menu_item_url(item)"
:href="'#/' + item.process.code"
link
>
<v-list-item-content>
<v-list-item-title>{{ item.name }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-list-item href="#" link>
<v-list-item @click="$router.push({'name': 'home'})" link>
<v-list-item-content>
<v-list-item-title>Main menu</v-list-item-title>
</v-list-item-content>
Expand All @@ -53,7 +53,7 @@ Vue.component('Screen', {
<v-toolbar-title>{{ title }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn icon href="#scananything">
<v-btn icon @click="$router.push('scananything')">
<v-icon >mdi-magnify</v-icon>
</v-btn>
<v-menu
Expand Down
4 changes: 2 additions & 2 deletions shopfloor_mobile/static/wms/src/homepage.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var homepage = Vue.component('home-page', {
export var HomePage = Vue.component('home-page', {
computed: {
navigation () {
return this.$root.config.get('menus')
Expand All @@ -15,7 +15,7 @@ var homepage = Vue.component('home-page', {
<v-list-item
v-for="item in navigation"
:key="item.name"
:href="'#' + $root.make_menu_item_url(item)"
:href="'#/' + item['process'].code"
link
>
<v-list-item-content>
Expand Down
8 changes: 6 additions & 2 deletions shopfloor_mobile/static/wms/src/loginpage.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Storage} from './services/storage.js'

Vue.component('login-page', {
export var LoginPage = Vue.component('login-page', {
data: function(){ return {
'apikey': '72B044F7AC780DAC',
'error': '',
Expand All @@ -12,7 +12,11 @@ Vue.component('login-page', {
Storage.apikey = this.apikey
this.error = ""
this.$root.config.load().catch((error) => {
this.error = "Invalid API KEY"
this.error = "Invalid API KEY"
}).then(() => {
if (this.$root.config.authenticated) {
this.$router.push({'name': 'home'})
}
});

}
Expand Down
88 changes: 22 additions & 66 deletions shopfloor_mobile/static/wms/src/main.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,30 @@
//import searchbar from 'components/searchbar/searchbar.js'

import {router} from './router.js'
import {Config} from './services/config.js'
import {Storage} from './services/storage.js'

const NotFound = { template: '<p>Page not found</p>' }
const Home = { template: '<home-page v-bind:routes="routes"></home-page>', props: {routes:"myroutes"}} // { props: {routes: AllRoutes} }}
const LoginPage = { template: '<login-page></login-page>' }
const ScanAnything = { template: '<scan-anything></scan-anything>' }
import {SinglePackPutAway} from './scenario/single_pack_putaway.js'
import {SinglePackTransfer} from './scenario/single_pack_transfer.js'

const ScenarioTemplate = {
single_pack_putaway: {template: "<single-pack-putaway></single-pack-putaway>"},
single_pack_transfer: {template: "<single-pack-transfer></single-pack-transfer>"},
single_pack_putaway: SinglePackPutAway,
single_pack_transfer: SinglePackTransfer,
}

var AppConfig = new Config()

class Routes {
static get(path) {
// support demo mode via hash eg: `#demo/single_pack_putaway`
path = path.replace('demo/', '')
if (path == '') {
return Home
} else if (path == 'scananything'){
return ScanAnything
} else {
let menu_items = AppConfig.get('menus')
for (var idx in menu_items) {
let item = menu_items[idx]
if (item.process && item.process.code == path) {
return ScenarioTemplate[item.process.code]
}
}
return NotFound;
}
}
}

if ( Storage.apikey ) {
AppConfig.load()
}
AppConfig.load().then(() => {
// Adding the routes dynamically when received from ther server
AppConfig.get('menus').forEach(function(item){
console.dir(item)
app.$router.addRoutes([{
path: "/" + item.process.code,
component: ScenarioTemplate[item.process.code],
props: { menuItem: item}
}])
})
})
}

const vuetify_themes = {
light: {
Expand All @@ -52,52 +38,22 @@ const vuetify_themes = {
}
}

var app = new Vue({
el: '#app',
const app = new Vue({
router: router,
vuetify: new Vuetify({
// FIXME: has no effect
// theme: {
// themes: vuetify_themes
// }
}),
data: {
currentRoute: window.location.hash.slice(1),
demo_mode: false,
config: AppConfig,
},
computed: {
ViewComponent () {
if (this.config.authenticated) {
// TMP hack to be able to pass around params via querystring.
// We'll use proper routing later.
return Routes.get(this.currentRoute.split('?')[0]);
} else {
return LoginPage;
}
}
},
created: function () {
this.demo_mode = window.location.hash.includes('demo')
// TODO This need to be fixed so it is dynamic again
this.demo_mode = true;
},
render (h) { return h(this.ViewComponent) },
methods: {
make_menu_item_url (menu_item) {
// TODO: once we'll have proper routing in place this will change
let params = {
'menu_id': menu_item.id,
'process_id': menu_item.process.id,
}
let url = menu_item.process.code + '?' + new URLSearchParams(params).toString()
if (this.$root.demo_mode)
url = 'demo/' + url
return url
}
},

})

window.addEventListener('popstate', (e) => {
// Using the hash of the url for navigation
// To use url fragment we need a proper server in the backend
app.currentRoute = window.location.hash.slice(1)
});
}).$mount('#app');
26 changes: 26 additions & 0 deletions shopfloor_mobile/static/wms/src/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {HomePage} from './homepage.js'
import {ScanAnything} from "./scenario/scan_anything.js";
import {LoginPage} from './loginpage.js'
// const NotFound = { template: '<div>Lost in the scanner app.</div>' }

const routes = [
{ path: '/', component: HomePage, name: 'home'},
{ path: '/login', component: LoginPage, name: 'login'},
{ path: '/scananything/:codebar?', component: ScanAnything, name: 'scananything' },
// TODO Fix this it needs to be the last route, but I think it is not anymore with the dynamic one added.
// { path: '*', component: NotFound },
]

const router = new VueRouter({
routes: routes,
})
router.beforeEach(async (to, from, next) => {
await Vue.nextTick()
if (!router.app.config.authenticated && to.name!='login'){
next('login')
} else {
next()
}
})

export {router};
3 changes: 2 additions & 1 deletion shopfloor_mobile/static/wms/src/scenario/mixins.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Odoo, OdooMocked} from "../services/odoo.js";

export var ScenarioBaseMixin = {
props: ['menuItem'],
data: function () {
return {
'user_notification': {
Expand Down Expand Up @@ -228,4 +229,4 @@ export var GenericStatesMixin = {
}
}
}
}
}
41 changes: 34 additions & 7 deletions shopfloor_mobile/static/wms/src/scenario/scan_anything.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {ScenarioBaseMixin} from "./mixins.js";

Vue.component('scan-anything', {
export var ScanAnything = Vue.component('scan-anything', {
mixins: [ScenarioBaseMixin],
template: `
<Screen title="Scan Anything">
Expand All @@ -13,6 +13,31 @@ Vue.component('scan-anything', {
<reset-screen-button v-on:reset="on_reset" :show_reset_button="show_reset_button"></reset-screen-button>
</Screen>
`,
mounted () {
if (this.$route.params["codebar"]){
this.go_state(
'wait_call',
this.odoo.scan_anything(this.$route.params["codebar"])
)
}
},
beforeRouteUpdate (to, from, next) {
this.current_state = this.initial_state
if (to.params["codebar"]){
this.go_state(
'wait_call',
this.odoo.scan_anything(to.params["codebar"])
)
}
next()
},
methods: {
on_reset: function (e) {
this.reset_notification()
this.reset_erp_data('data')
this.$router.push({ name: "scananything", params: {codebar: undefined}})
},
},
data: function () {
return {
'usage': 'scan_anything',
Expand All @@ -25,10 +50,10 @@ Vue.component('scan-anything', {
this.reset_erp_data('data')
},
on_scan: (scanned) => {
this.go_state(
'wait_call',
this.odoo.scan_anything(scanned.text)
)
this.$router.push({
"name": "scananything",
params: {"codebar": scanned.text}
})
},
scan_placeholder: 'Scan anything...',
},
Expand All @@ -48,8 +73,10 @@ Vue.component('scan-anything', {
},
on_scan: (scanned) => {
this.erp_data.data.location_barcode = scanned.text
this.go_state('wait_call',
this.odoo.scan_anything(scanned.text))
this.$router.push({
"name": "scananything",
params: {"codebar": scanned.text}
})
},
},
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {ScenarioBaseMixin, GenericStatesMixin} from "./mixins.js";

Vue.component('single-pack-putaway', {
export var SinglePackPutAway = Vue.component('single-pack-putaway', {
mixins: [ScenarioBaseMixin, GenericStatesMixin],
template: `
<Screen title="Single pack putaway">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {ScenarioBaseMixin, GenericStatesMixin} from "./mixins.js";

Vue.component('single-pack-transfer', {
export var SinglePackTransfer = Vue.component('single-pack-transfer', {
mixins: [ScenarioBaseMixin, GenericStatesMixin],
template: `
<Screen title="Single pack transfer">
Expand Down
2 changes: 1 addition & 1 deletion shopfloor_mobile/static/wms/src/services/odoo.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export class OdooMocked extends OdooMixin{
window.DEMO_CASE = window.DEMO_CASES[this.usage][barcode]
if (!window.DEMO_CASE) {
return Promise.resolve({
"message": {"message_type": "error", "body": "Unknown barcode"}
"message": {"message_type": "error", "message": "Unknown barcode"}
})
}
let res = window.DEMO_CASE['fetch'];
Expand Down
Loading

0 comments on commit 8ca8fec

Please sign in to comment.