start to properly use vuex

This commit is contained in:
Jakob Schrettenbrunner 2018-06-04 00:45:01 +02:00
parent 20472a903c
commit 58ad7a4b27
12 changed files with 1207 additions and 156 deletions

View File

@ -1,8 +1,8 @@
{
"presets": ["es2015"],
"compact": true,
"minified": true,
"only": "public/themes/pterodactyl/js/frontend/files/src/*.js",
"sourceMaps": "inline",
"comments": false
"presets": [
"@babel/preset-env"
],
"plugins": [
["@babel/plugin-proposal-object-rest-spread", { "useBuiltIns": true }]
]
}

View File

@ -58,16 +58,8 @@ function styles() {
*/
function scripts() {
return webpackStream(webpackConfig)
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(through.obj(function (file, enc, cb) { // Remove Souremaps
if (!/\.map$/.test(file.path)) this.push(file);
cb();
}))
.pipe(babel())
.pipe(gulpif(argv.production, uglify()))
.pipe(concat('bundle.js'))
.pipe(rev())
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(paths.scripts.dest))
.pipe(rev.manifest(paths.manifest + '/manifest.json', {merge: true, base: paths.manifest}))
.pipe(gulp.dest(paths.manifest));
@ -78,11 +70,11 @@ function scripts() {
*/
function watch() {
gulp.watch(['./resources/assets/styles/**/*.css'], gulp.series(function cleanStyles() {
return del(['./public/assets/css/**/*.css']);
return del(['./public/assets/css/**/*.{css,map}']);
}, styles));
gulp.watch(paths.scripts.watch, gulp.series(function cleanScripts() {
return del(['./public/assets/scripts/**/*.js']);
return del(['./public/assets/scripts/**/*.{js,map}']);
}, scripts));
}

1081
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,19 @@
{
"name": "pterodactyl-panel",
"devDependencies": {
"@babel/core": "^7.0.0-beta.49",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta.49",
"@babel/plugin-transform-async-to-generator": "^7.0.0-beta.49",
"@babel/plugin-transform-runtime": "^7.0.0-beta.49",
"@babel/preset-env": "^7.0.0-beta.49",
"@fortawesome/fontawesome": "^1.1.8",
"@fortawesome/fontawesome-free-solid": "^5.0.13",
"@fortawesome/vue-fontawesome": "0.0.22",
"autoprefixer": "^8.2.0",
"axios": "^0.18.0",
"babel-cli": "6.18.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"babel-core": "^6.26.3",
"babel-loader": "^8.0.0-beta.3",
"babel-plugin-transform-object-assign": "^6.22.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-plugin-transform-strict-mode": "^6.18.0",
@ -63,5 +68,8 @@
"build:components": "./node_modules/gulp-cli/bin/gulp.js components",
"build:styles": "./node_modules/gulp-cli/bin/gulp.js styles",
"build:scripts": "./node_modules/gulp-cli/bin/gulp.js scripts"
},
"dependencies": {
"vuex-router-sync": "^5.0.0"
}
}

View File

@ -14,20 +14,25 @@ import FontAwesomeIcon from '@fortawesome/vue-fontawesome';
fontawesome.library.add(faSolid);
import { routes } from './routes';
import { storeData } from './store';
import createStore from './store';
window.events = new Vue;
window.Ziggy = Ziggy;
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history', routes
});
Vue.use(Vuex);
const store = new Vuex.Store(storeData);
const store = createStore(router);
const route = require('./../../../vendor/tightenco/ziggy/src/js/route').default;
Vue.config.productionTip = false;
Vue.mixin({ methods: { route } });
Vue.mixin(flash);
Vue.use(VueRouter);
Vue.use(vuexI18n.plugin, store);
Vue.i18n.add('en', Locales.en);
@ -35,9 +40,6 @@ Vue.i18n.set('en');
Vue.component('font-awesome-icon', FontAwesomeIcon);
const router = new VueRouter({
mode: 'history', routes
});
require('./bootstrap');

View File

