frequi_origin/src/components/ftbot/PairlistConfigurator.vue

173 lines
5.0 KiB
Vue
Raw Normal View History

2023-05-23 18:27:33 +00:00
<template>
2023-05-30 18:43:35 +00:00
<div class="d-flex px-3 gap-3 flex-column flex-lg-row">
<b-list-group ref="availablePairlistsEl" class="available-pairlists">
<b-list-group-item
v-for="pairlist in availablePairlists"
:key="pairlist.name"
:class="{
'no-drag': pairlistStore.config.pairlists.length == 0 && !pairlist.is_pairlist_generator,
}"
class="pairlist d-flex text-start align-items-center py-2 px-3"
>
<div class="d-flex flex-grow-1 align-items-start flex-column">
2023-06-01 19:06:32 +00:00
<span class="fw-bold">{{ pairlist.name }}</span>
<span class="text-small">{{ pairlist.description }}</span>
2023-05-24 18:19:46 +00:00
</div>
2023-05-30 18:43:35 +00:00
<b-button
2023-06-01 19:47:12 +00:00
class="p-0 add-pairlist"
2023-05-30 18:43:35 +00:00
style="border: none"
variant="outline-light"
:disabled="pairlistStore.config.pairlists.length == 0 && !pairlist.is_pairlist_generator"
@click="pairlistStore.addToConfig(pairlist, pairlistStore.config.pairlists.length)"
>
<i-mdi-arrow-right-bold-box-outline class="fs-4" />
</b-button>
</b-list-group-item>
</b-list-group>
2023-05-31 10:32:36 +00:00
<div class="d-flex flex-column flex-fill">
2023-05-30 18:43:35 +00:00
<PairlistConfigActions />
<PairlistConfigBlacklist />
<b-alert
:model-value="
pairlistStore.config.pairlists.length > 0 && !pairlistStore.firstPairlistIsGenerator
"
variant="warning"
>
First entry in the pairlist must be a Generating pairlist, like StaticPairList or
VolumePairList.
</b-alert>
<div
ref="pairlistConfigsEl"
class="d-flex flex-column flex-grow-1 position-relative"
:class="{ empty: configEmpty }"
>
2023-05-30 18:43:35 +00:00
<PairlistConfigItem
v-for="(pairlist, i) in pairlistsComp"
:key="pairlist.id"
v-model="pairlistStore.config.pairlists[i]"
:index="i"
@remove="pairlistStore.removeFromConfig"
2023-05-30 11:41:37 +00:00
/>
2023-05-30 18:43:35 +00:00
</div>
</div>
<div class="col-12 col-lg-3">
<CopyableTextfield
:content="pairlistStore.configJSON"
:is-valid="pairlistStore.pairlistValid"
/>
</div>
</div>
2023-05-23 18:27:33 +00:00
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
2023-05-23 18:27:33 +00:00
import { useBotStore } from '@/stores/ftbotwrapper';
import { usePairlistConfigStore } from '@/stores/pairlistConfig';
2023-05-23 18:27:33 +00:00
import PairlistConfigItem from './PairlistConfigItem.vue';
2023-05-30 11:28:55 +00:00
import PairlistConfigBlacklist from './PairlistConfigBlacklist.vue';
2023-05-30 15:45:03 +00:00
import PairlistConfigActions from './PairlistConfigActions.vue';
2023-05-30 11:41:37 +00:00
import { Pairlist } from '@/types';
2023-05-23 18:27:33 +00:00
import { useSortable, moveArrayElement } from '@vueuse/integrations/useSortable';
import CopyableTextfield from '@/components/general/CopyableTextfield.vue';
2023-05-23 18:27:33 +00:00
const botStore = useBotStore();
const pairlistStore = usePairlistConfigStore();
2023-05-23 18:27:33 +00:00
const availablePairlists = ref<Pairlist[]>([]);
const pairlistConfigsEl = ref<HTMLElement | null>(null);
2023-05-24 18:19:46 +00:00
const availablePairlistsEl = ref<HTMLElement | null>(null);
2023-05-29 06:40:24 +00:00
2023-05-23 18:27:33 +00:00
// v-for updates with sorting, deleting and adding items seem to get wonky without unique keys for every item
const pairlistsComp = computed(() =>
pairlistStore.config.pairlists.map((p) => {
2023-05-23 18:27:33 +00:00
if (p.id) {
return p;
} else {
return { id: Date.now().toString(36) + Math.random().toString(36).substring(2), ...p };
}
}),
);
const configEmpty = computed(() => {
return pairlistStore.config.pairlists.length == 0;
});
2023-05-24 18:19:46 +00:00
useSortable(availablePairlistsEl, availablePairlists.value, {
group: {
name: 'configurator',
pull: 'clone',
put: false,
},
sort: false,
filter: '.no-drag',
dragClass: 'dragging',
2023-05-23 18:27:33 +00:00
});
useSortable(pairlistConfigsEl, pairlistStore.config.pairlists, {
2023-05-23 18:27:33 +00:00
handle: '.handle',
2023-05-24 18:19:46 +00:00
group: 'configurator',
2023-05-23 18:27:33 +00:00
onUpdate: async (e) => {
moveArrayElement(pairlistStore.config.pairlists, e.oldIndex, e.newIndex);
2023-05-23 18:27:33 +00:00
},
2023-05-24 18:19:46 +00:00
onAdd: (e) => {
const pairlist = availablePairlists.value[e.oldIndex];
pairlistStore.addToConfig(pairlist, e.newIndex);
// quick fix from: https://github.com/SortableJS/Sortable/issues/1515
e.clone.replaceWith(e.item);
e.clone.remove();
2023-05-24 18:19:46 +00:00
},
2023-05-23 18:27:33 +00:00
});
onMounted(async () => {
2023-05-28 17:39:06 +00:00
availablePairlists.value = (await botStore.activeBot.getPairlists()).pairlists.sort((a, b) =>
// Sort by is_pairlist_generator (by name), then by name.
// TODO: this might need to be improved
a.is_pairlist_generator === b.is_pairlist_generator
? a.name.localeCompare(b.name)
: a.is_pairlist_generator
? -1
: 1,
);
2023-05-23 18:27:33 +00:00
});
</script>
2023-05-24 18:19:46 +00:00
<style lang="scss" scoped>
2023-05-24 18:19:46 +00:00
.pairlist {
&:hover {
cursor: grab;
}
&.no-drag {
color: gray;
}
&.no-drag:hover {
cursor: default;
}
&.dragging {
border: 1px solid white;
border-radius: 0;
}
}
2023-06-01 19:47:12 +00:00
[data-theme='light'] .add-pairlist {
color: black;
}
.empty {
border: 3px dashed rgba(255, 255, 255, 0.65);
2023-05-24 18:19:46 +00:00
2023-06-01 19:47:12 +00:00
[data-theme='light'] & {
border: 3px dashed rgba(0, 0, 0, 0.5);
}
&:after {
content: 'Drag pairlist here';
position: absolute;
align-self: center;
font-size: 1.1rem;
text-transform: uppercase;
line-height: 0;
top: 50%;
}
2023-05-24 18:19:46 +00:00
}
</style>