Merge pull request #17 from h3poteto/iss-3

closes #3 Fix login page design
This commit is contained in:
AkiraFukushima 2018-03-10 23:21:48 +09:00 committed by GitHub
commit 1ea2497c2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 237 additions and 104 deletions

View File

@ -5,15 +5,12 @@ export default class Account {
this.db = db
}
listInstances () {
listAccounts () {
return new Promise((resolve, reject) => {
this.db.find({accessToken: { $ne: '' }}, (err, doc) => {
this.db.find({accessToken: { $ne: '' }}, (err, docs) => {
if (err) return reject(err)
if (empty(doc)) return reject(new EmptyRecordError('empty'))
const instances = doc.map((e, i, array) => {
return { baseURL: e.baseURL, id: e._id }
})
resolve(instances)
if (empty(docs)) return reject(new EmptyRecordError('empty'))
resolve(docs)
})
})
}
@ -29,7 +26,7 @@ export default class Account {
if (empty(doc)) return reject(new EmptyRecordError('empty'))
const instance = {
baseURL: doc.baseURL,
id: doc.id
id: doc._id
}
resolve(instance)
}

View File

@ -102,15 +102,15 @@ ipcMain.on('get-social-token', (event, _) => {
})
// nedb
ipcMain.on('list-instances', (event, _) => {
ipcMain.on('list-accounts', (event, _) => {
const account = new Account(db)
account.listInstances()
account.listAccounts()
.catch((err) => {
console.error(err)
event.sender.send('error-list-instances', err)
event.sender.send('error-list-accounts', err)
})
.then((instances) => {
event.sender.send('response-list-instances', instances)
.then((accounts) => {
event.sender.send('response-list-accounts', accounts)
})
})

View File

@ -1,6 +1,6 @@
<template>
<div id="authorize">
<el-form ref="form" :model="authorizeForm" label-width="120px" label-position="top">
<el-form ref="form" :model="authorizeForm" label-width="120px" label-position="top" class="authorize-form">
<el-form-item label="Please paste authorization code from your browser:">
<el-input v-model="authorizeForm.code"></el-input>
</el-form-item>
@ -35,7 +35,29 @@ export default {
<style lang="scss">
body { font-family: 'Source Sans Pro', sans-serif; }
html, body, #app, #authorize {
height: 100%;
margin: 0;
}
#authorize {
background-color: #292f3f;
color: #ffffff;
text-align: center;
.authorize-form {
width: 500px;
margin: 0 auto;
}
.el-form-item__label {
color: #f0f3f9;
}
.el-input__inner {
background-color: #373d48;
color: #ffffff;
border: 0;
}
}
</style>

View File

@ -2,17 +2,17 @@
<div id="global_header">
<el-menu
:default-active="defaultActive"
class="el-menu-vertical instance-menu"
@open="instanceSelected"
@close="instanceClosed"
class="el-menu-vertical account-menu"
@open="accountSelected"
@close="accountClosed"
:collapse="isCollapse"
:route="true"
background-color="#4a5664"
text-color="#909399"
active-text-color="#ffffff">
<el-menu-item :index="index.toString()" v-for="(instance, index) in instances" v-bind:key="instance.id" :route="{path: `/${instance.id}/home`}">
<el-menu-item :index="index.toString()" v-for="(account, index) in accounts" v-bind:key="account.id" :route="{path: `/${account.id}/home`}">
<i class="el-icon-menu"></i>
<span slot="title">{{ instance.baseURL }}</span>
<span slot="title">{{ account.baseURL }}</span>
</el-menu-item>
</el-menu>
<div class="space">
@ -34,23 +34,23 @@ export default {
},
computed: {
...mapState({
instances: state => state.GlobalHeader.instances
accounts: state => state.GlobalHeader.accounts
})
},
created () {
this.$store.dispatch('GlobalHeader/listInstances')
.then((instances) => {
return this.$router.push({ path: `/${instances[0].id}/home` })
this.$store.dispatch('GlobalHeader/listAccounts')
.then((accounts) => {
return this.$router.push({ path: `/${accounts[0]._id}/home` })
})
.catch(() => {
return this.$router.push({ path: '/login' })
})
},
methods: {
instanceSelected (key, keyPath) {
accountSelected (key, keyPath) {
console.log(key, keyPath)
},
instanceClosed (key, keyPath) {
accountClosed (key, keyPath) {
console.log(key, keyPath)
}
}
@ -66,7 +66,7 @@ html, body, #app, #global_header {
}
#global_header {
.instance-menu {
.account-menu {
height: 100%;
position: fixed;
top: 0;

View File

@ -1,74 +1,47 @@
<template>
<div id="login">
<el-form ref="instanceForm" label-width="120px" label-position="top">
<el-form-item label="Domain name">
<el-input v-model="instanceForm.domain"></el-input>
</el-form-item>
<el-form-item class="submit">
<el-button type="primary" @click="search">Search</el-button>
</el-form-item>
</el-form>
<el-form ref="loginForm" v-if="instances.length > 0" label-width="120px" label-position="top">
<el-form-item label="Select instance">
<el-radio-group v-model="loginForm.selectInstance" @change="changeInstance">
<el-radio class="instance-list" v-for="instance in instances" v-bind:key="instance.id" :label="instance.name" border></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item class="submit">
<el-button type="primary" @click="login" v-if="selectedInstance !== null">Login</el-button>
</el-form-item>
</el-form>
<instance-form v-if="page == 1"></instance-form>
<login-form v-if="page == 2"></login-form>
</div>
</template>
<script>
import InstanceForm from './Login/InstanceForm'
import LoginForm from './Login/LoginForm'
import { mapState } from 'vuex'
export default {
name: 'login',
data () {
return {
instanceForm: {
domain: ''
},
loginForm: {
selectInstance: ''
}
}
},
computed: {
...mapState({
instances: state => state.Login.instances,
selectedInstance: state => state.Login.selectedInstance
page: state => state.Login.page
})
},
created () {
},
methods: {
login () {
this.$store.dispatch('Login/fetchLogin', this.selectedInstance)
.then((url) => {
this.$router.push({ path: '/authorize' })
})
},
search () {
this.$store.dispatch('Login/searchInstance', this.instanceForm.domain)
},
changeInstance (value) {
this.$store.dispatch('Login/changeInstance', value)
}
}
components: { InstanceForm, LoginForm }
}
</script>
<style lang="scss">
body { font-family: 'Source Sans Pro', sans-serif; }
html, body, #app, #login {
height: 100%;
margin: 0;
}
#login {
background-color: #292f3f;
color: #ffffff;
text-align: center;
.instance-list {
display: block;
.el-form-item__label {
color: #f0f3f9;
}
.el-input__inner {
background-color: #373d48;
color: #ffffff;
border: 0;
}
}
</style>

View File

@ -0,0 +1,53 @@
<template>
<div id="instance_form">
<el-form ref="instanceForm" label-width="120px" label-position="top" class="instance-form">
<el-form-item label="Domain name">
<el-input v-model="instanceForm.domain" class="input"></el-input>
</el-form-item>
<el-form-item class="submit">
<el-button type="primary" @click="search">Search</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: 'instance-form',
data () {
return {
instanceForm: {
domain: ''
}
}
},
methods: {
search () {
const loading = this.$loading({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
this.$store.dispatch('Login/searchInstance', this.instanceForm.domain)
.then(() => {
loading.close()
this.$store.commit('Login/changePage', 2)
})
.catch(() => {
this.$message({
message: 'Could not search instance',
type: 'error'
})
})
}
}
}
</script>
<style lang="scss" scoped>
.instance-form {
width: 400px;
margin: 0 auto;
}
</style>

View File

@ -0,0 +1,72 @@
<template>
<div id="login_form">
<el-form ref="loginForm" label-width="120px" label-position="top">
<el-form-item label="Select instance">
<el-radio-group v-model="loginForm.selectInstance" @change="changeInstance" class="instance-group">
<el-radio class="instance-list" v-for="instance in instances" v-bind:key="instance.id" :label="instance.name" border></el-radio>
</el-radio-group>
</el-form-item>
<p v-if="instances.length === 0">Could not find instance</p>
<el-form-item class="submit">
<el-button type="text" class="back" @click="back"><icon name="chevron-left"></icon></el-button>
<el-button type="primary" class="login" @click="login" v-if="selectedInstance !== null">Login</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'login-form',
data () {
return {
loginForm: {
selectInstance: ''
}
}
},
computed: {
...mapState({
instances: state => state.Login.instances,
selectedInstance: state => state.Login.selectedInstance
})
},
methods: {
login () {
this.$store.dispatch('Login/fetchLogin', this.selectedInstance)
.then((url) => {
this.$router.push({ path: '/authorize' })
})
},
changeInstance (value) {
this.$store.dispatch('Login/changeInstance', value)
},
back () {
this.$store.dispatch('Login/pageBack')
}
}
}
</script>
<style lang="scss" scoped>
.instance-group {
width: 300px;
text-align: left;
margin: 0 auto;
}
.instance-list {
display: block;
width: 300px;
margin-left: 0 !important;
border-color: #606266;
color: #dcdfe6;
margin-bottom: 10px;
}
.back {
margin-right: 20px;
}
</style>

View File

@ -8,11 +8,11 @@ const Authorize = {
submit ({ commit }, code) {
return new Promise((resolve, reject) => {
ipcRenderer.send('get-access-token', code)
ipcRenderer.on('response-get-access-token', (event, id) => {
ipcRenderer.once('response-get-access-token', (event, id) => {
console.log(id)
resolve(id)
})
ipcRenderer.on('error-get-access-token', (event, err) => {
ipcRenderer.once('error-get-access-token', (event, err) => {
console.log(err)
})
})

View File

@ -3,23 +3,24 @@ import { ipcRenderer } from 'electron'
const GlobalHeader = {
namespaced: true,
state: {
instances: []
accounts: []
},
mutations: {
updateInstances (state, instances) {
state.instances = instances
updateAccounts (state, accounts) {
state.accounts = accounts
}
},
actions: {
listInstances ({ commit }) {
listAccounts ({ commit }) {
return new Promise((resolve, reject) => {
ipcRenderer.send('list-instances', 'list')
ipcRenderer.on('error-list-instances', (event, err) => {
ipcRenderer.send('list-accounts', 'list')
ipcRenderer.once('error-list-accounts', (event, err) => {
reject(err)
})
ipcRenderer.on('response-list-instances', (event, instances) => {
commit('updateInstances', instances)
resolve(instances)
ipcRenderer.once('response-list-accounts', (event, accounts) => {
commit('updateAccounts', accounts)
console.log(accounts)
resolve(accounts)
})
})
}

View File

@ -5,43 +5,58 @@ const Login = {
namespaced: true,
state: {
instances: [],
selectedInstance: null
selectedInstance: null,
page: 1
},
mutations: {
updateInstances (state, body) {
state.instances = body.instances
updateInstances (state, instances) {
state.instances = instances
},
changeInstance (state, instance) {
state.selectedInstance = instance
},
changePage (state, page) {
state.page = page
}
},
actions: {
searchInstance ({ commit }, domain) {
ipcRenderer.send('get-social-token', 'get')
ipcRenderer.on('response-get-social-token', (event, token) => {
axios
.get(`https://instances.social/api/1.0/instances/search?q=${domain}`, {
'headers': { 'Authorization': `Bearer ${token}` }
})
.then((res) => {
commit('updateInstances', res.data)
console.log(res.data)
})
console.log(domain)
return new Promise((resolve, reject) => {
ipcRenderer.send('get-social-token', 'get')
ipcRenderer.once('error-get-social-token', (event, err) => {
reject(err)
})
ipcRenderer.once('response-get-social-token', (event, token) => {
axios
.get(`https://instances.social/api/1.0/instances/search?q=${domain}`, {
'headers': { 'Authorization': `Bearer ${token}` }
})
.then((res) => {
commit('updateInstances', res.data.instances)
resolve(res)
})
})
})
},
fetchLogin ({ commit }, instance) {
return new Promise((resolve, reject) => {
ipcRenderer.send('get-auth-url', instance)
ipcRenderer.on('error-get-auth-url', (event, err) => {
ipcRenderer.once('error-get-auth-url', (event, err) => {
reject(err)
})
ipcRenderer.on('response-get-auth-url', (event, url) => {
ipcRenderer.once('response-get-auth-url', (event, url) => {
resolve(url)
})
})
},
changeInstance ({ commit }, instance) {
commit('changeInstance', instance)
},
pageBack ({ commit }) {
commit('changePage', 1)
commit('updateInstances', [])
commit('changeInstance', null)
}
}
}

View File

@ -21,21 +21,21 @@ const SideMenu = {
actions: {
fetchInstance ({ commit }, id) {
ipcRenderer.send('get-instance', id)
ipcRenderer.on('error-get-instance', (event, err) => {
ipcRenderer.once('error-get-instance', (event, err) => {
// TODO: handle error
console.log(err)
})
ipcRenderer.on('response-get-instance', (event, instance) => {
ipcRenderer.once('response-get-instance', (event, instance) => {
commit('updateInstance', instance)
})
},
username ({ commit }, id) {
return new Promise((resolve, reject) => {
ipcRenderer.send('get-local-account', id)
ipcRenderer.on('error-get-local-account', (event, err) => {
ipcRenderer.once('error-get-local-account', (event, err) => {
reject(err)
})
ipcRenderer.on('response-get-local-account', (event, account) => {
ipcRenderer.once('response-get-local-account', (event, account) => {
const client = new Mastodon(
{
access_token: account.accessToken,