@ -11,16 +11,16 @@
ref="search"
/>
</div>
<div v-if="this.loading" class="my-4 animate fadein">
<div v-if="this.isServersLoading" class="my-4 animate fadein">
<div class="text-center h-16">
<span class="spinner spinner-xl"></span>
</div>
</div>
<transition-group class="w-full m-auto mt-4 animate fadein sm:flex flex-wrap content-start" v-else>
<transition-group class="w-full m-auto mt-4 animate fadein sm:flex flex-wrap content-start">
<server-box
v-for="(server, index) in servers.models"
v-bind:key="index"
v-bind:server="server"
v-for="(server, index) in this.serverList"
:key="index"
:server="server"
/>
</transition-group>
</div>
@ -29,11 +29,11 @@
<script>
import { DateTime } from 'luxon';
import { ServerCollection } from '../../models/server';
import _ from 'lodash';
import Flash from '../Flash';
import ServerBox from './ServerBox';
import Navigation from '../core/Navigation';
import {mapGetters, mapState} from 'vuex'
export default {
name: 'dashboard',
@ -41,18 +41,24 @@
data: function () {
return {
backgroundedAt: DateTime.local(),
documentVisible: true,
loading: true,
search: '',
servers: new ServerCollection,
}
},
computed: {
...mapGetters([
'isServersLoading',
'serverList'
]),
...mapState({
servers: 'servers'
})
},
/**
* Start loading the servers before the DOM $.el is created.
*/
created: function () {
this.loadServers();
this.$store.dispatch('loadServers')
document.addEventListener('visibilitychange', () => {
this.documentVisible = document.visibilityState === 'visible';
@ -69,44 +75,6 @@
},
methods: {
/**
* Load the user's servers and render them onto the dashboard.
*
* @param {string} query
*/
loadServers: function (query = '') {
this.loading = true;
window.axios.get(this.route('api.client.index'), {
params: { query },
})
.finally(() => {
this.clearFlashes();
})
.then(response => {
this.servers = new ServerCollection;
response.data.data.forEach(obj => {
this.getResourceUse(
this.servers.add(obj.attributes)
);
});
if (this.servers.models.length === 0) {
this.info(this.$t('dashboard.index.no_matches'));
}
})
.catch(err => {
console.error(err);
const response = err.response;
if (response.data && _.isObject(response.data.errors)) {
response.data.errors.forEach(function (error) {
this.error(error.detail);
});
}
})
.finally(() => {
this.loading = false;
});
},
/**
* Handle a search for servers but only call the search function every 500ms

View File

@ -0,0 +1,6 @@
const LoadingState = {
LOADING: 'loading',
DONE: 'done',
ERROR: 'error',
};
export default LoadingState;

View File

@ -3,10 +3,10 @@ import Login from './components/auth/Login';
import Dashboard from './components/dashboard/Dashboard';
import Account from './components/dashboard/Account';
import ResetPassword from './components/auth/ResetPassword';
import { Server, ServerConsole, ServerAllocations, ServerDatabases, ServerFiles, ServerSchedules, ServerSettings, ServerSubusers } from './components/server';
import {
Server, ServerAllocations, ServerConsole,
Server,
ServerAllocations,
ServerConsole,
ServerDatabases,
ServerFiles,
ServerSchedules,
@ -32,7 +32,7 @@ export const routes = [
{ name : 'account.api', path: '/account/api', component: Account },
{ name : 'account.security', path: '/account/security', component: Account },
{ path: '/server/:id', component: Server,
{ path: '/server/:serverID', component: Server,
children: [
{ name: 'server', path: '', component: ServerConsole },
{ name: 'server-files', path: 'files', component: ServerFiles },

View File

@ -1,38 +0,0 @@
import { User } from './models/user';
export const storeData = {
state: {
user: null,
},
actions: {
login: function ({ commit }) {
commit('login');
},
logout: function ({ commit }) {
commit('logout');
},
},
getters: {
getCurrentUser: function (state) {
if (!(state.user instanceof User)) {
state.user = User.fromJWT(localStorage.getItem('token'));
}
return state.user;
},
},
mutations: {
/**
* Log in a user and store them in vuex using the local storage token.
*
* @param state
*/
login: function (state) {
state.user = User.fromJWT(localStorage.getItem('token'));
},
logout: function (state) {
console.log('logout');
state.user = null;
}
}
};

View File

@ -0,0 +1,18 @@
import Vuex from 'vuex';
import { sync } from 'vuex-router-sync';
import { serverModule } from "./modules/server";
import { userModule } from './modules/user'
const createStore = (router) => {
const store = new Vuex.Store({
//strict: process.env.NODE_ENV !== 'production',
modules: {
userModule,
serverModule,
},
});
sync(store, router);
return store;
};
export default createStore;

View File

@ -0,0 +1,64 @@
import LoadingState from '../../models/loadingStates';
import route from '../../../../../vendor/tightenco/ziggy/src/js/route';
export const serverModule = {
state: {
servers: {},
serverIDs: [],
currentServerID: '',
serverLoadingState: '',
},
mutations: {
setCurrentServer (state, serverID) {
state.currentServerID = serverID;
},
setServers (state, servers) {
servers.forEach(s => {
state.servers[s.identifier] = s;
if (!!state.serverIDs.indexOf(s.identifier)) {
state.serverIDs.push(s.identifier)
}
});
},
removeServer (state, serverID) {
delete state.servers[serverID];
state.serverIDs.remove(serverID);
},
setServerLoadingState (state, s) {
state.serverLoadingState = s;
}
},
actions: {
loadServers({ commit }) {
commit('setServerLoadingState', LoadingState.LOADING);
window.axios.get(route('api.client.index'))
.then(response => {
commit('setServers', response.data.data.map(o => o.attributes));
commit('setServerLoadingState', LoadingState.DONE);
})
.catch(err => {
console.error(err);
const response = err.response;
if (response.data && _.isObject(response.data.errors)) {
response.data.errors.forEach(function (error) {
this.error(error.detail);
});
}
})
.finally(() => {
this.loading = false;
});
},
},
getters: {
currentServer (state) {
return state.servers[state.route.params.serverID];
},
isServersLoading (state) {
return state.serverLoadingState === LoadingState.LOADING;
},
serverList (state) {
return state.serverIDs.map(k => state.servers[k]);
}
}
};

View File

@ -0,0 +1,34 @@
import {User} from "../../models/user";
export const userModule = {
state: {
user: null,
},
actions: {
login ({ commit }) {
commit('setUser', User.fromJWT(localStorage.getItem('token')));
},
logout ({ commit }) {
commit('unsetUser');
}
},
getters: {
getCurrentUser: function (state) {
return state.user;
},
},
mutations: {
/**
* Log in a user and store them in vuex using the local storage token.
*
* @param state
* @param user
*/
setUser: function (state, user) {
state.user = user;
},
unsetUser: function (state) {
state.user = null;
}
}
};