UI fixes
This commit is contained in:
parent
cd6f408d39
commit
46e8c9376f
@ -6,11 +6,6 @@ class UsersController < ApplicationController
|
|||||||
skip_before_action :verify_authenticity_token, only: [:verify_login]
|
skip_before_action :verify_authenticity_token, only: [:verify_login]
|
||||||
|
|
||||||
def show
|
def show
|
||||||
if current_user
|
|
||||||
render json: { id: current_user.id, name: current_user.display_name, admin: current_user.admin? }
|
|
||||||
else
|
|
||||||
render json: nil
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def login
|
def login
|
||||||
@ -48,11 +43,15 @@ class UsersController < ApplicationController
|
|||||||
def create
|
def create
|
||||||
@user = User.new(user_params)
|
@user = User.new(user_params)
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
if @user.save
|
if @user.save
|
||||||
set_current_user(@user)
|
set_current_user(@user)
|
||||||
redirect_to root_path, notice: 'User was successfully created.'
|
format.html { redirect_to root_path, notice: 'User created.' }
|
||||||
|
format.json { render :show, status: :created, location: @user }
|
||||||
else
|
else
|
||||||
render action: :new
|
format.html { render :new }
|
||||||
|
format.json { render json: @user.errors, status: :unprocessable_entity }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -62,10 +61,15 @@ class UsersController < ApplicationController
|
|||||||
|
|
||||||
def update
|
def update
|
||||||
@user = current_user
|
@user = current_user
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
if @user.update(user_params)
|
if @user.update(user_params)
|
||||||
redirect_to root_path, notice: 'User account updated'
|
format.html { redirect_to root_path, notice: 'User updated.' }
|
||||||
|
format.json { render :show, status: :created, location: @user }
|
||||||
else
|
else
|
||||||
render action: 'edit'
|
format.html { render :edit }
|
||||||
|
format.json { render json: @user.errors, status: :unprocessable_entity }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -33,12 +33,6 @@
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
|
||||||
...mapMutations([
|
|
||||||
'setUser'
|
|
||||||
])
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
isLoading(val) {
|
isLoading(val) {
|
||||||
if (val) {
|
if (val) {
|
||||||
@ -51,7 +45,7 @@
|
|||||||
|
|
||||||
created() {
|
created() {
|
||||||
if (this.user === null && this.authChecked === false) {
|
if (this.user === null && this.authChecked === false) {
|
||||||
this.loadResource(api.getCurrentUser().then(user => this.setUser(user)));
|
this.checkAuthentication();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hard coded values taken directly from Bulma css
|
// Hard coded values taken directly from Bulma css
|
||||||
|
@ -13,14 +13,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="navbar-menu" :class="{ 'is-active': menuActive}">
|
<div class="navbar-menu" :class="{ 'is-active': menuActive}">
|
||||||
<div class="navbar-start">
|
<div class="navbar-start">
|
||||||
<a v-if="updateAvailable" href="#" @click.prevent="updateApp">UPDATE AVAILABLE!</a>
|
<a class="navbar-item" v-if="updateAvailable" href="#" @click.prevent="updateApp">UPDATE AVAILABLE!</a>
|
||||||
<router-link to="/" class="navbar-item">Recipes</router-link>
|
<router-link to="/" class="navbar-item">Recipes</router-link>
|
||||||
<router-link to="/ingredients" class="navbar-item">Ingredients</router-link>
|
<router-link to="/ingredients" class="navbar-item">Ingredients</router-link>
|
||||||
<router-link to="/calculator" class="navbar-item">Calculator</router-link>
|
<router-link to="/calculator" class="navbar-item">Calculator</router-link>
|
||||||
<router-link v-if="isLoggedIn" to="/logs" class="navbar-item">Log</router-link>
|
<router-link v-if="isLoggedIn" to="/logs" class="navbar-item">Log</router-link>
|
||||||
<router-link v-if="isLoggedIn" to="/notes" class="navbar-item">Notes</router-link>
|
<router-link v-if="isLoggedIn" to="/notes" class="navbar-item">Notes</router-link>
|
||||||
<router-link to="/about" class="navbar-item">About</router-link>
|
<router-link to="/about" class="navbar-item">About</router-link>
|
||||||
<a v-if="isAdmin" class="navbar-item" href="/admin/users">Admin</a>
|
<router-link v-if="isAdmin" to="/admin/users" class="navbar-item">Admin</router-link>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="navbar-end">
|
<div class="navbar-end">
|
||||||
@ -30,14 +30,17 @@
|
|||||||
{{ user.name }}
|
{{ user.name }}
|
||||||
</a>
|
</a>
|
||||||
<div class="navbar-dropdown is-boxed">
|
<div class="navbar-dropdown is-boxed">
|
||||||
<a class="navbar-item" href="#">
|
<router-link to="/user/edit" class="navbar-item">
|
||||||
Profile
|
Profile
|
||||||
</a>
|
</router-link>
|
||||||
<router-link to="/logout" class="navbar-item">Logout</router-link>
|
<router-link to="/logout" class="navbar-item">Logout</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<user-login></user-login>
|
<user-login class="navbar-link"></user-login>
|
||||||
|
<div class="navbar-dropdown is-boxed">
|
||||||
|
<router-link to="/user/new" class="navbar-item">Create Account</router-link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
21
app/javascript/components/AppValidationErrors.vue
Normal file
21
app/javascript/components/AppValidationErrors.vue
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="notification is-danger" v-if="errors !== null" v-for="(errs, prop) in errors">
|
||||||
|
{{ prop }}: {{ errs.join(", ") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
errors: {
|
||||||
|
required: false,
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
@ -2,6 +2,8 @@
|
|||||||
<div>
|
<div>
|
||||||
<h1 class="title">{{action}} {{ingredient.name || "[Unnamed Ingredient]"}}</h1>
|
<h1 class="title">{{action}} {{ingredient.name || "[Unnamed Ingredient]"}}</h1>
|
||||||
|
|
||||||
|
<app-validation-errors :errors="validationErrors"></app-validation-errors>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label is-small-mobile">Name</label>
|
<label class="label is-small-mobile">Name</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
@ -143,6 +145,11 @@
|
|||||||
required: true,
|
required: true,
|
||||||
type: Object
|
type: Object
|
||||||
},
|
},
|
||||||
|
validationErrors: {
|
||||||
|
required: false,
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
action: {
|
action: {
|
||||||
required: false,
|
required: false,
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
<h1 class="title">Creating Log for {{ log.recipe.name }}</h1>
|
<h1 class="title">Creating Log for {{ log.recipe.name }}</h1>
|
||||||
|
|
||||||
|
<app-validation-errors :errors="validationErrors"></app-validation-errors>
|
||||||
|
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<app-date-picker v-model="log.date" label="Date"></app-date-picker>
|
<app-date-picker v-model="log.date" label="Date"></app-date-picker>
|
||||||
@ -38,7 +40,12 @@
|
|||||||
log: {
|
log: {
|
||||||
required: true,
|
required: true,
|
||||||
type: Object
|
type: Object
|
||||||
}
|
},
|
||||||
|
validationErrors: {
|
||||||
|
required: false,
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
|
15
app/javascript/components/TheAdminUserEditor.vue
Normal file
15
app/javascript/components/TheAdminUserEditor.vue
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
55
app/javascript/components/TheAdminUserList.vue
Normal file
55
app/javascript/components/TheAdminUserList.vue
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<h1 class="title">User List</h1>
|
||||||
|
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Admin?</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="u in userList" :key="u.id">
|
||||||
|
<td>{{u.name}}</td>
|
||||||
|
<td>{{u.email}}</td>
|
||||||
|
<td>{{u.admin}}</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="button is-danger">X</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import api from "../lib/Api";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
userList: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.loadResource(
|
||||||
|
api.getAdminUserList()
|
||||||
|
.then(list => this.userList = list)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<ingredient-edit :ingredient="ingredient" action="Creating"></ingredient-edit>
|
<ingredient-edit :ingredient="ingredient" :validation-errors="validationErrors" action="Creating"></ingredient-edit>
|
||||||
|
|
||||||
<button type="button" class="button is-primary" @click="save">Save</button>
|
<button type="button" class="button is-primary" @click="save">Save</button>
|
||||||
<router-link class="button is-secondary" to="/ingredients">Cancel</router-link>
|
<router-link class="button is-secondary" to="/ingredients">Cancel</router-link>
|
||||||
@ -51,12 +51,13 @@
|
|||||||
lipids: null,
|
lipids: null,
|
||||||
ingredient_units: []
|
ingredient_units: []
|
||||||
},
|
},
|
||||||
validationErrors: null
|
validationErrors: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
save() {
|
save() {
|
||||||
|
this.validationErrors = {}
|
||||||
this.loadResource(
|
this.loadResource(
|
||||||
api.postIngredient(this.ingredient)
|
api.postIngredient(this.ingredient)
|
||||||
.then(() => this.$router.push('/ingredients'))
|
.then(() => this.$router.push('/ingredients'))
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
Loading...
|
Loading...
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<ingredient-edit :ingredient="ingredient"></ingredient-edit>
|
<ingredient-edit :ingredient="ingredient" :validation-errors="validationErrors"></ingredient-edit>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" class="button is-primary" @click="save">Save</button>
|
<button type="button" class="button is-primary" @click="save">Save</button>
|
||||||
@ -25,7 +25,7 @@
|
|||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
ingredient: null,
|
ingredient: null,
|
||||||
validationErrors: null
|
validationErrors: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
save() {
|
save() {
|
||||||
|
this.validationErrors = {};
|
||||||
this.loadResource(
|
this.loadResource(
|
||||||
api.patchIngredient(this.ingredient)
|
api.patchIngredient(this.ingredient)
|
||||||
.then(() => this.$router.push({name: 'ingredient', params: {id: this.ingredientId }}))
|
.then(() => this.$router.push({name: 'ingredient', params: {id: this.ingredientId }}))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<log-edit v-if="log.recipe !== null" :log="log">
|
<log-edit v-if="log.recipe !== null" :log="log" :validation-errors="validationErrors">
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button type="button" class="button is-primary" @click="save">Save Log</button>
|
<button type="button" class="button is-primary" @click="save">Save Log</button>
|
||||||
<router-link class="button is-secondary" to="/">Cancel</router-link>
|
<router-link class="button is-secondary" to="/">Cancel</router-link>
|
||||||
@ -26,7 +26,7 @@
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
validationErrors: [],
|
validationErrors: {},
|
||||||
log: {
|
log: {
|
||||||
date: null,
|
date: null,
|
||||||
rating: null,
|
rating: null,
|
||||||
@ -45,6 +45,7 @@
|
|||||||
methods: {
|
methods: {
|
||||||
save() {
|
save() {
|
||||||
this.log.original_recipe_id = this.recipeId;
|
this.log.original_recipe_id = this.recipeId;
|
||||||
|
this.validationErrors = {};
|
||||||
|
|
||||||
this.loadResource(
|
this.loadResource(
|
||||||
api.postLog(this.log)
|
api.postLog(this.log)
|
||||||
@ -56,7 +57,7 @@
|
|||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.loadResource(
|
this.loadResource(
|
||||||
api.getRecipe(this.recipeId, data => this.log.recipe = data)
|
api.getRecipe(this.recipeId, null, null, null, data => this.log.recipe = data)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<log-edit v-if="log !== null" :log="log">
|
<log-edit v-if="log !== null" :log="log" :validation-errors="validationErrors">
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button type="button" class="button is-primary" @click="save">Save Log</button>
|
<button type="button" class="button is-primary" @click="save">Save Log</button>
|
||||||
<router-link class="button is-secondary" to="/">Cancel</router-link>
|
<router-link class="button is-secondary" to="/">Cancel</router-link>
|
||||||
@ -26,7 +26,7 @@
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
validationErrors: [],
|
validationErrors: {},
|
||||||
log: null
|
log: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
save() {
|
save() {
|
||||||
|
this.validationErrors = {};
|
||||||
this.loadResource(
|
this.loadResource(
|
||||||
api.patchLog(this.log)
|
api.patchLog(this.log)
|
||||||
.then(() => this.$router.push('/'))
|
.then(() => this.$router.push('/'))
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
<h1 class="title">Creating {{ recipe.name || "[Unamed Recipe]" }}</h1>
|
<h1 class="title">Creating {{ recipe.name || "[Unamed Recipe]" }}</h1>
|
||||||
|
|
||||||
|
<app-validation-errors :errors="validationErrors"></app-validation-errors>
|
||||||
|
|
||||||
<recipe-edit :recipe="recipe" action="Creating"></recipe-edit>
|
<recipe-edit :recipe="recipe" action="Creating"></recipe-edit>
|
||||||
|
|
||||||
<button type="button" class="button is-primary" @click="save">Save</button>
|
<button type="button" class="button is-primary" @click="save">Save</button>
|
||||||
@ -20,7 +22,7 @@
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
validationErrors: [],
|
validationErrors: {},
|
||||||
recipe: {
|
recipe: {
|
||||||
name: null,
|
name: null,
|
||||||
source: null,
|
source: null,
|
||||||
@ -37,6 +39,7 @@
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
save() {
|
save() {
|
||||||
|
this.validationErrors = {};
|
||||||
this.loadResource(
|
this.loadResource(
|
||||||
api.postRecipe(this.recipe)
|
api.postRecipe(this.recipe)
|
||||||
.then(() => this.$router.push('/'))
|
.then(() => this.$router.push('/'))
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<h1 class="title">Editing {{ recipe.name || "[Unamed Recipe]" }}</h1>
|
<h1 class="title">Editing {{ recipe.name || "[Unamed Recipe]" }}</h1>
|
||||||
|
|
||||||
|
<app-validation-errors :errors="validationErrors"></app-validation-errors>
|
||||||
|
|
||||||
<recipe-edit :recipe="recipe"></recipe-edit>
|
<recipe-edit :recipe="recipe"></recipe-edit>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -26,7 +29,7 @@
|
|||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
recipe: null,
|
recipe: null,
|
||||||
validationErrors: []
|
validationErrors: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -38,6 +41,7 @@
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
save() {
|
save() {
|
||||||
|
this.validationErrors = {};
|
||||||
this.loadResource(
|
this.loadResource(
|
||||||
api.patchRecipe(this.recipe)
|
api.patchRecipe(this.recipe)
|
||||||
.then(() => this.$router.push({name: 'recipe', params: {id: this.recipeId }}))
|
.then(() => this.$router.push({name: 'recipe', params: {id: this.recipeId }}))
|
||||||
|
57
app/javascript/components/TheUserCreator.vue
Normal file
57
app/javascript/components/TheUserCreator.vue
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<h1 class="title">Create New User</h1>
|
||||||
|
|
||||||
|
<app-validation-errors :errors="validationErrors"></app-validation-errors>
|
||||||
|
|
||||||
|
<user-edit :user-obj="userObj" action="Creating"></user-edit>
|
||||||
|
|
||||||
|
<button type="button" class="button is-primary" @click="save">Save</button>
|
||||||
|
<router-link class="button is-secondary" to="/">Cancel</router-link>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import UserEdit from "./UserEdit";
|
||||||
|
import api from "../lib/Api";
|
||||||
|
import * as Errors from '../lib/Errors';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
validationErrors: {},
|
||||||
|
userObj: {
|
||||||
|
username: '',
|
||||||
|
full_name: '',
|
||||||
|
email: '',
|
||||||
|
password: '',
|
||||||
|
password_confirmation: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
save() {
|
||||||
|
this.validationErrors = {};
|
||||||
|
this.loadResource(
|
||||||
|
api.postUser(this.userObj)
|
||||||
|
.then(() => this.checkAuthentication())
|
||||||
|
.then(() => this.$router.push('/'))
|
||||||
|
.catch(Errors.onlyFor(Errors.ApiValidationError, err => this.validationErrors = err.validationErrors()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
UserEdit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
77
app/javascript/components/TheUserEditor.vue
Normal file
77
app/javascript/components/TheUserEditor.vue
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<h1 class="title">Edit User</h1>
|
||||||
|
|
||||||
|
<app-validation-errors :errors="validationErrors"></app-validation-errors>
|
||||||
|
|
||||||
|
<user-edit v-if="userObj != null" :user-obj="userObj" action="Creating"></user-edit>
|
||||||
|
|
||||||
|
<button type="button" class="button is-primary" @click="save">Save</button>
|
||||||
|
<router-link class="button is-secondary" to="/">Cancel</router-link>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import UserEdit from "./UserEdit";
|
||||||
|
import api from "../lib/Api";
|
||||||
|
import * as Errors from '../lib/Errors';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
validationErrors: {},
|
||||||
|
userObj: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.refreshUser();
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
user() {
|
||||||
|
this.refreshUser();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
refreshUser() {
|
||||||
|
if (this.user) {
|
||||||
|
this.userObj = {
|
||||||
|
username: this.user.username,
|
||||||
|
full_name: this.user.full_name,
|
||||||
|
email: this.user.email,
|
||||||
|
password: '',
|
||||||
|
password_confirmation: ''
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.userObj = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
save() {
|
||||||
|
this.validationErrors = {};
|
||||||
|
this.loadResource(
|
||||||
|
api.patchUser(this.userObj)
|
||||||
|
.then(() => this.checkAuthentication())
|
||||||
|
.then(() => {
|
||||||
|
this.$router.push('/');
|
||||||
|
})
|
||||||
|
.catch(Errors.onlyFor(Errors.ApiValidationError, err => this.validationErrors = err.validationErrors()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
UserEdit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
26
app/javascript/components/UserEdit.vue
Normal file
26
app/javascript/components/UserEdit.vue
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<app-text-field label="Username" v-model="userObj.username"></app-text-field>
|
||||||
|
<app-text-field label="Name" v-model="userObj.full_name"></app-text-field>
|
||||||
|
<app-text-field label="Email" v-model="userObj.email"></app-text-field>
|
||||||
|
<app-text-field label="Password" v-model="userObj.password"></app-text-field>
|
||||||
|
<app-text-field label="Password Confirmation" v-model="userObj.password_confirmation"></app-text-field>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
userObj: {
|
||||||
|
required: true,
|
||||||
|
type: Object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -357,6 +357,38 @@ class Api {
|
|||||||
return this.patch("/logs/" + log.id, this.buildLogParams(log));
|
return this.patch("/logs/" + log.id, this.buildLogParams(log));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAdminUserList() {
|
||||||
|
return this.get("/admin/users");
|
||||||
|
}
|
||||||
|
|
||||||
|
postUser(userObj) {
|
||||||
|
const params = {
|
||||||
|
user: {
|
||||||
|
username: userObj.username,
|
||||||
|
full_name: userObj.full_name,
|
||||||
|
email: userObj.email,
|
||||||
|
password: userObj.password,
|
||||||
|
password_confirmation: userObj.password_confirmation
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.post("/user/", params);
|
||||||
|
}
|
||||||
|
|
||||||
|
patchUser(userObj) {
|
||||||
|
const params = {
|
||||||
|
user: {
|
||||||
|
username: userObj.username,
|
||||||
|
full_name: userObj.full_name,
|
||||||
|
email: userObj.email,
|
||||||
|
password: userObj.password,
|
||||||
|
password_confirmation: userObj.password_confirmation
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.patch("/user/", params);
|
||||||
|
}
|
||||||
|
|
||||||
postLogin(username, password) {
|
postLogin(username, password) {
|
||||||
const params = {
|
const params = {
|
||||||
username: username,
|
username: username,
|
||||||
|
@ -42,13 +42,13 @@ ApiValidationError.prototype = Object.assign(new ApiError(), {
|
|||||||
name: "ApiValidationError",
|
name: "ApiValidationError",
|
||||||
|
|
||||||
validationErrors: function() {
|
validationErrors: function() {
|
||||||
const errors = new Map();
|
const errors = {};
|
||||||
if (this.json) {
|
if (this.json) {
|
||||||
for (let key in this.json) {
|
for (let key in this.json) {
|
||||||
errors.set(key, this.json[key]);
|
errors[key] = this.json[key];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errors.set("base", ["unknown error"]);
|
errors["base"] = ["unknown error"];
|
||||||
}
|
}
|
||||||
return errors;
|
return errors;
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { mapGetters, mapMutations, mapState } from 'vuex';
|
import { mapGetters, mapMutations, mapState } from 'vuex';
|
||||||
|
import api from "../lib/Api";
|
||||||
|
|
||||||
Vue.mixin({
|
Vue.mixin({
|
||||||
computed: {
|
computed: {
|
||||||
@ -16,7 +17,8 @@ Vue.mixin({
|
|||||||
methods: {
|
methods: {
|
||||||
...mapMutations([
|
...mapMutations([
|
||||||
'setError',
|
'setError',
|
||||||
'setLoading'
|
'setLoading',
|
||||||
|
'setUser'
|
||||||
]),
|
]),
|
||||||
|
|
||||||
loadResource(promise) {
|
loadResource(promise) {
|
||||||
@ -25,6 +27,10 @@ Vue.mixin({
|
|||||||
return promise
|
return promise
|
||||||
.catch(err => this.setError(err))
|
.catch(err => this.setError(err))
|
||||||
.then(() => this.setLoading(false));
|
.then(() => this.setLoading(false));
|
||||||
|
},
|
||||||
|
|
||||||
|
checkAuthentication() {
|
||||||
|
return this.loadResource(api.getCurrentUser().then(user => this.setUser(user)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -21,6 +21,7 @@ import AppPager from "../components/AppPager";
|
|||||||
import AppRating from "../components/AppRating";
|
import AppRating from "../components/AppRating";
|
||||||
import AppTagEditor from "../components/AppTagEditor";
|
import AppTagEditor from "../components/AppTagEditor";
|
||||||
import AppTextField from "../components/AppTextField";
|
import AppTextField from "../components/AppTextField";
|
||||||
|
import AppValidationErrors from "../components/AppValidationErrors";
|
||||||
|
|
||||||
Vue.component("AppAutocomplete", AppAutocomplete);
|
Vue.component("AppAutocomplete", AppAutocomplete);
|
||||||
Vue.component("AppConfirm", AppConfirm);
|
Vue.component("AppConfirm", AppConfirm);
|
||||||
@ -33,6 +34,7 @@ Vue.component("AppPager", AppPager);
|
|||||||
Vue.component("AppRating", AppRating);
|
Vue.component("AppRating", AppRating);
|
||||||
Vue.component("AppTagEditor", AppTagEditor);
|
Vue.component("AppTagEditor", AppTagEditor);
|
||||||
Vue.component("AppTextField", AppTextField);
|
Vue.component("AppTextField", AppTextField);
|
||||||
|
Vue.component("AppValidationErrors", AppValidationErrors);
|
||||||
|
|
||||||
|
|
||||||
Vue.use(VueProgressBar, {
|
Vue.use(VueProgressBar, {
|
||||||
|
@ -20,6 +20,12 @@ import TheRecipeEditor from './components/TheRecipeEditor';
|
|||||||
import TheRecipeCreator from './components/TheRecipeCreator';
|
import TheRecipeCreator from './components/TheRecipeCreator';
|
||||||
import TheRecipeList from './components/TheRecipeList';
|
import TheRecipeList from './components/TheRecipeList';
|
||||||
|
|
||||||
|
import TheUserCreator from './components/TheUserCreator';
|
||||||
|
import TheUserEditor from './components/TheUserEditor';
|
||||||
|
|
||||||
|
import TheAdminUserList from './components/TheAdminUserList';
|
||||||
|
import TheAdminUserEditor from './components/TheAdminUserEditor';
|
||||||
|
|
||||||
Vue.use(Router);
|
Vue.use(Router);
|
||||||
|
|
||||||
const router = new Router({
|
const router = new Router({
|
||||||
@ -116,6 +122,30 @@ router.addRoutes(
|
|||||||
.then(() => next("/"));
|
.then(() => next("/"));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: "/user/new",
|
||||||
|
name: "new_user",
|
||||||
|
component: TheUserCreator
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/user/edit",
|
||||||
|
name: "edit_user",
|
||||||
|
component: TheUserEditor
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: "/admin/users",
|
||||||
|
name: "admin_users",
|
||||||
|
component: TheAdminUserList
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: "/admin/users/:id/edit",
|
||||||
|
name: "admin_edit_user",
|
||||||
|
component: TheAdminUserEditor
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '*',
|
path: '*',
|
||||||
component: The404Page
|
component: The404Page
|
||||||
|
5
app/views/admin/users/index.json.jbuilder
Normal file
5
app/views/admin/users/index.json.jbuilder
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
json.array! @users do |u|
|
||||||
|
json.extract! u, :id, :username, :full_name, :email, :admin
|
||||||
|
json.name u.display_name
|
||||||
|
end
|
@ -1,2 +1,8 @@
|
|||||||
|
|
||||||
json.ex
|
if current_user
|
||||||
|
json.extract! current_user, :id, :username, :email, :full_name, :admin
|
||||||
|
|
||||||
|
json.name current_user.display_name
|
||||||
|
else
|
||||||
|
json.nil!
|
||||||
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user