Allow login to multiple bots

This commit is contained in:
Matthias 2021-08-29 10:29:53 +02:00
parent acd702dab3
commit 0955c21082
7 changed files with 79 additions and 12 deletions

View File

@ -0,0 +1,29 @@
<template>
<div>
<h3>Available bots</h3>
<div v-for="bot in allAvailableBots" :key="bot">
{{ bot }}
</div>
<LoginModal login-text="Add new bot" />
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { namespace } from 'vuex-class';
import { MultiBotStoreGetters } from '@/store/modules/botStoreWrapper';
import LoginModal from '@/views/LoginModal.vue';
const ftbot = namespace('ftbot');
@Component({ components: { LoginModal } })
export default class BotList extends Vue {
@ftbot.Getter [MultiBotStoreGetters.allAvailableBots]: string[];
clickAddBot() {
//
}
}
</script>
<style scoped></style>

View File

@ -60,17 +60,23 @@
<script lang="ts"> <script lang="ts">
import { Component, Vue, Emit, Prop } from 'vue-property-decorator'; import { Component, Vue, Emit, Prop } from 'vue-property-decorator';
import { Action } from 'vuex-class'; import { Action, namespace } from 'vuex-class';
import userService from '@/shared/userService'; import { useUserService } from '@/shared/userService';
import { AuthPayload } from '@/types'; import { AuthPayload } from '@/types';
import { MultiBotStoreGetters } from '@/store/modules/botStoreWrapper';
const defaultURL = window.location.origin || 'http://localhost:8080'; const defaultURL = window.location.origin || 'http://localhost:8080';
const ftbot = namespace('ftbot');
@Component({}) @Component({})
export default class Login extends Vue { export default class Login extends Vue {
@Action setLoggedIn; @Action setLoggedIn;
@ftbot.Getter [MultiBotStoreGetters.nextBotId]: string;
@ftbot.Action addBot;
@Prop({ default: false }) inModal!: boolean; @Prop({ default: false }) inModal!: boolean;
$refs!: { $refs!: {
@ -126,11 +132,12 @@ export default class Login extends Vue {
return; return;
} }
this.errorMessage = ''; this.errorMessage = '';
const userService = useUserService(this.nextBotId);
// Push the name to submitted names // Push the name to submitted names
userService userService
.login(this.auth) .login(this.auth)
.then(() => { .then(() => {
this.setLoggedIn(true); this.addBot(this.nextBotId);
// TODO: Investigate how this needs to be done properly // TODO: Investigate how this needs to be done properly
// setBaseUrl(userService.getAPIUrl()); // setBaseUrl(userService.getAPIUrl());

View File

@ -17,7 +17,7 @@ export class UserService {
* Stores info for current botId in the object of all bots. * Stores info for current botId in the object of all bots.
*/ */
private storeLoginInfo(loginInfo: AuthStorage): void { private storeLoginInfo(loginInfo: AuthStorage): void {
const allInfo = this.getAllLoginInfos(); const allInfo = UserService.getAllLoginInfos();
allInfo[this.botId] = loginInfo; allInfo[this.botId] = loginInfo;
localStorage.setItem(AUTH_LOGIN_INFO, JSON.stringify(allInfo)); localStorage.setItem(AUTH_LOGIN_INFO, JSON.stringify(allInfo));
} }
@ -26,7 +26,7 @@ export class UserService {
* Logout - removing info for this particular bot. * Logout - removing info for this particular bot.
*/ */
private removeLoginInfo(): void { private removeLoginInfo(): void {
const info = this.getAllLoginInfos(); const info = UserService.getAllLoginInfos();
delete info[this.botId]; delete info[this.botId];
localStorage.setItem(AUTH_LOGIN_INFO, JSON.stringify(info)); localStorage.setItem(AUTH_LOGIN_INFO, JSON.stringify(info));
} }
@ -41,7 +41,7 @@ export class UserService {
* Retrieve full logininfo object (for all registered bots) * Retrieve full logininfo object (for all registered bots)
* @returns * @returns
*/ */
private getAllLoginInfos(): AuthStorageMulti { private static getAllLoginInfos(): AuthStorageMulti {
const info = JSON.parse(localStorage.getItem(AUTH_LOGIN_INFO) || '{}'); const info = JSON.parse(localStorage.getItem(AUTH_LOGIN_INFO) || '{}');
return info; return info;
} }
@ -51,7 +51,7 @@ export class UserService {
* @returns Login Info object * @returns Login Info object
*/ */
private getLoginInfo(): AuthStorage { private getLoginInfo(): AuthStorage {
const info = this.getAllLoginInfos(); const info = UserService.getAllLoginInfos();
if (this.botId in info && 'apiUrl' in info[this.botId] && 'refreshToken' in info[this.botId]) { if (this.botId in info && 'apiUrl' in info[this.botId] && 'refreshToken' in info[this.botId]) {
return info[this.botId]; return info[this.botId];
} }
@ -62,6 +62,11 @@ export class UserService {
}; };
} }
public static getAvailableBotList(): string[] {
const allInfo = UserService.getAllLoginInfos();
return Object.keys(allInfo);
}
public getAccessToken(): string { public getAccessToken(): string {
return this.getLoginInfo().accessToken; return this.getLoginInfo().accessToken;
} }
@ -183,4 +188,4 @@ export function useUserService(botId: string) {
return userservice; return userservice;
} }
export default useUserService('ftbot.0'); // export default useUserService('ftbot.0');

View File

@ -3,6 +3,7 @@ import Vuex from 'vuex';
import { getCurrentTheme, getTheme, storeCurrentTheme } from '@/shared/themes'; import { getCurrentTheme, getTheme, storeCurrentTheme } from '@/shared/themes';
import axios, { AxiosInstance } from 'axios'; import axios, { AxiosInstance } from 'axios';
import { UserService } from '@/shared/userService';
import createBotStore from './modules/botStoreWrapper'; import createBotStore from './modules/botStoreWrapper';
import { BotStoreGetters } from './modules/ftbot'; import { BotStoreGetters } from './modules/ftbot';
import alertsModule from './modules/alerts'; import alertsModule from './modules/alerts';
@ -142,5 +143,7 @@ const store = new Vuex.Store({
}); });
store.registerModule('ftbot', createBotStore(store)); store.registerModule('ftbot', createBotStore(store));
store.dispatch('ftbot/addBot', 'ftbot.0'); UserService.getAvailableBotList().forEach((e) => {
store.dispatch('ftbot/addBot', e);
});
export default store; export default store;

View File

@ -9,6 +9,7 @@ export enum MultiBotStoreGetters {
hasBots = 'hasBots', hasBots = 'hasBots',
selectedBot = 'selectedBot', selectedBot = 'selectedBot',
allAvailableBots = 'allAvailableBots', allAvailableBots = 'allAvailableBots',
nextBotId = 'nextBotId',
} }
export default function createBotStore(store) { export default function createBotStore(store) {
@ -28,6 +29,13 @@ export default function createBotStore(store) {
[MultiBotStoreGetters.allAvailableBots](state: FTMultiBotState): string[] { [MultiBotStoreGetters.allAvailableBots](state: FTMultiBotState): string[] {
return state.availableBots; return state.availableBots;
}, },
[MultiBotStoreGetters.nextBotId](state: FTMultiBotState): string {
let botCount = state.availableBots.length;
while (`ftbot.${botCount}` in state.availableBots) {
botCount += 1;
}
return `ftbot.${botCount}`;
},
}; };
// Autocreate getters // Autocreate getters
Object.keys(BotStoreGetters).forEach((e) => { Object.keys(BotStoreGetters).forEach((e) => {
@ -37,6 +45,13 @@ export default function createBotStore(store) {
}); });
const mutations = { const mutations = {
selectBot(state: FTMultiBotState, botId: string) {
if (botId in state.availableBots) {
state.selectedBot = botId;
} else {
console.warn(`Botid ${botId} not available, but selected`);
}
},
addBot(state: FTMultiBotState, botId: string) { addBot(state: FTMultiBotState, botId: string) {
state.availableBots = [...state.availableBots, botId]; state.availableBots = [...state.availableBots, botId];
}, },

View File

@ -1,5 +1,7 @@
<template> <template>
<div class="home"> <div class="home">
<bot-list />
<hr />
<!-- <img alt="Freqtrade logo" src="../assets/freqtrade-logo.png" width="450px" class="my-5" /> --> <!-- <img alt="Freqtrade logo" src="../assets/freqtrade-logo.png" width="450px" class="my-5" /> -->
<div alt="Freqtrade logo" class="logo-svg my-5 mx-auto" /> <div alt="Freqtrade logo" class="logo-svg my-5 mx-auto" />
<div> <div>
@ -19,7 +21,11 @@
<script lang="ts"> <script lang="ts">
import { Component, Vue } from 'vue-property-decorator'; import { Component, Vue } from 'vue-property-decorator';
@Component import BotList from '@/components/BotList.vue';
@Component({
components: { BotList },
})
export default class Home extends Vue {} export default class Home extends Vue {}
</script> </script>

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<b-button v-b-modal.modal-prevent-closing>Login</b-button> <b-button v-b-modal.modal-prevent-closing>{{ loginText }}</b-button>
<b-modal id="modal-prevent-closing" ref="modal" title="Submit Your Name" @ok="handleOk"> <b-modal id="modal-prevent-closing" ref="modal" title="Submit Your Name" @ok="handleOk">
<Login id="loginForm" ref="loginForm" in-modal /> <Login id="loginForm" ref="loginForm" in-modal />
</b-modal> </b-modal>
@ -8,7 +8,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue } from 'vue-property-decorator'; import { Component, Prop, Vue } from 'vue-property-decorator';
import Login from '@/components/Login.vue'; import Login from '@/components/Login.vue';
@ -20,6 +20,8 @@ export default class LoginModal extends Vue {
loginForm: HTMLFormElement; loginForm: HTMLFormElement;
}; };
@Prop({ required: false, default: 'Login', type: String }) loginText!: string;
resetLogin() { resetLogin() {
// this.$refs.loginForm.resetLogin(); // this.$refs.loginForm.resetLogin();
} }