mirror of
https://github.com/freqtrade/frequi.git
synced 2024-11-26 21:15:15 +00:00
pinia: add layout store
Navbar to composition API Trading.vue to composition API
This commit is contained in:
parent
2d91945662
commit
e1810eabbf
|
@ -38,6 +38,7 @@
|
|||
"vue-property-decorator": "^9.1.2",
|
||||
"vue-router": "^3.5.3",
|
||||
"vue-select": "^3.18.3",
|
||||
"vue2-helpers": "^1.1.7",
|
||||
"vuex": "^3.6.2",
|
||||
"vuex-composition-helpers": "^1.1.0"
|
||||
},
|
||||
|
|
|
@ -109,11 +109,11 @@ export default class TradeList extends Vue {
|
|||
|
||||
@Prop({ required: true }) trades!: Array<Trade>;
|
||||
|
||||
@Prop({ default: 'Trades' }) title!: string;
|
||||
@Prop({ default: 'Trades', type: String }) title!: string;
|
||||
|
||||
@Prop({ required: false, default: '' }) stakeCurrency!: string;
|
||||
|
||||
@Prop({ default: false }) activeTrades!: boolean;
|
||||
@Prop({ default: false, type: Boolean }) activeTrades!: boolean;
|
||||
|
||||
@Prop({ default: false }) showFilter!: boolean;
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
</template>
|
||||
<b-dropdown-item>V: {{ getUiVersion }}</b-dropdown-item>
|
||||
<router-link class="dropdown-item" to="/settings">Settings</router-link>
|
||||
<b-checkbox v-model="layoutLockedLocal" class="pl-5">Lock layout</b-checkbox>
|
||||
<b-checkbox v-model="layoutStore.layoutLocked" class="pl-5">Lock layout</b-checkbox>
|
||||
<b-dropdown-item @click="resetDynamicLayout">Reset Layout</b-dropdown-item>
|
||||
<router-link
|
||||
v-if="botCount === 1"
|
||||
|
@ -105,170 +105,163 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Watch } from 'vue-property-decorator';
|
||||
import LoginModal from '@/views/LoginModal.vue';
|
||||
import { Action, namespace, Getter } from 'vuex-class';
|
||||
import BootswatchThemeSelect from '@/components/BootswatchThemeSelect.vue';
|
||||
import { LayoutActions, LayoutGetters } from '@/store/modules/layout';
|
||||
import { BotStoreGetters } from '@/store/modules/ftbot';
|
||||
import Favico from 'favico.js';
|
||||
import { MultiBotStoreGetters } from '@/store/modules/botStoreWrapper';
|
||||
import ReloadControl from '@/components/ftbot/ReloadControl.vue';
|
||||
import BotEntry from '@/components/BotEntry.vue';
|
||||
import BotList from '@/components/BotList.vue';
|
||||
import { BotDescriptor } from '@/types';
|
||||
import StoreModules from '@/store/storeSubModules';
|
||||
|
||||
const ftbot = namespace(StoreModules.ftbot);
|
||||
const layoutNs = namespace(StoreModules.layout);
|
||||
import { defineComponent, ref, onBeforeUnmount, onMounted, watch } from '@vue/composition-api';
|
||||
import {
|
||||
useActions,
|
||||
useGetters,
|
||||
useNamespacedActions,
|
||||
useNamespacedGetters,
|
||||
} from 'vuex-composition-helpers';
|
||||
import { useRoute } from 'vue2-helpers/vue-router';
|
||||
import { OpenTradeVizOptions, useSettingsStore } from '@/stores/settings';
|
||||
import { useLayoutStore } from '@/stores/layout';
|
||||
|
||||
@Component({
|
||||
export default defineComponent({
|
||||
name: 'NavBar',
|
||||
components: { LoginModal, BootswatchThemeSelect, ReloadControl, BotEntry, BotList },
|
||||
})
|
||||
export default class NavBar extends Vue {
|
||||
pingInterval: number | null = null;
|
||||
setup() {
|
||||
const { getUiVersion } = useGetters(['getUiVersion']);
|
||||
const { setLoggedIn, loadUIVersion } = useActions(['setLoggedIn', 'loadUIVersion']);
|
||||
const { pingAll, allGetState, logout } = useNamespacedActions(StoreModules.ftbot, [
|
||||
'pingAll',
|
||||
'allGetState',
|
||||
'logout',
|
||||
]);
|
||||
const {
|
||||
isBotOnline,
|
||||
hasBots,
|
||||
botCount,
|
||||
botName,
|
||||
openTradeCount,
|
||||
canRunBacktest,
|
||||
selectedBotObj,
|
||||
} = useNamespacedGetters(StoreModules.ftbot, [
|
||||
BotStoreGetters.isBotOnline,
|
||||
MultiBotStoreGetters.hasBots,
|
||||
MultiBotStoreGetters.botCount,
|
||||
BotStoreGetters.botName,
|
||||
BotStoreGetters.openTradeCount,
|
||||
BotStoreGetters.canRunBacktest,
|
||||
MultiBotStoreGetters.selectedBotObj,
|
||||
]);
|
||||
|
||||
botSelectOpen = false;
|
||||
|
||||
@Action setLoggedIn;
|
||||
|
||||
@Action loadUIVersion;
|
||||
|
||||
@Getter getUiVersion!: string;
|
||||
|
||||
@ftbot.Action pingAll;
|
||||
|
||||
@ftbot.Action allGetState;
|
||||
|
||||
@ftbot.Action logout;
|
||||
|
||||
@ftbot.Getter [BotStoreGetters.isBotOnline]!: boolean;
|
||||
|
||||
@ftbot.Getter [MultiBotStoreGetters.hasBots]: boolean;
|
||||
|
||||
@ftbot.Getter [MultiBotStoreGetters.botCount]: number;
|
||||
|
||||
@ftbot.Getter [BotStoreGetters.botName]: string;
|
||||
|
||||
@ftbot.Getter [BotStoreGetters.openTradeCount]: number;
|
||||
|
||||
@ftbot.Getter [BotStoreGetters.canRunBacktest]!: boolean;
|
||||
|
||||
@ftbot.Getter [MultiBotStoreGetters.selectedBotObj]!: BotDescriptor;
|
||||
|
||||
@layoutNs.Getter [LayoutGetters.getLayoutLocked]: boolean;
|
||||
|
||||
@layoutNs.Action [LayoutActions.resetDashboardLayout];
|
||||
|
||||
@layoutNs.Action [LayoutActions.resetTradingLayout];
|
||||
|
||||
@layoutNs.Action [LayoutActions.setLayoutLocked];
|
||||
|
||||
openTradesInTitle: string = OpenTradeVizOptions.showPill;
|
||||
|
||||
favicon: Favico | undefined = undefined;
|
||||
|
||||
mounted() {
|
||||
const settingsStore = useSettingsStore();
|
||||
this.openTradesInTitle = settingsStore.openTradesInTitle;
|
||||
settingsStore.$subscribe((_, state) => {
|
||||
const needsUpdate = this.openTradesInTitle !== state.openTradesInTitle;
|
||||
this.openTradesInTitle = state.openTradesInTitle;
|
||||
if (needsUpdate) {
|
||||
this.setTitle();
|
||||
this.setOpenTradesAsPill(this.openTradeCount);
|
||||
const layoutStore = useLayoutStore();
|
||||
const route = useRoute();
|
||||
const favicon = ref<Favico | undefined>(undefined);
|
||||
const pingInterval = ref<number>();
|
||||
|
||||
const clickLogout = () => {
|
||||
logout();
|
||||
// TODO: This should be per bot
|
||||
setLoggedIn(false);
|
||||
};
|
||||
|
||||
const setOpenTradesAsPill = (tradeCount: number) => {
|
||||
if (!favicon) {
|
||||
favicon.value = new Favico({
|
||||
animation: 'none',
|
||||
// position: 'up',
|
||||
// fontStyle: 'normal',
|
||||
// bgColor: '#',
|
||||
// textColor: '#FFFFFF',
|
||||
});
|
||||
}
|
||||
if (tradeCount !== 0 && settingsStore.openTradesInTitle === 'showPill') {
|
||||
favicon.badge(tradeCount);
|
||||
} else {
|
||||
favicon.reset();
|
||||
console.log('reset');
|
||||
}
|
||||
};
|
||||
const resetDynamicLayout = (): void => {
|
||||
console.log(`resetLayout called for ${route?.fullPath}`);
|
||||
switch (route?.fullPath) {
|
||||
case '/trade':
|
||||
layoutStore.resetTradingLayout();
|
||||
break;
|
||||
case '/dashboard':
|
||||
layoutStore.resetDashboardLayout();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
};
|
||||
const setTitle = () => {
|
||||
let title = 'freqUI';
|
||||
if (settingsStore.openTradesInTitle === OpenTradeVizOptions.asTitle) {
|
||||
title = `(${openTradeCount}) ${title}`;
|
||||
}
|
||||
if (botName) {
|
||||
title = `${title} - ${botName}`;
|
||||
}
|
||||
document.title = title;
|
||||
};
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (pingInterval) {
|
||||
clearInterval(pingInterval.value);
|
||||
}
|
||||
});
|
||||
|
||||
this.pingAll();
|
||||
this.loadUIVersion();
|
||||
this.pingInterval = window.setInterval(this.pingAll, 60000);
|
||||
onMounted(() => {
|
||||
pingAll();
|
||||
loadUIVersion();
|
||||
pingInterval.value = window.setInterval(pingAll, 60000);
|
||||
if (hasBots) {
|
||||
// Query botstate - this will enable / disable certain modes
|
||||
allGetState();
|
||||
}
|
||||
});
|
||||
|
||||
if (this.hasBots) {
|
||||
// Query botstate - this will enable / disable certain modes
|
||||
this.allGetState();
|
||||
}
|
||||
}
|
||||
settingsStore.$subscribe((_, state) => {
|
||||
const needsUpdate = settingsStore.openTradesInTitle !== state.openTradesInTitle;
|
||||
if (needsUpdate) {
|
||||
setTitle();
|
||||
setOpenTradesAsPill(openTradeCount.value);
|
||||
}
|
||||
});
|
||||
|
||||
beforeDestroy() {
|
||||
if (this.pingInterval) {
|
||||
clearInterval(this.pingInterval);
|
||||
}
|
||||
}
|
||||
watch(botName, () => setTitle());
|
||||
watch(openTradeCount, () => {
|
||||
console.log('openTradeCount changed');
|
||||
if (settingsStore.openTradesInTitle === OpenTradeVizOptions.showPill) {
|
||||
setOpenTradesAsPill(openTradeCount.value);
|
||||
} else if (settingsStore.openTradesInTitle === OpenTradeVizOptions.asTitle) {
|
||||
setTitle();
|
||||
}
|
||||
});
|
||||
|
||||
clickLogout(): void {
|
||||
this.logout();
|
||||
// TODO: This should be per bot
|
||||
this.setLoggedIn(false);
|
||||
}
|
||||
|
||||
get layoutLockedLocal() {
|
||||
return this.getLayoutLocked;
|
||||
}
|
||||
|
||||
set layoutLockedLocal(value: boolean) {
|
||||
this.setLayoutLocked(value);
|
||||
}
|
||||
|
||||
setOpenTradesAsPill(tradeCount: number) {
|
||||
if (!this.favicon) {
|
||||
this.favicon = new Favico({
|
||||
animation: 'none',
|
||||
// position: 'up',
|
||||
// fontStyle: 'normal',
|
||||
// bgColor: '#',
|
||||
// textColor: '#FFFFFF',
|
||||
});
|
||||
}
|
||||
if (tradeCount !== 0 && this.openTradesInTitle === 'showPill') {
|
||||
this.favicon.badge(tradeCount);
|
||||
} else {
|
||||
this.favicon.reset();
|
||||
console.log('reset');
|
||||
}
|
||||
}
|
||||
|
||||
resetDynamicLayout(): void {
|
||||
const route = this.$router.currentRoute.path;
|
||||
console.log(`resetLayout called for ${route}`);
|
||||
switch (route) {
|
||||
case '/trade':
|
||||
this.resetTradingLayout();
|
||||
break;
|
||||
case '/dashboard':
|
||||
this.resetDashboardLayout();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
setTitle() {
|
||||
let title = 'freqUI';
|
||||
if (this.openTradesInTitle === OpenTradeVizOptions.asTitle) {
|
||||
title = `(${this.openTradeCount}) ${title}`;
|
||||
}
|
||||
if (this.botName) {
|
||||
title = `${title} - ${this.botName}`;
|
||||
}
|
||||
document.title = title;
|
||||
}
|
||||
|
||||
@Watch(BotStoreGetters.botName)
|
||||
botnameChanged() {
|
||||
this.setTitle();
|
||||
}
|
||||
|
||||
@Watch(BotStoreGetters.openTradeCount)
|
||||
openTradeCountChanged() {
|
||||
console.log('openTradeCount changed');
|
||||
if (this.openTradesInTitle === OpenTradeVizOptions.showPill) {
|
||||
this.setOpenTradesAsPill(this.openTradeCount);
|
||||
} else if (this.openTradesInTitle === OpenTradeVizOptions.asTitle) {
|
||||
this.setTitle();
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
setLoggedIn,
|
||||
loadUIVersion,
|
||||
getUiVersion,
|
||||
pingAll,
|
||||
allGetState,
|
||||
logout,
|
||||
favicon,
|
||||
isBotOnline,
|
||||
hasBots,
|
||||
botCount,
|
||||
botName,
|
||||
openTradeCount,
|
||||
canRunBacktest,
|
||||
selectedBotObj,
|
||||
clickLogout,
|
||||
resetDynamicLayout,
|
||||
setTitle,
|
||||
layoutStore,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -8,7 +8,6 @@ import { UiVersion } from '@/types';
|
|||
import StoreModules from '@/store/storeSubModules';
|
||||
import createBotStore, { MultiBotStoreGetters } from './modules/botStoreWrapper';
|
||||
import alertsModule from './modules/alerts';
|
||||
import layoutModule from './modules/layout';
|
||||
|
||||
Vue.use(Vuex);
|
||||
const initCurrentTheme = getCurrentTheme();
|
||||
|
@ -16,7 +15,6 @@ const initCurrentTheme = getCurrentTheme();
|
|||
const store = new Vuex.Store({
|
||||
modules: {
|
||||
[StoreModules.alerts]: alertsModule,
|
||||
[StoreModules.layout]: layoutModule,
|
||||
},
|
||||
state: {
|
||||
currentTheme: initCurrentTheme,
|
||||
|
|
|
@ -1,170 +0,0 @@
|
|||
import { GridItemData } from 'vue-grid-layout';
|
||||
|
||||
export enum TradeLayout {
|
||||
multiPane = 'g-multiPane',
|
||||
openTrades = 'g-openTrades',
|
||||
tradeHistory = 'g-tradeHistory',
|
||||
tradeDetail = 'g-tradeDetail',
|
||||
chartView = 'g-chartView',
|
||||
}
|
||||
|
||||
export enum DashboardLayout {
|
||||
dailyChart = 'g-dailyChart',
|
||||
botComparison = 'g-botComparison',
|
||||
allOpenTrades = 'g-allOpenTrades',
|
||||
cumChartChart = 'g-cumChartChart',
|
||||
tradesLogChart = 'g-TradesLogChart',
|
||||
}
|
||||
|
||||
export enum LayoutGetters {
|
||||
getDashboardLayoutSm = 'getDashboardLayoutSm',
|
||||
getDashboardLayout = 'getDashboardLayout',
|
||||
getTradingLayoutSm = 'getTradingLayoutSm',
|
||||
getTradingLayout = 'getTradingLayout',
|
||||
getLayoutLocked = 'getLayoutLocked',
|
||||
}
|
||||
|
||||
export enum LayoutActions {
|
||||
setDashboardLayout = 'setDashboardLayout',
|
||||
setTradingLayout = 'setTradingLayout',
|
||||
resetDashboardLayout = 'resetDashboardLayout',
|
||||
resetTradingLayout = 'resetTradingLayout',
|
||||
setLayoutLocked = 'setLayoutLocked',
|
||||
}
|
||||
|
||||
export enum LayoutMutations {
|
||||
setDashboardLayout = 'setDashboardLayout',
|
||||
setTradingLayout = 'setTradingLayout',
|
||||
setLayoutLocked = 'setLayoutLocked',
|
||||
}
|
||||
// Define default layouts
|
||||
const DEFAULT_TRADING_LAYOUT: GridItemData[] = [
|
||||
{ i: TradeLayout.multiPane, x: 0, y: 0, w: 3, h: 35 },
|
||||
{ i: TradeLayout.chartView, x: 3, y: 0, w: 9, h: 14 },
|
||||
{ i: TradeLayout.tradeDetail, x: 3, y: 19, w: 9, h: 6 },
|
||||
{ i: TradeLayout.openTrades, x: 3, y: 14, w: 9, h: 5 },
|
||||
{ i: TradeLayout.tradeHistory, x: 3, y: 25, w: 9, h: 10 },
|
||||
];
|
||||
|
||||
// Currently only multiPane is visible
|
||||
const DEFAULT_TRADING_LAYOUT_SM: GridItemData[] = [
|
||||
{ i: TradeLayout.multiPane, x: 0, y: 0, w: 12, h: 10 },
|
||||
{ i: TradeLayout.chartView, x: 0, y: 10, w: 12, h: 0 },
|
||||
{ i: TradeLayout.tradeDetail, x: 0, y: 19, w: 12, h: 0 },
|
||||
{ i: TradeLayout.openTrades, x: 0, y: 8, w: 12, h: 0 },
|
||||
{ i: TradeLayout.tradeHistory, x: 0, y: 25, w: 12, h: 0 },
|
||||
];
|
||||
|
||||
const DEFAULT_DASHBOARD_LAYOUT: GridItemData[] = [
|
||||
{ i: DashboardLayout.botComparison, x: 0, y: 0, w: 8, h: 6 } /* Bot Comparison */,
|
||||
{ i: DashboardLayout.dailyChart, x: 8, y: 0, w: 4, h: 6 },
|
||||
{ i: DashboardLayout.allOpenTrades, x: 0, y: 6, w: 8, h: 6 },
|
||||
{ i: DashboardLayout.cumChartChart, x: 8, y: 6, w: 4, h: 6 },
|
||||
{ i: DashboardLayout.tradesLogChart, x: 0, y: 12, w: 12, h: 4 },
|
||||
];
|
||||
|
||||
const DEFAULT_DASHBOARD_LAYOUT_SM: GridItemData[] = [
|
||||
{ i: DashboardLayout.botComparison, x: 0, y: 0, w: 12, h: 6 } /* Bot Comparison */,
|
||||
{ i: DashboardLayout.allOpenTrades, x: 0, y: 6, w: 12, h: 8 },
|
||||
{ i: DashboardLayout.dailyChart, x: 0, y: 14, w: 12, h: 6 },
|
||||
{ i: DashboardLayout.cumChartChart, x: 0, y: 20, w: 12, h: 6 },
|
||||
{ i: DashboardLayout.tradesLogChart, x: 0, y: 26, w: 12, h: 4 },
|
||||
];
|
||||
|
||||
const STORE_DASHBOARD_LAYOUT = 'ftDashboardLayout';
|
||||
const STORE_TRADING_LAYOUT = 'ftTradingLayout';
|
||||
const STORE_LAYOUT_LOCK = 'ftLayoutLocked';
|
||||
|
||||
function getLayoutLocked() {
|
||||
const fromStore = localStorage.getItem(STORE_LAYOUT_LOCK);
|
||||
if (fromStore) {
|
||||
return JSON.parse(fromStore);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getLayout(storageString: string, defaultLayout: GridItemData[]) {
|
||||
const fromStore = localStorage.getItem(storageString);
|
||||
if (fromStore) {
|
||||
return JSON.parse(fromStore);
|
||||
}
|
||||
|
||||
return JSON.parse(JSON.stringify(defaultLayout));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function finding a layout entry
|
||||
* @param gridLayout Array of grid layouts used in this layout. Must be passed to GridLayout, too.
|
||||
* @param name Name within the dashboard layout to find
|
||||
*/
|
||||
export function findGridLayout(gridLayout: GridItemData[], name: string): GridItemData {
|
||||
let layout = gridLayout.find((value) => value.i === name);
|
||||
if (!layout) {
|
||||
layout = { i: name, x: 0, y: 0, w: 4, h: 6 };
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
dashboardLayout: getLayout(STORE_DASHBOARD_LAYOUT, DEFAULT_DASHBOARD_LAYOUT),
|
||||
tradingLayout: getLayout(STORE_TRADING_LAYOUT, DEFAULT_TRADING_LAYOUT),
|
||||
layoutLocked: getLayoutLocked(),
|
||||
},
|
||||
|
||||
getters: {
|
||||
[LayoutGetters.getDashboardLayoutSm]() {
|
||||
return [...DEFAULT_DASHBOARD_LAYOUT_SM];
|
||||
},
|
||||
[LayoutGetters.getDashboardLayout](state) {
|
||||
return state.dashboardLayout;
|
||||
},
|
||||
[LayoutGetters.getTradingLayoutSm]() {
|
||||
return [...DEFAULT_TRADING_LAYOUT_SM];
|
||||
},
|
||||
[LayoutGetters.getTradingLayout](state) {
|
||||
return state.tradingLayout;
|
||||
},
|
||||
[LayoutGetters.getLayoutLocked](state) {
|
||||
return state.layoutLocked;
|
||||
},
|
||||
},
|
||||
|
||||
mutations: {
|
||||
[LayoutMutations.setDashboardLayout](state, layout) {
|
||||
state.dashboardLayout = layout;
|
||||
localStorage.setItem(STORE_DASHBOARD_LAYOUT, JSON.stringify(layout));
|
||||
},
|
||||
[LayoutMutations.setTradingLayout](state, layout) {
|
||||
state.tradingLayout = layout;
|
||||
localStorage.setItem(STORE_TRADING_LAYOUT, JSON.stringify(layout));
|
||||
},
|
||||
[LayoutMutations.setLayoutLocked](state, locked: boolean) {
|
||||
state.layoutLocked = locked;
|
||||
localStorage.setItem(STORE_LAYOUT_LOCK, JSON.stringify(locked));
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
[LayoutActions.setDashboardLayout]({ commit }, layout) {
|
||||
commit(LayoutMutations.setDashboardLayout, layout);
|
||||
},
|
||||
[LayoutActions.setTradingLayout]({ commit }, layout) {
|
||||
commit(LayoutMutations.setTradingLayout, layout);
|
||||
},
|
||||
[LayoutActions.setLayoutLocked]({ commit }, locked: boolean) {
|
||||
commit(LayoutMutations.setLayoutLocked, locked);
|
||||
},
|
||||
[LayoutActions.resetDashboardLayout]({ commit }) {
|
||||
commit(
|
||||
LayoutMutations.setDashboardLayout,
|
||||
JSON.parse(JSON.stringify(DEFAULT_DASHBOARD_LAYOUT)),
|
||||
);
|
||||
},
|
||||
|
||||
[LayoutActions.resetTradingLayout]({ commit }) {
|
||||
commit(LayoutMutations.setTradingLayout, JSON.parse(JSON.stringify(DEFAULT_TRADING_LAYOUT)));
|
||||
},
|
||||
},
|
||||
};
|
|
@ -2,7 +2,6 @@
|
|||
enum StoreModules {
|
||||
ftbot = 'ftbot',
|
||||
alerts = 'alerts',
|
||||
layout = 'layout',
|
||||
}
|
||||
|
||||
export default StoreModules;
|
||||
|
|
116
src/stores/layout.ts
Normal file
116
src/stores/layout.ts
Normal file
|
@ -0,0 +1,116 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import { GridItemData } from 'vue-grid-layout';
|
||||
|
||||
export enum TradeLayout {
|
||||
multiPane = 'g-multiPane',
|
||||
openTrades = 'g-openTrades',
|
||||
tradeHistory = 'g-tradeHistory',
|
||||
tradeDetail = 'g-tradeDetail',
|
||||
chartView = 'g-chartView',
|
||||
}
|
||||
|
||||
export enum DashboardLayout {
|
||||
dailyChart = 'g-dailyChart',
|
||||
botComparison = 'g-botComparison',
|
||||
allOpenTrades = 'g-allOpenTrades',
|
||||
cumChartChart = 'g-cumChartChart',
|
||||
tradesLogChart = 'g-TradesLogChart',
|
||||
}
|
||||
|
||||
// Define default layouts
|
||||
const DEFAULT_TRADING_LAYOUT: GridItemData[] = [
|
||||
{ i: TradeLayout.multiPane, x: 0, y: 0, w: 3, h: 35 },
|
||||
{ i: TradeLayout.chartView, x: 3, y: 0, w: 9, h: 14 },
|
||||
{ i: TradeLayout.tradeDetail, x: 3, y: 19, w: 9, h: 6 },
|
||||
{ i: TradeLayout.openTrades, x: 3, y: 14, w: 9, h: 5 },
|
||||
{ i: TradeLayout.tradeHistory, x: 3, y: 25, w: 9, h: 10 },
|
||||
];
|
||||
|
||||
// Currently only multiPane is visible
|
||||
const DEFAULT_TRADING_LAYOUT_SM: GridItemData[] = [
|
||||
{ i: TradeLayout.multiPane, x: 0, y: 0, w: 12, h: 10 },
|
||||
{ i: TradeLayout.chartView, x: 0, y: 10, w: 12, h: 0 },
|
||||
{ i: TradeLayout.tradeDetail, x: 0, y: 19, w: 12, h: 0 },
|
||||
{ i: TradeLayout.openTrades, x: 0, y: 8, w: 12, h: 0 },
|
||||
{ i: TradeLayout.tradeHistory, x: 0, y: 25, w: 12, h: 0 },
|
||||
];
|
||||
|
||||
const DEFAULT_DASHBOARD_LAYOUT: GridItemData[] = [
|
||||
{ i: DashboardLayout.botComparison, x: 0, y: 0, w: 8, h: 6 } /* Bot Comparison */,
|
||||
{ i: DashboardLayout.dailyChart, x: 8, y: 0, w: 4, h: 6 },
|
||||
{ i: DashboardLayout.allOpenTrades, x: 0, y: 6, w: 8, h: 6 },
|
||||
{ i: DashboardLayout.cumChartChart, x: 8, y: 6, w: 4, h: 6 },
|
||||
{ i: DashboardLayout.tradesLogChart, x: 0, y: 12, w: 12, h: 4 },
|
||||
];
|
||||
|
||||
const DEFAULT_DASHBOARD_LAYOUT_SM: GridItemData[] = [
|
||||
{ i: DashboardLayout.botComparison, x: 0, y: 0, w: 12, h: 6 } /* Bot Comparison */,
|
||||
{ i: DashboardLayout.allOpenTrades, x: 0, y: 6, w: 12, h: 8 },
|
||||
{ i: DashboardLayout.dailyChart, x: 0, y: 14, w: 12, h: 6 },
|
||||
{ i: DashboardLayout.cumChartChart, x: 0, y: 20, w: 12, h: 6 },
|
||||
{ i: DashboardLayout.tradesLogChart, x: 0, y: 26, w: 12, h: 4 },
|
||||
];
|
||||
|
||||
const STORE_LAYOUTS = 'ftLayoutSettings';
|
||||
|
||||
function migrateLayoutSettings() {
|
||||
const STORE_DASHBOARD_LAYOUT = 'ftDashboardLayout';
|
||||
const STORE_TRADING_LAYOUT = 'ftTradingLayout';
|
||||
const STORE_LAYOUT_LOCK = 'ftLayoutLocked';
|
||||
|
||||
// If new does not exist
|
||||
if (localStorage.getItem(STORE_LAYOUTS) === null) {
|
||||
console.log('Migrating dashboard settings');
|
||||
const layoutLocked = localStorage.getItem(STORE_LAYOUT_LOCK);
|
||||
const tradingLayout = localStorage.getItem(STORE_TRADING_LAYOUT);
|
||||
const dashboardLayout = localStorage.getItem(STORE_DASHBOARD_LAYOUT);
|
||||
|
||||
const res = {
|
||||
dashboardLayout: dashboardLayout,
|
||||
tradingLayout,
|
||||
layoutLocked,
|
||||
};
|
||||
localStorage.setItem(STORE_LAYOUTS, JSON.stringify(res));
|
||||
}
|
||||
localStorage.removeItem(STORE_LAYOUT_LOCK);
|
||||
localStorage.removeItem(STORE_TRADING_LAYOUT);
|
||||
localStorage.removeItem(STORE_DASHBOARD_LAYOUT);
|
||||
}
|
||||
migrateLayoutSettings();
|
||||
/**
|
||||
* Helper function finding a layout entry
|
||||
* @param gridLayout Array of grid layouts used in this layout. Must be passed to GridLayout, too.
|
||||
* @param name Name within the dashboard layout to find
|
||||
*/
|
||||
export function findGridLayout(gridLayout: GridItemData[], name: string): GridItemData {
|
||||
let layout = gridLayout.find((value) => value.i === name);
|
||||
if (!layout) {
|
||||
layout = { i: name, x: 0, y: 0, w: 4, h: 6 };
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
|
||||
export const useLayoutStore = defineStore('layoutStore', {
|
||||
state: () => {
|
||||
return {
|
||||
dashboardLayout: JSON.parse(JSON.stringify(DEFAULT_DASHBOARD_LAYOUT)),
|
||||
tradingLayout: JSON.parse(JSON.stringify(DEFAULT_TRADING_LAYOUT)),
|
||||
layoutLocked: true,
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
getDashboardLayoutSm: () => [...DEFAULT_DASHBOARD_LAYOUT_SM],
|
||||
getTradingLayoutSm: () => [...DEFAULT_TRADING_LAYOUT_SM],
|
||||
},
|
||||
actions: {
|
||||
resetTradingLayout() {
|
||||
this.tradingLayout = JSON.parse(JSON.stringify(DEFAULT_TRADING_LAYOUT));
|
||||
},
|
||||
resetDashboardLayout() {
|
||||
this.dashboardLayout = JSON.parse(JSON.stringify(DEFAULT_DASHBOARD_LAYOUT));
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
key: STORE_LAYOUTS,
|
||||
},
|
||||
});
|
|
@ -2,7 +2,7 @@
|
|||
<GridLayout
|
||||
class="h-100 w-100"
|
||||
:row-height="50"
|
||||
:layout.sync="gridLayout"
|
||||
:layout="gridLayout"
|
||||
:vertical-compact="false"
|
||||
:margin="[5, 5]"
|
||||
:responsive-layouts="responsiveGridLayouts"
|
||||
|
@ -11,7 +11,7 @@
|
|||
:responsive="true"
|
||||
:prevent-collision="true"
|
||||
:cols="{ lg: 12, md: 12, sm: 12, xs: 4, xxs: 2 }"
|
||||
@layout-updated="layoutUpdated"
|
||||
@layout-updated="layoutUpdatedEvent"
|
||||
@breakpoint-changed="breakpointChanged"
|
||||
>
|
||||
<GridItem
|
||||
|
@ -94,8 +94,6 @@
|
|||
<script lang="ts">
|
||||
import { formatPrice } from '@/shared/formatters';
|
||||
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import { namespace } from 'vuex-class';
|
||||
import { GridLayout, GridItem, GridItemData } from 'vue-grid-layout';
|
||||
|
||||
import DailyChart from '@/components/charts/DailyChart.vue';
|
||||
|
@ -105,21 +103,16 @@ import BotComparisonList from '@/components/ftbot/BotComparisonList.vue';
|
|||
import TradeList from '@/components/ftbot/TradeList.vue';
|
||||
import DraggableContainer from '@/components/layout/DraggableContainer.vue';
|
||||
|
||||
import {
|
||||
DashboardLayout,
|
||||
findGridLayout,
|
||||
LayoutActions,
|
||||
LayoutGetters,
|
||||
} from '@/store/modules/layout';
|
||||
import { Trade, DailyReturnValue, DailyPayload, ClosedTrade } from '@/types';
|
||||
import { BotStoreGetters } from '@/store/modules/ftbot';
|
||||
import { MultiBotStoreGetters } from '@/store/modules/botStoreWrapper';
|
||||
import StoreModules from '@/store/storeSubModules';
|
||||
|
||||
const ftbot = namespace(StoreModules.ftbot);
|
||||
const layoutNs = namespace(StoreModules.layout);
|
||||
import { defineComponent, ref, computed, onMounted } from '@vue/composition-api';
|
||||
import { useNamespacedGetters, useNamespacedActions } from 'vuex-composition-helpers';
|
||||
import { DashboardLayout, findGridLayout, useLayoutStore } from '@/stores/layout';
|
||||
|
||||
@Component({
|
||||
export default defineComponent({
|
||||
name: 'Dashboard',
|
||||
components: {
|
||||
GridLayout,
|
||||
GridItem,
|
||||
|
@ -130,111 +123,118 @@ const layoutNs = namespace(StoreModules.layout);
|
|||
TradeList,
|
||||
DraggableContainer,
|
||||
},
|
||||
})
|
||||
export default class Dashboard extends Vue {
|
||||
@ftbot.Getter [MultiBotStoreGetters.botCount]!: number;
|
||||
setup() {
|
||||
const {
|
||||
botCount,
|
||||
allOpenTradesAllBots,
|
||||
allTradesAllBots,
|
||||
allDailyStatsAllBots,
|
||||
performanceStats,
|
||||
} = useNamespacedGetters(StoreModules.ftbot, [
|
||||
MultiBotStoreGetters.botCount,
|
||||
MultiBotStoreGetters.allOpenTradesAllBots,
|
||||
MultiBotStoreGetters.allTradesAllBots,
|
||||
MultiBotStoreGetters.allDailyStatsAllBots,
|
||||
BotStoreGetters.performanceStats,
|
||||
]);
|
||||
|
||||
@ftbot.Getter [MultiBotStoreGetters.allOpenTradesAllBots]!: Trade[];
|
||||
const { getPerformance, allGetDaily, getTrades, getOpenTrades, getProfit } =
|
||||
useNamespacedActions(StoreModules.ftbot, [
|
||||
'getPerformance',
|
||||
'allGetDaily',
|
||||
'getTrades',
|
||||
'getOpenTrades',
|
||||
'getProfit',
|
||||
]);
|
||||
|
||||
@ftbot.Getter [MultiBotStoreGetters.allTradesAllBots]!: ClosedTrade[];
|
||||
const layoutStore = useLayoutStore();
|
||||
const currentBreakpoint = ref('');
|
||||
|
||||
@ftbot.Getter [MultiBotStoreGetters.allDailyStatsAllBots]!: Record<string, DailyReturnValue>;
|
||||
|
||||
@ftbot.Getter [BotStoreGetters.performanceStats]!: PerformanceEntry[];
|
||||
|
||||
@ftbot.Action getPerformance;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
@ftbot.Action allGetDaily!: (payload?: DailyPayload) => void;
|
||||
|
||||
@ftbot.Action getTrades;
|
||||
|
||||
@ftbot.Action getOpenTrades;
|
||||
|
||||
@ftbot.Action getProfit;
|
||||
|
||||
@layoutNs.Getter [LayoutGetters.getDashboardLayoutSm]!: GridItemData[];
|
||||
|
||||
@layoutNs.Getter [LayoutGetters.getDashboardLayout]!: GridItemData[];
|
||||
|
||||
@layoutNs.Action [LayoutActions.setDashboardLayout];
|
||||
|
||||
@layoutNs.Getter [LayoutGetters.getLayoutLocked]: boolean;
|
||||
|
||||
formatPrice = formatPrice;
|
||||
|
||||
localGridLayout: GridItemData[] = [];
|
||||
|
||||
currentBreakpoint = '';
|
||||
|
||||
get isLayoutLocked() {
|
||||
return this.getLayoutLocked || !this.isResizableLayout;
|
||||
}
|
||||
|
||||
get isResizableLayout() {
|
||||
return ['', 'sm', 'md', 'lg', 'xl'].includes(this.currentBreakpoint);
|
||||
}
|
||||
|
||||
get gridLayout() {
|
||||
if (this.isResizableLayout) {
|
||||
return this.getDashboardLayout;
|
||||
}
|
||||
return this.localGridLayout;
|
||||
}
|
||||
|
||||
set gridLayout(newLayout) {
|
||||
// Dummy setter to make gridLayout happy. Updates happen through layoutUpdated.
|
||||
}
|
||||
|
||||
layoutUpdated(newLayout) {
|
||||
// Frozen layouts for small screen sizes.
|
||||
if (this.isResizableLayout) {
|
||||
console.log('newlayout', newLayout);
|
||||
console.log('saving dashboard');
|
||||
this.setDashboardLayout(newLayout);
|
||||
}
|
||||
}
|
||||
|
||||
get gridLayoutDaily(): GridItemData {
|
||||
return findGridLayout(this.gridLayout, DashboardLayout.dailyChart);
|
||||
}
|
||||
|
||||
get gridLayoutBotComparison(): GridItemData {
|
||||
return findGridLayout(this.gridLayout, DashboardLayout.botComparison);
|
||||
}
|
||||
|
||||
get gridLayoutAllOpenTrades(): GridItemData {
|
||||
return findGridLayout(this.gridLayout, DashboardLayout.allOpenTrades);
|
||||
}
|
||||
|
||||
get gridLayoutCumChart(): GridItemData {
|
||||
return findGridLayout(this.gridLayout, DashboardLayout.cumChartChart);
|
||||
}
|
||||
|
||||
get gridLayoutTradesLogChart(): GridItemData {
|
||||
return findGridLayout(this.gridLayout, DashboardLayout.tradesLogChart);
|
||||
}
|
||||
|
||||
get responsiveGridLayouts() {
|
||||
return {
|
||||
sm: this.getDashboardLayoutSm,
|
||||
const breakpointChanged = (newBreakpoint) => {
|
||||
// // console.log('breakpoint:', newBreakpoint);
|
||||
currentBreakpoint.value = newBreakpoint;
|
||||
};
|
||||
}
|
||||
const isResizableLayout = computed(() =>
|
||||
['', 'sm', 'md', 'lg', 'xl'].includes(currentBreakpoint.value),
|
||||
);
|
||||
const isLayoutLocked = computed(() => {
|
||||
return layoutStore.layoutLocked || !isResizableLayout;
|
||||
});
|
||||
|
||||
mounted() {
|
||||
this.allGetDaily({ timescale: 30 });
|
||||
this.getTrades();
|
||||
this.getOpenTrades();
|
||||
this.getPerformance();
|
||||
this.getProfit();
|
||||
this.localGridLayout = [...this.getDashboardLayoutSm];
|
||||
}
|
||||
const gridLayout = computed((): GridItemData[] => {
|
||||
if (isResizableLayout) {
|
||||
return layoutStore.dashboardLayout;
|
||||
}
|
||||
return [...layoutStore.getDashboardLayoutSm];
|
||||
});
|
||||
|
||||
breakpointChanged(newBreakpoint) {
|
||||
// console.log('breakpoint:', newBreakpoint);
|
||||
this.currentBreakpoint = newBreakpoint;
|
||||
}
|
||||
}
|
||||
const layoutUpdatedEvent = (newLayout) => {
|
||||
if (isResizableLayout) {
|
||||
console.log('newlayout', newLayout);
|
||||
console.log('saving dashboard');
|
||||
layoutStore.tradingLayout = newLayout;
|
||||
}
|
||||
};
|
||||
|
||||
const gridLayoutDaily = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayout.value, DashboardLayout.dailyChart);
|
||||
});
|
||||
|
||||
const gridLayoutBotComparison = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayout.value, DashboardLayout.botComparison);
|
||||
});
|
||||
|
||||
const gridLayoutAllOpenTrades = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayout.value, DashboardLayout.allOpenTrades);
|
||||
});
|
||||
|
||||
const gridLayoutCumChart = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayout.value, DashboardLayout.cumChartChart);
|
||||
});
|
||||
|
||||
const gridLayoutTradesLogChart = computed((): GridItemData => {
|
||||
return findGridLayout(gridLayout.value, DashboardLayout.tradesLogChart);
|
||||
});
|
||||
|
||||
const responsiveGridLayouts = computed(() => {
|
||||
return {
|
||||
sm: layoutStore.getDashboardLayoutSm,
|
||||
};
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
allGetDaily({ timescale: 30 });
|
||||
getTrades();
|
||||
getOpenTrades();
|
||||
getPerformance();
|
||||
getProfit();
|
||||
});
|
||||
|
||||
return {
|
||||
formatPrice,
|
||||
isLayoutLocked,
|
||||
layoutUpdatedEvent,
|
||||
breakpointChanged,
|
||||
gridLayout,
|
||||
gridLayoutDaily,
|
||||
gridLayoutBotComparison,
|
||||
gridLayoutAllOpenTrades,
|
||||
gridLayoutCumChart,
|
||||
gridLayoutTradesLogChart,
|
||||
responsiveGridLayouts,
|
||||
getPerformance,
|
||||
allGetDaily,
|
||||
getTrades,
|
||||
getOpenTrades,
|
||||
getProfit,
|
||||
botCount,
|
||||
allOpenTradesAllBots,
|
||||
allTradesAllBots,
|
||||
allDailyStatsAllBots,
|
||||
performanceStats,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<b-form-group
|
||||
description="Lock dynamic layouts, so they cannot move anymore. Can also be set from the navbar at the top."
|
||||
>
|
||||
<b-checkbox v-model="layoutLockedLocal">Lock layout</b-checkbox>
|
||||
<b-checkbox v-model="layoutStore.layoutLocked">Lock layout</b-checkbox>
|
||||
</b-form-group>
|
||||
<b-form-group description="Reset dynamic layouts to how they were.">
|
||||
<b-button size="sm" @click="resetDynamicLayout">Reset layout</b-button>
|
||||
|
@ -39,28 +39,20 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { AlertActions } from '@/store/modules/alerts';
|
||||
import { LayoutActions, LayoutGetters } from '@/store/modules/layout';
|
||||
import StoreModules from '@/store/storeSubModules';
|
||||
import { defineComponent, WritableComputedRef, computed } from '@vue/composition-api';
|
||||
import { useGetters, useNamespacedActions, useNamespacedGetters } from 'vuex-composition-helpers';
|
||||
import { defineComponent } from '@vue/composition-api';
|
||||
import { useGetters, useNamespacedActions } from 'vuex-composition-helpers';
|
||||
import { OpenTradeVizOptions, useSettingsStore } from '@/stores/settings';
|
||||
import { useLayoutStore } from '@/stores/layout';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Settings',
|
||||
setup() {
|
||||
const settingsStore = useSettingsStore();
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
const { getUiVersion } = useGetters(['getUiVersion']);
|
||||
const { setLayoutLocked, resetTradingLayout, resetDashboardLayout } = useNamespacedActions(
|
||||
StoreModules.layout,
|
||||
[
|
||||
LayoutActions.setLayoutLocked,
|
||||
LayoutActions.resetTradingLayout,
|
||||
LayoutActions.resetDashboardLayout,
|
||||
],
|
||||
);
|
||||
const { getLayoutLocked } = useNamespacedGetters(StoreModules.layout, [
|
||||
LayoutGetters.getLayoutLocked,
|
||||
]);
|
||||
|
||||
const { addAlert } = useNamespacedActions(StoreModules.alerts, [AlertActions.addAlert]);
|
||||
|
||||
const timezoneOptions = ['UTC', Intl.DateTimeFormat().resolvedOptions().timeZone];
|
||||
|
@ -69,27 +61,20 @@ export default defineComponent({
|
|||
{ value: OpenTradeVizOptions.asTitle, text: 'Show in title' },
|
||||
{ value: OpenTradeVizOptions.noOpenTrades, text: "Don't show open trades in header" },
|
||||
];
|
||||
const layoutLockedLocal: WritableComputedRef<boolean> = computed({
|
||||
get(): boolean {
|
||||
return getLayoutLocked.value;
|
||||
},
|
||||
set(value: boolean): void {
|
||||
setLayoutLocked(value);
|
||||
},
|
||||
});
|
||||
|
||||
//
|
||||
const resetDynamicLayout = () => {
|
||||
resetTradingLayout();
|
||||
resetDashboardLayout();
|
||||
layoutStore.resetTradingLayout();
|
||||
layoutStore.resetDashboardLayout();
|
||||
addAlert({ message: 'Layouts have been reset.' });
|
||||
};
|
||||
return {
|
||||
getUiVersion,
|
||||
resetDynamicLayout,
|
||||
settingsStore,
|
||||
layoutStore,
|
||||
timezoneOptions,
|
||||
openTradesOptions,
|
||||
layoutLockedLocal,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -128,8 +128,6 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import { namespace } from 'vuex-class';
|
||||
import { GridLayout, GridItem, GridItemData } from 'vue-grid-layout';
|
||||
|
||||
import Balance from '@/components/ftbot/Balance.vue';
|
||||
|
@ -145,15 +143,14 @@ import Performance from '@/components/ftbot/Performance.vue';
|
|||
import TradeDetail from '@/components/ftbot/TradeDetail.vue';
|
||||
import TradeList from '@/components/ftbot/TradeList.vue';
|
||||
|
||||
import { Lock, Trade } from '@/types';
|
||||
import { BotStoreGetters } from '@/store/modules/ftbot';
|
||||
import { TradeLayout, findGridLayout, LayoutGetters, LayoutActions } from '@/store/modules/layout';
|
||||
import StoreModules from '@/store/storeSubModules';
|
||||
import { defineComponent, ref, computed } from '@vue/composition-api';
|
||||
import { useNamespacedGetters } from 'vuex-composition-helpers';
|
||||
import { useLayoutStore, findGridLayout, TradeLayout } from '@/stores/layout';
|
||||
|
||||
const ftbot = namespace(StoreModules.ftbot);
|
||||
const layoutNs = namespace(StoreModules.layout);
|
||||
|
||||
@Component({
|
||||
export default defineComponent({
|
||||
name: 'Trading',
|
||||
components: {
|
||||
Balance,
|
||||
BotControls,
|
||||
|
@ -170,98 +167,105 @@ const layoutNs = namespace(StoreModules.layout);
|
|||
TradeDetail,
|
||||
TradeList,
|
||||
},
|
||||
})
|
||||
export default class Trading extends Vue {
|
||||
@ftbot.Getter [BotStoreGetters.detailTradeId]!: number;
|
||||
setup() {
|
||||
const {
|
||||
detailTradeId,
|
||||
openTrades,
|
||||
closedTrades,
|
||||
allTrades,
|
||||
tradeDetail,
|
||||
timeframe,
|
||||
currentLocks,
|
||||
whitelist,
|
||||
stakeCurrency,
|
||||
} = useNamespacedGetters(StoreModules.ftbot, [
|
||||
BotStoreGetters.detailTradeId,
|
||||
BotStoreGetters.openTrades,
|
||||
BotStoreGetters.closedTrades,
|
||||
BotStoreGetters.allTrades,
|
||||
BotStoreGetters.tradeDetail,
|
||||
BotStoreGetters.timeframe,
|
||||
BotStoreGetters.currentLocks,
|
||||
BotStoreGetters.whitelist,
|
||||
BotStoreGetters.stakeCurrency,
|
||||
]);
|
||||
const layoutStore = useLayoutStore();
|
||||
const currentBreakpoint = ref('');
|
||||
|
||||
@ftbot.Getter [BotStoreGetters.openTrades]!: Trade[];
|
||||
|
||||
@ftbot.Getter [BotStoreGetters.closedTrades]!: Trade[];
|
||||
|
||||
@ftbot.Getter [BotStoreGetters.allTrades]!: Trade[];
|
||||
|
||||
@ftbot.Getter [BotStoreGetters.tradeDetail]!: Trade;
|
||||
|
||||
@ftbot.Getter [BotStoreGetters.timeframe]!: string;
|
||||
|
||||
@ftbot.Getter [BotStoreGetters.currentLocks]!: Lock[];
|
||||
|
||||
@ftbot.Getter [BotStoreGetters.whitelist]!: string[];
|
||||
|
||||
@ftbot.Getter [BotStoreGetters.stakeCurrency]!: string;
|
||||
|
||||
@layoutNs.Getter [LayoutGetters.getTradingLayout]!: GridItemData[];
|
||||
|
||||
@layoutNs.Getter [LayoutGetters.getTradingLayoutSm]!: GridItemData[];
|
||||
|
||||
@layoutNs.Action [LayoutActions.setTradingLayout];
|
||||
|
||||
@layoutNs.Getter [LayoutGetters.getLayoutLocked]: boolean;
|
||||
|
||||
currentBreakpoint = '';
|
||||
|
||||
localGridLayout: GridItemData[] = [];
|
||||
|
||||
get isLayoutLocked() {
|
||||
return this.getLayoutLocked || !this.isResizableLayout;
|
||||
}
|
||||
|
||||
get isResizableLayout() {
|
||||
return ['', 'sm', 'md', 'lg', 'xl'].includes(this.currentBreakpoint);
|
||||
}
|
||||
|
||||
get gridLayout(): GridItemData[] {
|
||||
if (this.isResizableLayout) {
|
||||
return this.getTradingLayout;
|
||||
}
|
||||
return this.localGridLayout;
|
||||
}
|
||||
|
||||
set gridLayout(newLayout) {
|
||||
// Dummy setter to make gridLayout happy. Updates happen through layoutUpdated.
|
||||
}
|
||||
|
||||
get gridLayoutMultiPane(): GridItemData {
|
||||
return findGridLayout(this.gridLayout, TradeLayout.multiPane);
|
||||
}
|
||||
|
||||
get gridLayoutOpenTrades(): GridItemData {
|
||||
return findGridLayout(this.gridLayout, TradeLayout.openTrades);
|
||||
}
|
||||
|
||||
get gridLayoutTradeHistory(): GridItemData {
|
||||
return findGridLayout(this.gridLayout, TradeLayout.tradeHistory);
|
||||
}
|
||||
|
||||
get gridLayoutTradeDetail(): GridItemData {
|
||||
return findGridLayout(this.gridLayout, TradeLayout.tradeDetail);
|
||||
}
|
||||
|
||||
get gridLayoutChartView(): GridItemData {
|
||||
return findGridLayout(this.gridLayout, TradeLayout.chartView);
|
||||
}
|
||||
|
||||
mounted() {
|
||||
this.localGridLayout = [...this.getTradingLayoutSm];
|
||||
}
|
||||
|
||||
layoutUpdatedEvent(newLayout) {
|
||||
if (this.isResizableLayout) {
|
||||
this.setTradingLayout(newLayout);
|
||||
}
|
||||
}
|
||||
|
||||
get responsiveGridLayouts() {
|
||||
return {
|
||||
sm: this[LayoutGetters.getTradingLayoutSm],
|
||||
const breakpointChanged = (newBreakpoint) => {
|
||||
// console.log('breakpoint:', newBreakpoint);
|
||||
currentBreakpoint.value = newBreakpoint;
|
||||
};
|
||||
}
|
||||
const isResizableLayout = computed(() =>
|
||||
['', 'sm', 'md', 'lg', 'xl'].includes(currentBreakpoint.value),
|
||||
);
|
||||
const isLayoutLocked = computed(() => {
|
||||
return layoutStore.layoutLocked || !isResizableLayout;
|
||||
});
|
||||
const gridLayout = computed((): GridItemData[] => {
|
||||
if (isResizableLayout) {
|
||||
return layoutStore.tradingLayout;
|
||||
}
|
||||
return [...layoutStore.getTradingLayoutSm];
|
||||
});
|
||||
|
||||
breakpointChanged(newBreakpoint) {
|
||||
console.log('breakpoint:', newBreakpoint);
|
||||
this.currentBreakpoint = newBreakpoint;
|
||||
}
|
||||
}
|
||||
const gridLayoutMultiPane = computed(() => {
|
||||
return findGridLayout(gridLayout.value, TradeLayout.multiPane);
|
||||
});
|
||||
|
||||
const gridLayoutOpenTrades = computed(() => {
|
||||
return findGridLayout(gridLayout.value, TradeLayout.openTrades);
|
||||
});
|
||||
|
||||
const gridLayoutTradeHistory = computed(() => {
|
||||
return findGridLayout(gridLayout.value, TradeLayout.tradeHistory);
|
||||
});
|
||||
|
||||
const gridLayoutTradeDetail = computed(() => {
|
||||
return findGridLayout(gridLayout.value, TradeLayout.tradeDetail);
|
||||
});
|
||||
|
||||
const gridLayoutChartView = computed(() => {
|
||||
return findGridLayout(gridLayout.value, TradeLayout.chartView);
|
||||
});
|
||||
|
||||
const responsiveGridLayouts = computed(() => {
|
||||
return {
|
||||
sm: layoutStore.getTradingLayoutSm,
|
||||
};
|
||||
});
|
||||
|
||||
const layoutUpdatedEvent = (newLayout) => {
|
||||
if (isResizableLayout) {
|
||||
layoutStore.tradingLayout = newLayout;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
detailTradeId,
|
||||
openTrades,
|
||||
closedTrades,
|
||||
allTrades,
|
||||
tradeDetail,
|
||||
timeframe,
|
||||
currentLocks,
|
||||
whitelist,
|
||||
stakeCurrency,
|
||||
layoutStore,
|
||||
breakpointChanged,
|
||||
layoutUpdatedEvent,
|
||||
isLayoutLocked,
|
||||
gridLayout,
|
||||
gridLayoutMultiPane,
|
||||
gridLayoutOpenTrades,
|
||||
gridLayoutTradeHistory,
|
||||
gridLayoutTradeDetail,
|
||||
gridLayoutChartView,
|
||||
responsiveGridLayouts,
|
||||
isResizableLayout,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -5319,6 +5319,11 @@ vue-template-es2015-compiler@^1.9.0, vue-template-es2015-compiler@^1.9.1:
|
|||
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
|
||||
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
|
||||
|
||||
vue2-helpers@^1.1.7:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/vue2-helpers/-/vue2-helpers-1.1.7.tgz#f105313979af0260ef446c583fd2fa75b067afd1"
|
||||
integrity sha512-NLF7bYFPyoKMvn/Bkxr7+7Ure/kZpWmd6pQpG613dT0Sn6EwI+2+LwVUQyDkDk4P0UaAwvn/QEYzhBRzDzuGLw==
|
||||
|
||||
vue@^2.6.14:
|
||||
version "2.6.14"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
|
||||
|
|
Loading…
Reference in New Issue
Block a user