diff --git a/package.json b/package.json index 2bc0e7f38..a506cb6e3 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "lodash.debounce": "^4.0.6", "lodash.groupby": "^4.6.0", "vue": "^2.0.0", + "vue-router": "^2.3.0", "vuex": "^2.0.0" } } diff --git a/shells/dev/target/index.js b/shells/dev/target/index.js index 7d6197cec..72f93026c 100644 --- a/shells/dev/target/index.js +++ b/shells/dev/target/index.js @@ -6,6 +6,47 @@ import Counter from './Counter.vue' import Events from './Events.vue' import MyClass from './MyClass.js' +import IndexRoute from './router/IndexRoute.vue' +import RouteOne from './router/RouteOne.vue' +import RouteTwo from './router/RouteTwo.vue' +import RouteWithParams from './router/RouteWithParams.vue' +import NamedRoute from './router/NamedRoute.vue' +import RouteWithQuery from './router/RouteWithQuery.vue' +import RouteWithBeforeEnter from './router/RouteWithBeforeEnter.vue' +import RouteWithAlias from './router/RouteWithAlias.vue' +import RouteWithProps from './router/RouteWithProps.vue' + +import VueRouter from 'vue-router' + +Vue.use(VueRouter) + +const DynamicComponent = { + template: '
Hello from dynamic component
' +} + +const routes = [ + { path: '/route-one', component: RouteOne }, + { path: '/route-two', component: RouteTwo }, + { path: '/route-with-params/:username/:id', component: RouteWithParams }, + { path: '/route-named', component: NamedRoute, name: 'NamedRoute' }, + { path: '/route-with-query', component: RouteWithQuery }, + { path: '/route-with-before-enter', component: RouteWithBeforeEnter, beforeEnter: (to, from, next) => { + next() + }}, + { path: '/route-with-redirect', redirect: '/route-one' }, + { path: '/route-with-alias', component: RouteWithAlias, alias: '/this-is-the-alias' }, + { path: '/route-with-dynamic-component', component: DynamicComponent }, + { path: '/route-with-props', component: RouteWithProps, props: { + username: 'My Username', + id: 99 + }}, + { path: '/route-with-props-default', component: RouteWithProps } +] + +const router = new VueRouter({ + routes +}) + let items = [] for (var i = 0; i < 100; i++) { items.push({ id: i }) @@ -16,12 +57,14 @@ circular.self = circular new Vue({ store, + router, render (h) { return h('div', null, [ h(Counter), h(Target, {props:{msg: 'hi', ins: new MyClass()}}), h(Other), - h(Events) + h(Events), + h(IndexRoute) ]) }, data: { diff --git a/shells/dev/target/router/IndexRoute.vue b/shells/dev/target/router/IndexRoute.vue new file mode 100644 index 000000000..dc7d809c0 --- /dev/null +++ b/shells/dev/target/router/IndexRoute.vue @@ -0,0 +1,21 @@ + + + diff --git a/shells/dev/target/router/NamedRoute.vue b/shells/dev/target/router/NamedRoute.vue new file mode 100644 index 000000000..e68fd580b --- /dev/null +++ b/shells/dev/target/router/NamedRoute.vue @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/shells/dev/target/router/RouteOne.vue b/shells/dev/target/router/RouteOne.vue new file mode 100644 index 000000000..b131fd159 --- /dev/null +++ b/shells/dev/target/router/RouteOne.vue @@ -0,0 +1,11 @@ + + + diff --git a/shells/dev/target/router/RouteTwo.vue b/shells/dev/target/router/RouteTwo.vue new file mode 100644 index 000000000..ffa59b0ad --- /dev/null +++ b/shells/dev/target/router/RouteTwo.vue @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/shells/dev/target/router/RouteWithAlias.vue b/shells/dev/target/router/RouteWithAlias.vue new file mode 100644 index 000000000..0a67a2ec8 --- /dev/null +++ b/shells/dev/target/router/RouteWithAlias.vue @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/shells/dev/target/router/RouteWithBeforeEnter.vue b/shells/dev/target/router/RouteWithBeforeEnter.vue new file mode 100644 index 000000000..479291b0a --- /dev/null +++ b/shells/dev/target/router/RouteWithBeforeEnter.vue @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/shells/dev/target/router/RouteWithParams.vue b/shells/dev/target/router/RouteWithParams.vue new file mode 100644 index 000000000..0b8db1849 --- /dev/null +++ b/shells/dev/target/router/RouteWithParams.vue @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/shells/dev/target/router/RouteWithProps.vue b/shells/dev/target/router/RouteWithProps.vue new file mode 100644 index 000000000..34e7af10a --- /dev/null +++ b/shells/dev/target/router/RouteWithProps.vue @@ -0,0 +1,20 @@ + + + \ No newline at end of file diff --git a/shells/dev/target/router/RouteWithQuery.vue b/shells/dev/target/router/RouteWithQuery.vue new file mode 100644 index 000000000..759da6f26 --- /dev/null +++ b/shells/dev/target/router/RouteWithQuery.vue @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/src/backend/index.js b/src/backend/index.js index 023342665..4bfb18bad 100644 --- a/src/backend/index.js +++ b/src/backend/index.js @@ -4,6 +4,7 @@ import { highlight, unHighlight, getInstanceRect } from './highlighter' import { initVuexBackend } from './vuex' import { initEventsBackend } from './events' +import { initRouterBackend } from './router' import { stringify, classify, camelize } from '../util' import path from 'path' @@ -95,6 +96,9 @@ function connect () { bridge.send('ready', hook.Vue.version) console.log('[vue-devtools] Ready. Detected Vue v' + hook.Vue.version) scan() + + // router + initRouterBackend(hook.Vue, bridge, rootInstances) } /** diff --git a/src/backend/router.js b/src/backend/router.js new file mode 100644 index 000000000..a8fe59cb3 --- /dev/null +++ b/src/backend/router.js @@ -0,0 +1,19 @@ +import { stringify } from '../util' + +export function initRouterBackend (Vue, bridge, rootInstances) { + for (let i = 0; i < rootInstances.length; i++) { + if (rootInstances[i]._router) { + rootInstances[i]._router.afterEach((to, from) => { + bridge.send('router:changed', stringify({ + to, + from, + timestamp: Date.now() + })) + }) + bridge.send('router:init', stringify({ + routes: rootInstances[i]._router.options.routes, + mode: rootInstances[i]._router.mode + })) + } + } +} diff --git a/src/devtools/App.vue b/src/devtools/App.vue index 285bc401a..cb36da1bd 100644 --- a/src/devtools/App.vue +++ b/src/devtools/App.vue @@ -31,6 +31,13 @@ Events {{ newEventCount }} + + directions + Router + @@ -47,6 +54,7 @@ import ComponentsTab from './views/components/ComponentsTab.vue' import EventsTab from './views/events/EventsTab.vue' import VuexTab from './views/vuex/VuexTab.vue' +import RouterTab from './views/router/RouterTab.vue' import { mapState } from 'vuex' @@ -62,7 +70,8 @@ export default { components: { components: ComponentsTab, vuex: VuexTab, - events: EventsTab + events: EventsTab, + router: RouterTab }, computed: mapState({ message: state => state.message, diff --git a/src/devtools/common.styl b/src/devtools/common.styl index d9b54f50c..9f2530569 100644 --- a/src/devtools/common.styl +++ b/src/devtools/common.styl @@ -22,3 +22,47 @@ $dark-active-color = $active-color $dark-border-color = lighten($slate, 10%) $dark-background-color = $slate $dark-component-color = $active-color + +// Entries + +.no-entries + color: #ccc + text-align: center + margin-top: 50px + line-height: 30px + +.entry + position: relative; + font-family Menlo, Consolas, monospace + color #881391 + cursor pointer + padding 10px 20px + font-size 12px + background-color $background-color + box-shadow 0 1px 5px rgba(0,0,0,.12) + .entry-name + font-weight 600 + .entry-source + color #999 + .component-name + color $component-color + .entry-type + color #999 + margin-left 8px + &.active + color #fff + background-color $active-color + .time, .entry-type, .component-name + color lighten($active-color, 75%) + .entry-name + color: #fff + .entry-source + color #ddd + .app.dark & + background-color $dark-background-color + +.time + font-size 11px + color #999 + float right + margin-top 3px diff --git a/src/devtools/components/SplitPane.vue b/src/devtools/components/SplitPane.vue index ada80b318..6cf99bea2 100644 --- a/src/devtools/components/SplitPane.vue +++ b/src/devtools/components/SplitPane.vue @@ -45,27 +45,5 @@ export default { diff --git a/src/devtools/components/TriplePane.vue b/src/devtools/components/TriplePane.vue new file mode 100644 index 000000000..12b52fb80 --- /dev/null +++ b/src/devtools/components/TriplePane.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/src/devtools/components/splitPanes.styl b/src/devtools/components/splitPanes.styl new file mode 100644 index 000000000..2a5ba77c5 --- /dev/null +++ b/src/devtools/components/splitPanes.styl @@ -0,0 +1,22 @@ +.split-pane + display flex + height 100% + &.dragging + cursor ew-resize + +.left, .right, .middle + position relative + +.left, .middle + border-right 1px solid $border-color + .app.dark & + border-right 1px solid $dark-border-color + +.dragger + position absolute + z-index 99 + top 0 + bottom 0 + right -5px + width 10px + cursor ew-resize \ No newline at end of file diff --git a/src/devtools/index.js b/src/devtools/index.js index 84d53607e..5f8d9b806 100644 --- a/src/devtools/index.js +++ b/src/devtools/index.js @@ -83,6 +83,19 @@ function initApp (shell) { } }) + bridge.on('router:init', payload => { + store.commit('router/INIT', parse(payload)) + }) + + bridge.on('router:changed', payload => { + store.commit('router/CHANGED', parse(payload)) + }) + + // register filters + Vue.filter('formatTime', function (timestamp) { + return (new Date(timestamp)).toString().match(/\d\d:\d\d:\d\d/)[0] + }) + app = new Vue({ store, render (h) { diff --git a/src/devtools/store/index.js b/src/devtools/store/index.js index c14ebb1bd..2d6c66eaa 100644 --- a/src/devtools/store/index.js +++ b/src/devtools/store/index.js @@ -3,6 +3,7 @@ import Vuex from 'vuex' import components from 'views/components/module' import vuex from 'views/vuex/module' import events from 'views/events/module' +import router from 'views/router/module' Vue.use(Vuex) @@ -25,7 +26,8 @@ const store = new Vuex.Store({ modules: { components, vuex, - events + events, + router } }) @@ -35,14 +37,16 @@ if (module.hot) { module.hot.accept([ 'views/components/module', 'views/vuex/module', - 'views/events/module' + 'views/events/module', + 'views/router/module' ], () => { try { store.hotUpdate({ modules: { components: require('views/components/module').default, vuex: require('views/vuex/module').default, - events: require('views/events/module').default + events: require('views/events/module').default, + router: require('views/router/module').default } }) } catch (e) { diff --git a/src/devtools/views/events/EventsHistory.vue b/src/devtools/views/events/EventsHistory.vue index 039968e40..2ce790d14 100644 --- a/src/devtools/views/events/EventsHistory.vue +++ b/src/devtools/views/events/EventsHistory.vue @@ -15,7 +15,7 @@
-
+
No events found
(Recording is paused)
- {{ event.eventName }} - {{ event.type }} - + {{ event.eventName }} + {{ event.type }} + by < {{ event.instanceName }} @@ -70,57 +70,10 @@ export default { inspect: 'INSPECT', reset: 'RESET', toggleRecording: 'TOGGLE' - }), - filters: { - formatTime (timestamp) { - return (new Date(timestamp)).toString().match(/\d\d:\d\d:\d\d/)[0] - } - } + }) } diff --git a/src/devtools/views/router/RouteMeta.vue b/src/devtools/views/router/RouteMeta.vue new file mode 100644 index 000000000..199d69ec4 --- /dev/null +++ b/src/devtools/views/router/RouteMeta.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/src/devtools/views/router/RouterTab.vue b/src/devtools/views/router/RouterTab.vue new file mode 100644 index 000000000..7ee13e979 --- /dev/null +++ b/src/devtools/views/router/RouterTab.vue @@ -0,0 +1,36 @@ + + + diff --git a/src/devtools/views/router/RoutesHistory.vue b/src/devtools/views/router/RoutesHistory.vue new file mode 100644 index 000000000..b6c238892 --- /dev/null +++ b/src/devtools/views/router/RoutesHistory.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/src/devtools/views/router/RoutesList.vue b/src/devtools/views/router/RoutesList.vue new file mode 100644 index 000000000..644aa1f07 --- /dev/null +++ b/src/devtools/views/router/RoutesList.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/src/devtools/views/router/module.js b/src/devtools/views/router/module.js new file mode 100644 index 000000000..5cd937eca --- /dev/null +++ b/src/devtools/views/router/module.js @@ -0,0 +1,60 @@ +const state = { + hasRouter: false, + instances: [], + routeChanges: [], + inspectedIndex: -1, + filter: '' +} + +const mutations = { + 'INIT' (state, payload) { + state.instances = [] + state.routeChanges = [] + state.inspectedIndex = -1 + state.hasRouter = true + state.instances.push(payload) + }, + 'RESET' (state) { + state.routeChanges = [] + state.inspectedIndex = -1 + }, + 'CHANGED' (state, payload) { + state.routeChanges.push(payload) + if (!state.filter) { + state.inspectedIndex = state.routeChanges.length - 1 + } + }, + 'INSPECT' (state, index) { + state.inspectedIndex = index + }, + 'UPDATE_FILTER' (state, filter) { + state.filter = filter + } +} + +const getters = { + activeRouteChange: state => { + return state.routeChanges[state.inspectedIndex] + }, + filteredRoutes: state => { + return state.routeChanges.filter(routeChange => { + return routeChange.from.fullPath.indexOf(state.filter) > -1 || routeChange.to.fullPath.indexOf(state.filter) > -1 + }) + }, + routes: state => { + const routes = [] + state.instances.forEach(instance => { + instance.routes.forEach(route => { + routes.push(route) + }) + }) + return routes + } +} + +export default { + namespaced: true, + state, + mutations, + getters +}