item moving
This commit is contained in:
parent
90106b844d
commit
8f0f0e715b
21
src/App.vue
21
src/App.vue
@ -3,10 +3,15 @@ import CharacterInventory from "./components/CharacterInventory.vue"
|
||||
import Login from "./pages/login.vue"
|
||||
import CharacterRoulette from "./components/CharacterRoulette.vue";
|
||||
import Sidebar from "./components/Sidebar.vue";
|
||||
import { loadStore } from "./state/state";
|
||||
import OrderDisplay from "./components/OrderDisplay.vue";
|
||||
loadStore()
|
||||
</script>
|
||||
<template>
|
||||
<OrderDisplay/>
|
||||
<div class="parent">
|
||||
<div class="splash"> </div>
|
||||
<div class="splash">
|
||||
</div>
|
||||
<div class="main">
|
||||
<CharacterInventory />
|
||||
</div>
|
||||
@ -63,6 +68,14 @@ import Sidebar from "./components/Sidebar.vue";
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.main {
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.sidebar {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.parent {
|
||||
display: grid;
|
||||
height: 100%;
|
||||
@ -76,13 +89,9 @@ import Sidebar from "./components/Sidebar.vue";
|
||||
.splash {
|
||||
grid-area: 1 / 1 / 2 / 2;
|
||||
}
|
||||
|
||||
.main {
|
||||
.main{
|
||||
grid-area: 2 / 2 / 5 / 4;
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
grid-area: 2 / 1 / 5 / 2;
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
<div>
|
||||
<div
|
||||
v-on:click="selectCharacter()"
|
||||
>{{name}} the <span v-html="job" /> ({{galders.toLocaleString()}}g) ({{props.character}})</div>
|
||||
>
|
||||
{{activeTable == props.character ? "*" :""}}
|
||||
{{name}} the <span v-html="job" /> ({{galders.toLocaleString()}}g) ({{props.character}}, {{items}})</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
@ -10,16 +12,19 @@ const session = storage.GetSession()
|
||||
const api:LTOApi = getLTOState(LTOApiv0, session, useStoreRef())
|
||||
|
||||
const props = defineProps(['character'])
|
||||
const name = ref(props.character.split("/").pop())
|
||||
const name = ref("")
|
||||
const job = ref("")
|
||||
const items = ref(0)
|
||||
const galders = ref(0)
|
||||
const {invs, activeTable, chars} = useStoreRef()
|
||||
|
||||
watch(invs.value,()=>{
|
||||
const currentInv = invs.value.get(props.character)
|
||||
if(currentInv){
|
||||
name.value = currentInv.name!
|
||||
galders.value = currentInv.galders!
|
||||
if(currentInv.galders){
|
||||
galders.value = currentInv.galders
|
||||
}
|
||||
items.value = Object.values(currentInv.items).length
|
||||
}
|
||||
},{deep:true})
|
||||
|
||||
@ -29,7 +34,6 @@ if(currentChar){
|
||||
job.value = JobNumberToString(currentChar.current_job)
|
||||
}
|
||||
|
||||
|
||||
const selectCharacter = () => {
|
||||
activeTable.value = props.character
|
||||
api.GetInventory(props.character)
|
||||
|
@ -1,4 +1,9 @@
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
id="logoutButton"
|
||||
v-on:click="send_orders()"
|
||||
>ayy lmao button</button>
|
||||
<HotTable
|
||||
ref="hotTableComponent"
|
||||
:settings="DefaultSettings()"
|
||||
@ -6,11 +11,19 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { HotTable, HotColumn } from '@handsontable/vue3';
|
||||
|
||||
const {invs, activeTable, columns, tags, dirty} = useStoreRef()
|
||||
const storeRefs = useStoreRef()
|
||||
const {invs, activeTable, columns, tags, dirty, chars, currentSearch, orders} = storeRefs
|
||||
|
||||
const hotTableComponent = ref<any>(null)
|
||||
const hott = ():Handsontable =>{
|
||||
return hotTableComponent.value.hotInstance as any
|
||||
}
|
||||
const session = storage.GetSession()
|
||||
const api:LTOApi = getLTOState(LTOApiv0, session, useStoreRef())
|
||||
const manager = new OrderSender(storeRefs)
|
||||
|
||||
const updateTable = ():TableRecipe | undefined => {
|
||||
if (invs.value.has(activeTable.value)) {
|
||||
@ -19,25 +32,76 @@ const updateTable = ():TableRecipe | undefined => {
|
||||
const it = new InventoryTable(chardat, {
|
||||
columns: columns.value,
|
||||
tags: tags.value,
|
||||
accounts: Array.from(invs.value.keys()),
|
||||
accounts: Array.from(chars.value.keys()),
|
||||
} as InventoryTableOptions)
|
||||
const hot = (hotTableComponent.value.hotInstance as Handsontable)
|
||||
const build = it.BuildTable()
|
||||
hot.updateSettings(build.settings)
|
||||
hott().updateSettings(build.settings)
|
||||
return build
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
watch(currentSearch, ()=>{
|
||||
filterTable()
|
||||
})
|
||||
|
||||
const send_orders = () => {
|
||||
if(hott()) {
|
||||
const headers = hott().getColHeader()
|
||||
const dat = hott().getData()
|
||||
const idxNumber = headers.indexOf(Columns.MoveCount.displayName)
|
||||
const idxTarget = headers.indexOf(Columns.Move.displayName)
|
||||
const origin = activeTable
|
||||
const pending:OrderDetails[] = [];
|
||||
for(const row of dat) {
|
||||
const nm = Number(row[idxNumber].replace("x",""))
|
||||
const target = (row[idxTarget] as string).replaceAll("-","").trim()
|
||||
if(!isNaN(nm) && nm > 0 && target.length > 0){
|
||||
const info:OrderDetails = {
|
||||
item_uid: row[0].toString(),
|
||||
count: nm,
|
||||
origin_path: origin.value,
|
||||
target_path: target,
|
||||
}
|
||||
pending.push(info)
|
||||
}
|
||||
}
|
||||
log.debug("OrderDetails", pending)
|
||||
for(const d of pending){
|
||||
const order = manager.send(d)
|
||||
order.tick(storeRefs, api)
|
||||
}
|
||||
saveStore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onMounted(()=>{
|
||||
window.setInterval(tick_orders, 1000)
|
||||
})
|
||||
const tick_orders = () => {
|
||||
if(orders && storeRefs && api){
|
||||
orders.value.tick(storeRefs, api)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const filterTable = () => {
|
||||
if(hott()){
|
||||
const fp = hott().getPlugin('filters')
|
||||
fp.removeConditions(2)
|
||||
fp.addCondition(2,'contains', [currentSearch.value])
|
||||
fp.filter()
|
||||
}
|
||||
}
|
||||
// register Handsontable's modules
|
||||
registerAllModules();
|
||||
|
||||
watch([columns.value.dirty, tags.value.dirty, activeTable, dirty], () => {
|
||||
log.debug(`${dirty.value} rendering inventory`, activeTable.value)
|
||||
log.debug(`${dirty.value} rendering inventory`, activeTable.value)
|
||||
let u = updateTable()
|
||||
if(u != undefined){
|
||||
saveStore()
|
||||
}
|
||||
saveStore()
|
||||
})
|
||||
|
||||
</script>
|
||||
@ -47,12 +111,13 @@ import { defineComponent, computed, PropType, defineProps, defineEmits, watch} f
|
||||
import { registerAllModules } from 'handsontable/registry';
|
||||
import { DefaultSettings, InventoryTable, InventoryTableOptions, TableRecipe } from '../lib/table';
|
||||
import { Columns, ColumnByNames, ColumnInfo } from '../lib/columns';
|
||||
import { TricksterItem, SampleData } from '../lib/trickster';
|
||||
import { TricksterItem} from '../lib/trickster';
|
||||
import Handsontable from 'handsontable';
|
||||
import { useStoreRef, saveStore } from '../state/state';
|
||||
import { storage } from '../session_storage';
|
||||
import { LTOApi, LTOApiv0 } from '../lib/lifeto';
|
||||
import log from 'loglevel';
|
||||
import { getLTOState, LTOApi, LTOApiv0 } from '../lib/lifeto';
|
||||
import log, { info } from 'loglevel';
|
||||
import { OrderDetails, OrderSender } from '../lib/lifeto/order_manager';
|
||||
</script>
|
||||
|
||||
<style src="handsontable/dist/handsontable.full.css">
|
||||
|
@ -7,7 +7,7 @@
|
||||
<script lang="ts" setup>
|
||||
import CharacterCard from './CharacterCard.vue';
|
||||
|
||||
const { chars, accounts, invs, activeTable } = useStoreRef()
|
||||
const { chars, invs, activeTable } = useStoreRef()
|
||||
|
||||
const characters = ref([] as string[])
|
||||
watch(chars, () => {
|
||||
@ -22,6 +22,7 @@ api.GetAccounts().then(xs => {
|
||||
characters.value.push(...x.characters.map(x=>x.path))
|
||||
})
|
||||
characters.value = [...new Set([...characters.value])]
|
||||
saveStore();
|
||||
})
|
||||
|
||||
onMounted(()=>{
|
||||
@ -38,7 +39,7 @@ import { defineComponent, computed, PropType, defineProps, defineEmits, ref, wat
|
||||
import { getLTOState, LTOApi, LTOApiv0 } from '../lib/lifeto';
|
||||
import { LoginHelper, Session } from '../lib/session';
|
||||
import { storage } from '../session_storage';
|
||||
import { useStore, useStoreRef } from '../state/state';
|
||||
import { saveStore, useStore, useStoreRef } from '../state/state';
|
||||
import log from 'loglevel';
|
||||
|
||||
</script>
|
||||
|
127
src/components/OrderDisplay.vue
Normal file
127
src/components/OrderDisplay.vue
Normal file
@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<div id="order-display">
|
||||
<div id="order-titlebar"></div>
|
||||
<table>
|
||||
<tr
|
||||
v-for="v in orders.orders"
|
||||
:key="dirty"
|
||||
>
|
||||
<td>{{v.action_id}}</td>
|
||||
<td>[{{v.progress()[0]}} / {{v.progress()[1]}}]</td>
|
||||
<td>{{v.order_type}}</td>
|
||||
<td>{{v.state}}</td>
|
||||
<td>{{(((new Date()).getTime() - new Date(v.created).getTime())/(60 *1000)).toFixed(0)}} min ago</td>
|
||||
<td>
|
||||
<button
|
||||
type="button"
|
||||
id="logoutButton"
|
||||
v-on:click="tick_order(v.action_id)"
|
||||
>tick</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
const storeRefs = useStoreRef()
|
||||
const {orders, dirty} = storeRefs;
|
||||
const session = storage.GetSession()
|
||||
const api:LTOApi = getLTOState(LTOApiv0, session, useStoreRef())
|
||||
const tick_order = (action_id:string)=> {
|
||||
const deet = orders.value.orders[action_id]
|
||||
console.log(deet)
|
||||
if(deet){
|
||||
deet.tick(storeRefs, api)
|
||||
}else {
|
||||
console.log(`tried to send ${action_id} but undefined`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onMounted(()=>{
|
||||
dragElement(document.getElementById("order-display"));
|
||||
function dragElement(elmnt:any) {
|
||||
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
|
||||
document.getElementById("order-titlebar")!.onmousedown = dragMouseDown;
|
||||
function dragMouseDown(e:any) {
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
// get the mouse cursor position at startup:
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
document.onmouseup = closeDragElement;
|
||||
// call a function whenever the cursor moves:
|
||||
document.onmousemove = elementDrag;
|
||||
}
|
||||
|
||||
function elementDrag(e:any) {
|
||||
e = e || window.event;
|
||||
e.preventDefault();
|
||||
// calculate the new cursor position:
|
||||
pos1 = pos3 - e.clientX;
|
||||
pos2 = pos4 - e.clientY;
|
||||
pos3 = e.clientX;
|
||||
pos4 = e.clientY;
|
||||
// set the element's new position:
|
||||
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
|
||||
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
|
||||
}
|
||||
|
||||
function closeDragElement() {
|
||||
// stop moving when mouse button is released:
|
||||
document.onmouseup = null;
|
||||
document.onmousemove = null;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { onMounted, watch } from 'vue';
|
||||
import { getLTOState, LTOApi, LTOApiv0 } from '../lib/lifeto';
|
||||
import { storage } from '../session_storage';
|
||||
import { useStoreRef } from '../state/state';
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<style>
|
||||
#order-display{
|
||||
position: absolute;
|
||||
z-index: 9;
|
||||
background-color: #f1f1f1;
|
||||
border: 1px solid #d3d3d3;
|
||||
text-align: center;
|
||||
width: 300px;
|
||||
}
|
||||
#order-titlebar {
|
||||
padding: 10px;
|
||||
cursor: move;
|
||||
z-index: 10;
|
||||
background-color: #2196F3;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,22 +1,30 @@
|
||||
<template>
|
||||
Filters:
|
||||
search:
|
||||
<div class="filter_field">
|
||||
<input
|
||||
type="text"
|
||||
id="searchbox"
|
||||
v-model="currentSearch"
|
||||
/>
|
||||
</div>
|
||||
<br>
|
||||
<FilterCheckboxGroup :header="'tags:'" :columns="TagColumns" />
|
||||
<FilterCheckboxGroup :header="'tags:'" :columns="[...TagColumns]" />
|
||||
<br>
|
||||
Columns:
|
||||
<br>
|
||||
<ColumnCheckboxGroup :header="'action:'" :columns="MoveColumns" :default="true" />
|
||||
<ColumnCheckboxGroup :header="'details:'" :columns="DetailsColumns" :default="true"/>
|
||||
<ColumnCheckboxGroup :header="'equipment:'" :columns="EquipmentColumns" />
|
||||
<ColumnCheckboxGroup :header="'stats:'" :columns="StatsColumns" />
|
||||
<ColumnCheckboxGroup :header="'action:'" :columns="[...MoveColumns]" :default="true" />
|
||||
<ColumnCheckboxGroup :header="'details:'" :columns="[...DetailsColumns]" :default="true"/>
|
||||
<ColumnCheckboxGroup :header="'equipment:'" :columns="[...EquipmentColumns]" />
|
||||
<ColumnCheckboxGroup :header="'stats:'" :columns="[...StatsColumns]" />
|
||||
<ColumnCheckboxGroup :header="'debug:'" :columns="[...DebugColumns]" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ColumnCheckboxGroup from './ColumnCheckboxGroup.vue';
|
||||
import FilterCheckboxGroup from './FilterCheckboxGroup.vue';
|
||||
import { StatsColumns, MoveColumns, TagColumns, EquipmentColumns, DetailsColumns } from '../lib/columns';
|
||||
import { DebugColumns, StatsColumns, MoveColumns, TagColumns, EquipmentColumns, DetailsColumns } from '../lib/columns';
|
||||
|
||||
const { accounts, invs } = useStoreRef()
|
||||
const { currentSearch} = useStoreRef()
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { TricksterItem } from "../trickster"
|
||||
import Core from "handsontable/core";
|
||||
|
||||
export const BasicColumns = [
|
||||
"Image","Name","Count",
|
||||
"uid","Image","Name","Count",
|
||||
] as const
|
||||
|
||||
export const DetailsColumns = [
|
||||
@ -28,6 +28,9 @@ export const StatsColumns = [
|
||||
"AP","GunAP","AC","DX","MP","MA","MD","WT","DA","LK","HP","DP","HV",
|
||||
] as const
|
||||
|
||||
|
||||
export const DebugColumns = [
|
||||
]
|
||||
export const HackColumns = [
|
||||
] as const
|
||||
|
||||
|
@ -11,11 +11,6 @@ export const ColumnByNames = (...n:ColumnName[]) => {
|
||||
export const ColumnByName = (n:ColumnName) => {
|
||||
return Columns[n]
|
||||
}
|
||||
export const test = <T extends ColumnInfo>(n:(new ()=>T)):[string,T] => {
|
||||
let nn = new n()
|
||||
return [nn.name, nn]
|
||||
}
|
||||
|
||||
|
||||
class Image implements ColumnInfo {
|
||||
name:ColumnName = 'Image'
|
||||
@ -76,24 +71,26 @@ class Count implements ColumnInfo {
|
||||
}
|
||||
}
|
||||
|
||||
const spacer = "-------------------------------"
|
||||
class Move implements ColumnInfo {
|
||||
name:ColumnName = "Move"
|
||||
displayName = "Target"
|
||||
writable = true
|
||||
options = getMoveTargets
|
||||
getter(item:TricksterItem):(string|number){
|
||||
return "---------------------------------------------"
|
||||
return spacer
|
||||
}
|
||||
}
|
||||
|
||||
const getMoveTargets = (invs: string[]):string[] => {
|
||||
let out:string[] = [];
|
||||
out.push(spacer)
|
||||
for(const k of invs){
|
||||
out.push(k)
|
||||
}
|
||||
out.push("")
|
||||
out.push("")
|
||||
out.push("!TRASH")
|
||||
out.push("TRASH")
|
||||
return out
|
||||
}
|
||||
|
||||
@ -175,6 +172,20 @@ class All implements ColumnInfo {
|
||||
return -10000
|
||||
}
|
||||
}
|
||||
class uid implements ColumnInfo {
|
||||
name:ColumnName = "uid"
|
||||
displayName = "id"
|
||||
renderer = invisibleRenderer
|
||||
getter(item:TricksterItem):(string|number){
|
||||
return item.unique_id
|
||||
}
|
||||
}
|
||||
|
||||
function invisibleRenderer(instance:Core, td:any, row:number, col:number, prop:any, value:any, cellProperties:any) {
|
||||
Handsontable.dom.empty(td);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Card implements ColumnInfo {
|
||||
name:ColumnName = "Card"
|
||||
@ -447,6 +458,7 @@ export const Columns:{[Property in ColumnName]:ColumnInfo}= {
|
||||
RefineState: new RefineState(),
|
||||
All: new All(),
|
||||
Compound: new Compound(),
|
||||
uid: new uid(),
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,40 +1,15 @@
|
||||
import { trace } from "loglevel"
|
||||
import { TricksterAccount, TricksterInventory } from "../trickster"
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
|
||||
|
||||
export const BankEndpoints = ["internal-xfer-item", "bank-item"] as const
|
||||
export type BankEndpoint = typeof BankEndpoints[number]
|
||||
|
||||
export interface LTOApi {
|
||||
GetInventory:(path:string)=>Promise<TricksterInventory>
|
||||
GetAccounts:() =>Promise<Array<TricksterAccount>>
|
||||
GetLoggedin: ()=>Promise<boolean>
|
||||
}
|
||||
|
||||
export const TxnStates = ["PENDING","INFLIGHT","WAITING","ERROR","SUCCESS"] as const
|
||||
export type TxnState = typeof TxnStates[number]
|
||||
|
||||
export interface TxnDetails {
|
||||
item_uid: string | "galders"
|
||||
count:number
|
||||
origin:string
|
||||
target:string
|
||||
}
|
||||
|
||||
export abstract class BankReceipt {
|
||||
action_id: string
|
||||
details:TxnDetails
|
||||
created:Date
|
||||
|
||||
constructor(details:TxnDetails) {
|
||||
this.details = details
|
||||
this.created = new Date()
|
||||
this.action_id = uuidv4();
|
||||
}
|
||||
abstract state():Promise<TxnState>
|
||||
abstract status():string
|
||||
abstract progress():[number, number]
|
||||
abstract error():string
|
||||
}
|
||||
|
||||
export interface BankApi {
|
||||
SendTxn: (txn:TxnDetails) => Promise<BankReceipt>
|
||||
GetLoggedin:() =>Promise<boolean>
|
||||
|
||||
BankAction:<T, D>(e:BankEndpoint, t:T) => Promise<D>
|
||||
}
|
||||
|
@ -1,27 +1,48 @@
|
||||
import { Axios, AxiosResponse } from "axios"
|
||||
import { zhCN } from "handsontable/i18n"
|
||||
import log from "loglevel"
|
||||
import { RefStore } from "../../state/state"
|
||||
import { Session } from "../session"
|
||||
import { bank_endpoint, Session } from "../session"
|
||||
import { dummyChar, TricksterAccount, TricksterInventory, TricksterItem, TricksterWallet } from "../trickster"
|
||||
import { LTOApi } from "./api"
|
||||
import { BankEndpoint, LTOApi } from "./api"
|
||||
|
||||
export const pathIsBank = (path:string):boolean => {
|
||||
if(!path.includes("/")) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export const splitPath = (path:string):[string,string]=>{
|
||||
const spl = path.split("/")
|
||||
switch(spl.length) {
|
||||
case 1:
|
||||
return [spl[0], ""]
|
||||
case 2:
|
||||
return [spl[0],spl[1]]
|
||||
}
|
||||
return ["",""]
|
||||
}
|
||||
export class LTOApiv0 implements LTOApi {
|
||||
s: Session
|
||||
constructor(s:Session) {
|
||||
this.s = s
|
||||
}
|
||||
|
||||
BankAction = async <T,D>(e: BankEndpoint, t: T):Promise<D> => {
|
||||
return this.s.request("POST",e,t,bank_endpoint).then((x)=>{
|
||||
return x.data
|
||||
})
|
||||
}
|
||||
GetInventory = async (char_path: string):Promise<TricksterInventory> =>{
|
||||
if(char_path.startsWith(":")) {
|
||||
char_path = char_path.replace(":","")
|
||||
}
|
||||
return this.s.authed_request("GET", `item-manager/items/account/${char_path}`,undefined).then((ans:AxiosResponse)=>{
|
||||
return this.s.request("GET", `item-manager/items/account/${char_path}`,undefined).then((ans:AxiosResponse)=>{
|
||||
const o = ans.data
|
||||
log.debug("GetInventory", o)
|
||||
let name = "bank"
|
||||
let id = 0
|
||||
let galders = 0
|
||||
if(char_path.includes("/")) {
|
||||
if(pathIsBank("char_path")){
|
||||
let [char, val] = Object.entries(o.characters)[0] as [string,any]
|
||||
name = val.name
|
||||
id = Number(char)
|
||||
@ -36,16 +57,16 @@ export class LTOApiv0 implements LTOApi {
|
||||
id,
|
||||
path: char_path,
|
||||
galders,
|
||||
items:(Object.entries(o.items) as any).map(([k, v]: [string, TricksterItem]):TricksterItem=>{
|
||||
items: Object.fromEntries((Object.entries(o.items) as any).map(([k, v]: [string, TricksterItem]):[string, TricksterItem]=>{
|
||||
v.unique_id = Number(k)
|
||||
return v
|
||||
}),
|
||||
return [k, v]
|
||||
})),
|
||||
} as TricksterInventory
|
||||
return out
|
||||
})
|
||||
}
|
||||
GetAccounts = async ():Promise<TricksterAccount[]> => {
|
||||
return this.s.authed_request("GET", "characters/list",undefined).then((ans:AxiosResponse)=>{
|
||||
return this.s.request("GET", "characters/list",undefined).then((ans:AxiosResponse)=>{
|
||||
log.debug("GetAccounts", ans.data)
|
||||
return ans.data.map((x:any)=>{
|
||||
return {
|
||||
@ -65,7 +86,7 @@ export class LTOApiv0 implements LTOApi {
|
||||
})
|
||||
}
|
||||
GetLoggedin = async ():Promise<boolean> => {
|
||||
return this.s.authed_request("POST", "accounts/list",undefined).then((ans:AxiosResponse)=>{
|
||||
return this.s.request("POST", "accounts/list",undefined).then((ans:AxiosResponse)=>{
|
||||
if(ans.status == 401) {
|
||||
return false
|
||||
}
|
||||
|
226
src/lib/lifeto/order.ts
Normal file
226
src/lib/lifeto/order.ts
Normal file
@ -0,0 +1,226 @@
|
||||
import { LTOApi } from "./api"
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { RefStore } from "../../state/state";
|
||||
import { debug } from "loglevel";
|
||||
|
||||
export const TxnStates = ["PENDING","INFLIGHT","WORKING","ERROR","SUCCESS"] as const
|
||||
|
||||
export type TxnState = typeof TxnStates[number]
|
||||
|
||||
export interface TxnDetails {
|
||||
item_uid: string | "galders"
|
||||
count:number
|
||||
origin:string
|
||||
target:string
|
||||
|
||||
origin_path:string
|
||||
target_path:string
|
||||
}
|
||||
|
||||
|
||||
export abstract class Order {
|
||||
action_id: string
|
||||
details?:TxnDetails
|
||||
created:Date
|
||||
state: TxnState
|
||||
constructor(details?:TxnDetails) {
|
||||
this.state = "PENDING"
|
||||
this.details = details
|
||||
this.created = new Date()
|
||||
this.action_id = uuidv4();
|
||||
}
|
||||
|
||||
mark(t:TxnState) {
|
||||
this.state = t
|
||||
}
|
||||
|
||||
abstract tick(r:RefStore, api:LTOApi):Promise<any>
|
||||
abstract status():string
|
||||
abstract progress():[number, number]
|
||||
abstract error():string
|
||||
|
||||
abstract order_type:OrderType
|
||||
|
||||
parse(i:any):Order {
|
||||
this.action_id = i.action_id
|
||||
this.details = i.details
|
||||
this.created = new Date(i.created)
|
||||
this.state = i.state
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class BasicOrder extends Order {
|
||||
stage: number
|
||||
err?: string
|
||||
|
||||
constructor(details:TxnDetails) {
|
||||
super(details)
|
||||
this.stage = 0
|
||||
}
|
||||
progress():[number,number]{
|
||||
return [this.stage, 1]
|
||||
}
|
||||
status():string {
|
||||
return this.state
|
||||
}
|
||||
error():string {
|
||||
return this.err ? this.err : ""
|
||||
}
|
||||
parse(i:any):BasicOrder {
|
||||
this.stage = i.stage
|
||||
this.err = i.err
|
||||
super.parse(i)
|
||||
return this
|
||||
}
|
||||
}
|
||||
/// start user defined
|
||||
|
||||
export const OrderTypes = ["InvalidOrder","BankItem","InternalXfer"]
|
||||
export type OrderType = typeof OrderTypes[number]
|
||||
|
||||
export class InvalidOrder extends Order{
|
||||
order_type = "InvalidOrder"
|
||||
|
||||
msg:string
|
||||
constructor(msg: string){
|
||||
super(undefined)
|
||||
this.msg = msg
|
||||
this.mark("ERROR")
|
||||
}
|
||||
status():string {
|
||||
return "ERROR"
|
||||
}
|
||||
progress():[number, number] {
|
||||
return [0,0]
|
||||
}
|
||||
error(): string {
|
||||
return this.msg
|
||||
}
|
||||
async tick(r:RefStore, api:LTOApi):Promise<void> {
|
||||
return
|
||||
}
|
||||
parse(i:any):InvalidOrder {
|
||||
super.parse(i)
|
||||
this.msg = i.msg
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
export interface BasicResponse {
|
||||
status: number
|
||||
data: any
|
||||
msg?: string
|
||||
}
|
||||
|
||||
|
||||
export interface InternalXferRequest {
|
||||
item_uid:string
|
||||
qty:string
|
||||
account:string
|
||||
new_char:string
|
||||
}
|
||||
|
||||
export interface InternalXferResponse extends BasicResponse {}
|
||||
|
||||
export class InternalXfer extends BasicOrder{
|
||||
order_type = "InternalXfer"
|
||||
|
||||
originalRequest:InternalXferRequest
|
||||
originalResponse?:InternalXferResponse
|
||||
constructor(details:TxnDetails) {
|
||||
super(details)
|
||||
this.originalRequest = {
|
||||
item_uid: details.item_uid,
|
||||
qty: details.count.toString(),
|
||||
new_char: details.target,
|
||||
account: details.origin,
|
||||
}
|
||||
}
|
||||
async tick(r:RefStore, api:LTOApi):Promise<void> {
|
||||
if(this.state !== "PENDING") {
|
||||
return
|
||||
}
|
||||
this.mark("WORKING")
|
||||
return api.BankAction<InternalXferRequest, InternalXferResponse>("internal-xfer-item",this.originalRequest)
|
||||
.then((x:InternalXferResponse)=>{
|
||||
if(x.status == 200){
|
||||
this.originalResponse = x
|
||||
this.stage = 1
|
||||
this.mark("SUCCESS")
|
||||
const origin_item = r.invs.value.get(this.details?.origin_path!)!.items[this.details?.item_uid!]!
|
||||
origin_item.item_count = origin_item.item_count - this.details?.count!
|
||||
r.dirty.value++
|
||||
}else{
|
||||
throw x.msg
|
||||
}
|
||||
})
|
||||
.catch((e)=>{
|
||||
debug("InternalXfer",e)
|
||||
this.stage = 1
|
||||
this.err = e
|
||||
this.mark("ERROR")
|
||||
})
|
||||
}
|
||||
parse(i:any):InternalXfer {
|
||||
super.parse(i)
|
||||
this.originalRequest = i.originalRequest
|
||||
this.originalResponse = i.originalResponse
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
export interface BankItemRequest {
|
||||
item_uid:string
|
||||
qty:string
|
||||
account:string
|
||||
}
|
||||
|
||||
export interface BankItemResponse extends BasicResponse {}
|
||||
|
||||
export class BankItem extends BasicOrder{
|
||||
order_type = "BankItem";
|
||||
|
||||
originalRequest:BankItemRequest
|
||||
originalResponse?:BankItemResponse
|
||||
constructor(details:TxnDetails) {
|
||||
super(details)
|
||||
this.originalRequest = {
|
||||
item_uid: details.item_uid,
|
||||
qty: details.count.toString(),
|
||||
account: details.target,
|
||||
}
|
||||
}
|
||||
async tick(r:RefStore, api:LTOApi):Promise<void> {
|
||||
if(this.state !== "PENDING" ){
|
||||
return
|
||||
}
|
||||
this.mark("WORKING")
|
||||
return api.BankAction<BankItemRequest, BankItemResponse>("bank-item",this.originalRequest)
|
||||
.then((x)=>{
|
||||
debug("BankItem",x)
|
||||
if(x.status == 200){
|
||||
this.stage = 1
|
||||
this.originalResponse = x
|
||||
this.mark("SUCCESS")
|
||||
const origin_item = r.invs.value.get(this.details?.origin_path!)!.items[this.details?.item_uid!]!
|
||||
origin_item.item_count = origin_item.item_count - this.details?.count!
|
||||
r.dirty.value++
|
||||
}else {
|
||||
throw x.msg ? "unknown error" : ""
|
||||
}
|
||||
})
|
||||
.catch((e)=>{
|
||||
this.stage = 1
|
||||
this.err = e
|
||||
this.mark("ERROR")
|
||||
})
|
||||
}
|
||||
|
||||
parse(i:any):BankItem {
|
||||
super.parse(i)
|
||||
this.originalRequest = i.originalRequest
|
||||
this.originalResponse = i.originalResponse
|
||||
return this
|
||||
}
|
||||
}
|
155
src/lib/lifeto/order_manager.ts
Normal file
155
src/lib/lifeto/order_manager.ts
Normal file
@ -0,0 +1,155 @@
|
||||
import log from "loglevel";
|
||||
import { Ref } from "vue";
|
||||
import { RefStore } from "../../state/state";
|
||||
import { JsonLoadable, Serializable } from "../storage";
|
||||
import { LTOApi } from "./api";
|
||||
import { pathIsBank, splitPath } from "./lifeto";
|
||||
import { BankItem, BankXfer, InternalXfer, InvalidOrder, Order, TxnDetails } from "./order";
|
||||
|
||||
export interface OrderDetails {
|
||||
item_uid: string | "galders"
|
||||
count:number
|
||||
origin_path:string
|
||||
target_path:string
|
||||
}
|
||||
|
||||
const notSupported = new InvalidOrder("not supported yet")
|
||||
const notFound = new InvalidOrder("character not found")
|
||||
|
||||
export class OrderTracker implements Serializable<OrderTracker> {
|
||||
orders: {[key:string]:Order} = {}
|
||||
|
||||
async tick(r:RefStore, api:LTOApi):Promise<any> {
|
||||
let hasDirty = false
|
||||
console.log("ticking")
|
||||
for(const [id, order] of Object.entries(this.orders)) {
|
||||
if(order.state == "SUCCESS" || order.state == "ERROR") {
|
||||
console.log("finished order", order)
|
||||
hasDirty = true
|
||||
delete this.orders[id]
|
||||
}
|
||||
order.tick(r,api)
|
||||
}
|
||||
if(hasDirty){
|
||||
r.dirty.value++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
parse(s: any): OrderTracker {
|
||||
if(s == undefined) {
|
||||
return new OrderTracker()
|
||||
}
|
||||
if(s.orders == undefined) {
|
||||
return new OrderTracker()
|
||||
}
|
||||
this.orders = {}
|
||||
const raw: Order[] = Object.values(s.orders)
|
||||
for(const o of raw) {
|
||||
let newOrder:Order | undefined = undefined
|
||||
console.log("loading", o)
|
||||
if(o.details){
|
||||
if(o.state == "SUCCESS" || o.state == "ERROR") {
|
||||
continue
|
||||
}
|
||||
switch(o.order_type) {
|
||||
case "InternalXfer":
|
||||
newOrder = new InternalXfer(o.details).parse(o)
|
||||
break;
|
||||
case "BankItem":
|
||||
newOrder = new BankItem(o.details).parse(o)
|
||||
break;
|
||||
case "InvalidOrder":
|
||||
newOrder = new InvalidOrder("").parse(o)
|
||||
break;
|
||||
}
|
||||
if(newOrder) {
|
||||
this.orders[newOrder.action_id] = newOrder
|
||||
}
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
export class OrderSender {
|
||||
r: RefStore
|
||||
constructor(r:RefStore) {
|
||||
this.r = r
|
||||
}
|
||||
|
||||
send(o:OrderDetails):Order {
|
||||
const formed = this.form(o)
|
||||
this.r.orders.value.orders[formed.action_id] = formed
|
||||
return formed
|
||||
}
|
||||
|
||||
form(o:OrderDetails):Order {
|
||||
// bank to bank
|
||||
if(pathIsBank(o.origin_path) && pathIsBank(o.target_path)) {
|
||||
return this.bank_to_bank(o)
|
||||
}
|
||||
// bank to user
|
||||
if(pathIsBank(o.origin_path) && !pathIsBank(o.target_path)) {
|
||||
return this.bank_to_user(o)
|
||||
}
|
||||
// user to bank
|
||||
if(!pathIsBank(o.origin_path) && pathIsBank(o.target_path)) {
|
||||
return this.user_to_bank(o)
|
||||
}
|
||||
// user to user
|
||||
if(!pathIsBank(o.origin_path) && !pathIsBank(o.target_path)) {
|
||||
return this.user_to_user(o)
|
||||
}
|
||||
return notSupported
|
||||
}
|
||||
bank_to_bank(o:OrderDetails): Order{
|
||||
const origin = this.r.chars.value.get(o.origin_path)
|
||||
const target = this.r.chars.value.get(o.target_path)
|
||||
return notSupported
|
||||
}
|
||||
bank_to_user(o:OrderDetails): Order{
|
||||
// get the uid of the bank
|
||||
const origin = this.r.chars.value.get(o.origin_path)
|
||||
const target = this.r.chars.value.get(o.target_path)
|
||||
if(!(origin && target)) {
|
||||
return notFound
|
||||
}
|
||||
const [account, name] = splitPath(target.path)
|
||||
if(account != origin.path) {
|
||||
return notSupported
|
||||
}
|
||||
return new InternalXfer(this.transformOrder(o))
|
||||
}
|
||||
user_to_bank(o:OrderDetails): Order{
|
||||
const origin = this.r.chars.value.get(o.origin_path)
|
||||
const target = this.r.chars.value.get(o.target_path)
|
||||
if(!(origin && target)) {
|
||||
return notFound
|
||||
}
|
||||
const [account, name] = splitPath(origin.path)
|
||||
if(account != target.path) {
|
||||
return notSupported
|
||||
}
|
||||
return new BankItem(this.transformOrder(o))
|
||||
}
|
||||
user_to_user(o:OrderDetails): Order{
|
||||
const origin = this.r.chars.value.get(o.origin_path)
|
||||
const target = this.r.chars.value.get(o.target_path)
|
||||
return notSupported
|
||||
}
|
||||
|
||||
transformOrder(o:OrderDetails):TxnDetails {
|
||||
const origin = this.r.chars.value.get(o.origin_path)!
|
||||
const target = this.r.chars.value.get(o.target_path)!
|
||||
return {
|
||||
origin: origin.id.toString(),
|
||||
target: target.id.toString(),
|
||||
item_uid: o.item_uid,
|
||||
count: o.count,
|
||||
origin_path: o.origin_path,
|
||||
target_path: o.target_path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { RefStore } from "../../state/state";
|
||||
import { Session } from "../session";
|
||||
import { bank_endpoint, Session } from "../session";
|
||||
import { TricksterAccount, TricksterInventory } from "../trickster";
|
||||
import { LTOApi } from "./api";
|
||||
import { BankEndpoint, LTOApi } from "./api";
|
||||
|
||||
export interface SessionBinding {
|
||||
new(s:Session):LTOApi
|
||||
@ -17,9 +17,19 @@ export class StatefulLTOApi implements LTOApi {
|
||||
this.u = s
|
||||
this.r=r
|
||||
}
|
||||
BankAction = <T,D>(e: BankEndpoint, t: T):Promise<D> => {
|
||||
return this.u.BankAction(e,t)
|
||||
}
|
||||
GetInventory = async (path:string):Promise<TricksterInventory>=>{
|
||||
const inv = await this.u.GetInventory(path)
|
||||
this.r.invs.value.set(inv.path,inv)
|
||||
if(this.r.invs.value.get(inv.path)){
|
||||
this.r.invs.value.get(inv.path)!.items = inv.items
|
||||
}else{
|
||||
this.r.invs.value.set(inv.path,inv)
|
||||
}
|
||||
if(inv.galders) {
|
||||
this.r.invs.value.get(inv.path)!.galders = inv.galders
|
||||
}
|
||||
this.r.dirty.value = this.r.dirty.value + 1
|
||||
return inv
|
||||
}
|
||||
|
@ -2,24 +2,37 @@ import axios, { AxiosResponse, Method } from "axios";
|
||||
import qs from "qs";
|
||||
import { getCookie, removeCookie } from "typescript-cookie";
|
||||
|
||||
|
||||
export const SITE_ROOT = "/lifeto/"
|
||||
|
||||
export const API_ROOT = "api/lifeto/"
|
||||
export const BANK_ROOT = "item-manager-action/"
|
||||
|
||||
const login_endpoint = (name:string)=>{
|
||||
return SITE_ROOT + name
|
||||
}
|
||||
export const api_endpoint = (name:string):string =>{
|
||||
return SITE_ROOT+API_ROOT + name
|
||||
}
|
||||
export const bank_endpoint = (name:string):string =>{
|
||||
return SITE_ROOT+BANK_ROOT + name
|
||||
}
|
||||
|
||||
export const EndpointCreators = [
|
||||
api_endpoint,
|
||||
bank_endpoint,
|
||||
]
|
||||
|
||||
type EndpointCreator = typeof EndpointCreators[number]
|
||||
|
||||
export interface Session {
|
||||
user:string
|
||||
xsrf:string
|
||||
csrf:string
|
||||
authed_request:(verb:Method,url:string,data:any)=>Promise<any>
|
||||
request:(verb:Method,url:string,data:any,c?:EndpointCreator)=>Promise<any>
|
||||
}
|
||||
|
||||
|
||||
export const SITE_ROOT = "/lifeto/"
|
||||
export const API_ROOT = "api/lifeto/"
|
||||
|
||||
const login_endpoint = (name:string)=>{
|
||||
return SITE_ROOT + name
|
||||
}
|
||||
const api_endpoint = (name:string)=>{
|
||||
return SITE_ROOT+API_ROOT + name
|
||||
}
|
||||
|
||||
|
||||
export class LoginHelper {
|
||||
user:string
|
||||
@ -32,13 +45,6 @@ export class LoginHelper {
|
||||
login = async ():Promise<TokenSession> =>{
|
||||
return axios.get(login_endpoint("login"),{withCredentials:false})
|
||||
.then(async (x)=>{
|
||||
console.log(x)
|
||||
if(x.data){
|
||||
try{
|
||||
this.csrf = x.data.split("csrf-token")[1].split('\">')[0].replace("\" content=\"",'')
|
||||
}catch(e){
|
||||
}
|
||||
}
|
||||
return axios.post(login_endpoint("login"),{
|
||||
login:this.user,
|
||||
password:this.pass,
|
||||
@ -74,19 +80,19 @@ export class TokenSession implements Session {
|
||||
this.xsrf = xsrf;
|
||||
}
|
||||
|
||||
authed_request = async (verb:string,url:string,data:any):Promise<AxiosResponse> => {
|
||||
request = async (verb:string,url:string,data:any, c:EndpointCreator = api_endpoint):Promise<AxiosResponse> => {
|
||||
let promise
|
||||
switch (verb.toLowerCase()){
|
||||
case "post":
|
||||
promise = axios.post(api_endpoint(url),data,this.genHeaders())
|
||||
promise = axios.post(c(url),data,this.genHeaders())
|
||||
break;
|
||||
case "postraw":
|
||||
const querystring = qs.stringify(data)
|
||||
promise = axios.post(api_endpoint(url),querystring,this.genHeaders())
|
||||
promise = axios.post(c(url),querystring,this.genHeaders())
|
||||
break;
|
||||
case "get":
|
||||
default:
|
||||
promise = axios.get(api_endpoint(url),this.genHeaders())
|
||||
promise = axios.get(c(url),this.genHeaders())
|
||||
}
|
||||
return promise.then(x=>{
|
||||
if(x.data){
|
||||
|
@ -20,9 +20,6 @@ export const ARRAY_SEPERATOR = ","
|
||||
|
||||
let as = ARRAY_SEPERATOR
|
||||
|
||||
|
||||
|
||||
|
||||
export interface Reviver<T> {
|
||||
Murder(t:T):string
|
||||
Revive(s:string):T
|
||||
@ -48,6 +45,25 @@ export const StoreColSet = {
|
||||
Revive: (s:string):ColumnSet=>new ColumnSet(s.split(as) as any)
|
||||
}
|
||||
export const StoreChars = {
|
||||
Murder: (s:Map<string,TricksterCharacter>):string=>JSON.stringify(Object.entries(s)),
|
||||
Murder: (s:Map<string,TricksterCharacter>):string=>{
|
||||
let o = JSON.stringify(Array.from(s.entries()))
|
||||
return o
|
||||
},
|
||||
Revive: (s:string):Map<string,TricksterCharacter>=>new Map(JSON.parse(s)),
|
||||
}
|
||||
|
||||
export const StoreJsonable = {
|
||||
Murder: <T>(s:T):string=>JSON.stringify(Object.entries(s)),
|
||||
Revive: <T>(s:string):T=>JSON.parse(s),
|
||||
}
|
||||
|
||||
export interface Serializable<T> {
|
||||
parse(s:any):T
|
||||
}
|
||||
|
||||
export const StoreSerializable = <T extends Serializable<T>>(n:(new ()=>T))=>{
|
||||
return {
|
||||
Murder: (s:T):string=>JSON.stringify(s),
|
||||
Revive: (s:string):T=>new n().parse(JSON.parse(s))
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import {ColumnInfo, ColumnName, Columns, ColumnSorter, LazyColumn} from "./colum
|
||||
import { ColumnSettings } from "handsontable/settings"
|
||||
import { PredefinedMenuItemKey } from "handsontable/plugins/contextMenu"
|
||||
import { ref } from "vue"
|
||||
import Handsontable from "handsontable"
|
||||
|
||||
|
||||
|
||||
@ -100,13 +101,18 @@ export class InventoryTable {
|
||||
return this.o.columns.map(x=>{
|
||||
let out:any = {
|
||||
renderer: x.renderer ? x.renderer : "text",
|
||||
filters: true,
|
||||
dropdownMenu: x.filtering ? DefaultDropdownItems() : false,
|
||||
readOnly: x.writable ? false : true,
|
||||
selectionMode: (x.writable ? "multiple" : 'single') as any,
|
||||
}
|
||||
if(x.options) {
|
||||
out.type = 'dropdown'
|
||||
out.source = Array.from(this.o.accounts.values())
|
||||
if(typeof x.options == "function") {
|
||||
out.source = x.options(this.o.accounts)
|
||||
}else {
|
||||
out.source = x.options
|
||||
}
|
||||
}
|
||||
return out
|
||||
})
|
||||
@ -114,6 +120,9 @@ export class InventoryTable {
|
||||
getTableRows():any[][] {
|
||||
return Object.values(this.inv.items)
|
||||
.filter((item):boolean=>{
|
||||
if(item.item_count <= 0) {
|
||||
return false
|
||||
}
|
||||
let found = true
|
||||
let hasAll = this.o.tags.has("All")
|
||||
if(this.o.tags.s.size > 0) {
|
||||
@ -172,9 +181,30 @@ export const DefaultSettings = ():HotTableProps=>{
|
||||
indicator: true,
|
||||
headerAction: true,
|
||||
},
|
||||
hiddenColumns: {
|
||||
columns: [0],
|
||||
},
|
||||
// renderAllRows: true,
|
||||
viewportColumnRenderingOffset: 3,
|
||||
viewportRowRenderingOffset: 100,
|
||||
// dropdownMenu: DefaultDropdownItems(),
|
||||
afterGetColHeader: (col, th) => {
|
||||
if(!th.innerHTML.toLowerCase().includes("name")) {
|
||||
const ct = th.querySelector('.changeType')
|
||||
if(ct){
|
||||
ct.parentElement!.removeChild(ct)
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeOnCellMouseDown(event:any, coords) {
|
||||
// Deselect the column after clicking on input.
|
||||
if (coords.row === -1 && event.target.nodeName === 'INPUT') {
|
||||
event.stopImmediatePropagation();
|
||||
this.deselectCell();
|
||||
}
|
||||
},
|
||||
className: 'htLeft',
|
||||
contextMenu: false,
|
||||
dropdownMenu: false,
|
||||
readOnlyCellClassName: "",
|
||||
licenseKey:"non-commercial-and-evaluation",
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ import { defineStore, storeToRefs } from 'pinia'
|
||||
import { getCookie, setCookie } from 'typescript-cookie'
|
||||
import { useCookies } from 'vue3-cookies'
|
||||
import { BasicColumns, ColumnInfo, ColumnName, Columns, DetailsColumns, MoveColumns } from '../lib/columns'
|
||||
import { Reviver, StoreChars, StoreColSet, StoreInvs, StoreStr, StoreStrSet } from '../lib/storage'
|
||||
import { OrderTracker } from '../lib/lifeto/order_manager'
|
||||
import { Reviver, StoreChars, StoreColSet, StoreInvs, StoreSerializable, StoreStr, StoreStrSet } from '../lib/storage'
|
||||
import { ColumnSet } from '../lib/table'
|
||||
import { TricksterCharacter, TricksterInventory } from '../lib/trickster'
|
||||
import { nameCookie} from '../session_storage'
|
||||
@ -12,42 +13,47 @@ const _defaultColumn:(ColumnInfo| ColumnName)[] = [
|
||||
...MoveColumns,
|
||||
...DetailsColumns,
|
||||
]
|
||||
export const useStore = defineStore('state', {
|
||||
state: ()=> {
|
||||
let store = {
|
||||
invs: new Map() as Map<string,TricksterInventory>,
|
||||
chars: new Map() as Map<string,TricksterCharacter>,
|
||||
accounts: new Set() as Set<string>,
|
||||
activeTable: "none",
|
||||
screen: "default",
|
||||
columns:new ColumnSet(_defaultColumn),
|
||||
tags: new ColumnSet(),
|
||||
dirty: 0,
|
||||
}
|
||||
loadStore();
|
||||
return store
|
||||
}
|
||||
})
|
||||
|
||||
// if you wish for the thing to persist
|
||||
export const StoreReviver = {
|
||||
chars: StoreChars,
|
||||
accounts: StoreStrSet,
|
||||
activeTable: StoreStr,
|
||||
screen: StoreStr,
|
||||
columns: StoreColSet,
|
||||
tags: StoreColSet,
|
||||
// orders: StoreSerializable(OrderTracker)
|
||||
}
|
||||
|
||||
export interface StoreProps {
|
||||
invs: Map<string,TricksterInventory>
|
||||
chars: Map<string, TricksterCharacter>
|
||||
accounts: Set<string>
|
||||
orders: OrderTracker
|
||||
activeTable: string
|
||||
screen: string
|
||||
columns: ColumnSet
|
||||
tags: ColumnSet
|
||||
dirty: number
|
||||
currentSearch: string
|
||||
}
|
||||
|
||||
export const useStore = defineStore('state', {
|
||||
state: ()=> {
|
||||
let store = {
|
||||
invs: new Map() as Map<string,TricksterInventory>,
|
||||
chars: new Map() as Map<string,TricksterCharacter>,
|
||||
orders: new OrderTracker(),
|
||||
activeTable: "none",
|
||||
screen: "default",
|
||||
columns:new ColumnSet(_defaultColumn),
|
||||
tags: new ColumnSet(),
|
||||
dirty: 0,
|
||||
currentSearch: "",
|
||||
}
|
||||
return store
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
export const loadStore = ()=> {
|
||||
let store = useStoreRef()
|
||||
for(const [k, v] of Object.entries(StoreReviver)){
|
||||
@ -63,7 +69,6 @@ export const saveStore = ()=> {
|
||||
let store = useStoreRef()
|
||||
for(const [k, v] of Object.entries(StoreReviver)){
|
||||
let coke;
|
||||
|
||||
if((store[k as keyof RefStore]) != undefined){
|
||||
coke = v.Murder(store[k as keyof RefStore].value as any)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user