filters lol

This commit is contained in:
a 2022-07-03 10:50:41 -05:00
parent 080215183f
commit f206ce3bb2
11 changed files with 290 additions and 75 deletions

View File

@ -29,27 +29,42 @@ import Sidebar from "./components/Sidebar.vue";
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
height: 100vh;
overflow-y: hidden;
}
.handsontable th {
border-right: 0px !important;
border-left: 0px !important;
border-top: 1px white !important;
border-bottom: 1px white !important;
line-height: 0 !important;
vertical-align: middle !important;
text-align: left !important;
min-width: 10px !important;
width: 20px !important;
}
.handsontable td {
border-right: 0px !important;
border-left: 0px !important;
border-top: 1px white !important;
border-bottom: 1px white !important;
background-color: #F7F7F7 !important;
vertical-align: middle !important;
}
.handsontable tr {
border-radius: 10px !important;
}
.handsontable .changeType {
margin: 0px !important;
border:0px !important;
float: none !important;
}
</style>
<style>
.parent {
display: grid;
height: 100%;
grid-template-columns: 1fr 4fr 3fr;
grid-template-rows: 1fr repeat(2, 3fr) 1fr;
grid-column-gap: 0px;
@ -64,7 +79,7 @@ import Sidebar from "./components/Sidebar.vue";
.main {
grid-area: 2 / 2 / 5 / 4;
overflow-x: scroll;
overflow-y: scroll;
overflow-y: hidden;
}
.sidebar {

View File

@ -2,35 +2,41 @@
<div>
<div
v-on:click="selectCharacter()"
>{{name}} the <span v-html="job" /> ({{galders.toLocaleString()}}g)</div>
>{{name}} the <span v-html="job" /> ({{galders.toLocaleString()}}g) ({{props.character}})</div>
</div>
</template>
<script lang="ts" setup>
const session = storage.GetSession()
const api:LTOApi = new LTOApiv0(session)
const api:LTOApi = getLTOState(LTOApiv0, session, useStoreRef())
const props = defineProps(['character'])
const name = ref("")
const name = ref(props.character.split("/").pop())
const job = ref("")
const galders = ref(0)
const {invs, activeTable} = useStoreRef()
name.value = invs.value.get(props.character)?.name!
job.value = invs.value.get(props.character)?.wallet?.job_img!
galders.value = invs.value.get(props.character)?.wallet?.galders!
watch(invs.value,()=>{
const currentInv = invs.value.get(props.character)
if(currentInv){
if(currentInv.wallet){
name.value = currentInv.name!
job.value = currentInv.wallet?.job_img!
galders.value = currentInv.wallet?.galders!
}
}
},{deep:true})
const selectCharacter = () => {
activeTable.value = props.character
log.info("selected char", activeTable.value)
api.GetInventory(props.character)
}
</script>
<script lang="ts">
import log from 'loglevel';
import { defineComponent, computed, PropType, defineProps, defineEmits, ref} from 'vue';
import { LTOApi, LTOApiv0 } from '../lib/lifeto';
import { defineComponent, computed, PropType, defineProps, defineEmits, ref, watch, onMounted} from 'vue';
import { getLTOState, LTOApi, LTOApiv0 } from '../lib/lifeto';
import { LoginHelper, Session } from '../lib/session';
import { storage } from '../session_storage';
import { useStore, useStoreRef } from '../state/state';

View File

@ -9,28 +9,32 @@
import { ref } from 'vue';
import { HotTable, HotColumn } from '@handsontable/vue3';
const session = storage.GetSession()
const api:LTOApi = new LTOApiv0(session)
const {invs, activeTable, columns, tags} = useStoreRef()
const {invs, activeTable, columns, tags, dirty} = useStoreRef()
const hotTableComponent = ref<any>(null)
const updateTable = () => {
const updateTable = ():TableRecipe | undefined => {
if (invs.value.has(activeTable.value)) {
const chardat = invs.value.get(activeTable.value)
if (chardat) {
const it = new InventoryTable(chardat!, { columns: columns.value, tags: tags.value })
const it = new InventoryTable(chardat, { columns: columns.value, tags: tags.value })
const hot = (hotTableComponent.value.hotInstance as Handsontable)
const build = it.BuildTable()
hot.updateSettings(build.settings)
hot.updateData(build.data)
return build
}
}
return undefined
}
// register Handsontable's modules
registerAllModules();
watch([columns.value.dirty,tags.value.dirty, activeTable], () => {
updateTable()
watch([columns.value.dirty, tags.value.dirty, activeTable, dirty], () => {
log.debug(`${dirty.value} rendering inventory`, activeTable.value)
let u = updateTable()
if(u != undefined){
saveStore()
}
})
</script>
@ -42,9 +46,10 @@ import { DefaultSettings, InventoryTable, TableRecipe } from '../lib/table';
import { Columns, ColumnByNames, ColumnInfo } from '../lib/columns';
import { TricksterItem, SampleData } from '../lib/trickster';
import Handsontable from 'handsontable';
import { useStoreRef } from '../state/state';
import { useStoreRef, saveStore } from '../state/state';
import { storage } from '../session_storage';
import { LTOApi, LTOApiv0 } from '../lib/lifeto';
import log from 'loglevel';
</script>
<style src="handsontable/dist/handsontable.full.css">

View File

@ -7,33 +7,33 @@
<script lang="ts" setup>
import CharacterCard from './CharacterCard.vue';
const { accounts, invs } = useStoreRef()
const { accounts, invs, activeTable } = useStoreRef()
const characters = ref([] as string[])
watch(invs, () => {
characters.value = [...new Set([...characters.value, ...invs.value.keys()])]
}, { deep: true })
const session = storage.GetSession()
const api: LTOApi = new LTOApiv0(session)
const api:LTOApi = getLTOState(LTOApiv0, session, useStoreRef())
api.GetAccounts().then(xs => {
xs.forEach(x => {
accounts.value.add(x)
api.GetCharacters(x).then(chars => {
chars.forEach(char => {
log.debug("new character", char)
invs.value.set(char.path, char)
})
})
characters.value.push(x)
})
})
onMounted(()=>{
let val = invs.value.get(activeTable.value)
if(!val || Object.values(val.items).length == 0) {
api.GetInventory(activeTable.value)
}
})
</script>
<script lang="ts">
import { defineComponent, computed, PropType, defineProps, defineEmits, ref, watch } from 'vue';
import { LTOApi, LTOApiv0 } from '../lib/lifeto';
import { defineComponent, computed, PropType, defineProps, defineEmits, ref, watch, onMounted } from 'vue';
import { getLTOState, LTOApi, LTOApiv0 } from '../lib/lifeto';
import { LoginHelper, Session } from '../lib/session';
import { storage } from '../session_storage';
import { useStore, useStoreRef } from '../state/state';

View File

@ -14,15 +14,14 @@ export const DetailsColumns = [
]
export const MoveColumns = [
"Move","MoveCount",
"MoveCount","Move",
]
export const TagColumns = [
"Equip","Drill","Card","Quest","Consume"
"All","Equip","Drill","Card","Quest","Consume", "Compound"
]
export const HackColumns = [
"All"
]
export const EquipmentColumns = [
@ -199,7 +198,7 @@ class Drill implements ColumnInfo {
class All implements ColumnInfo {
name:ColumnName = "All"
displayName = "all"
displayName = "swap"
getter(_:TricksterItem):(string|number){
return -10000
}
@ -216,6 +215,19 @@ class Card implements ColumnInfo {
const cardFilter= (item:TricksterItem): boolean => {
return (item.item_name.endsWith(" Card") || item.item_name.startsWith("Star Card"))
}
class Compound implements ColumnInfo {
name:ColumnName = "Compound"
displayName = "comp"
getter(item:TricksterItem):(string|number){
return compFilter(item) ? 1 : 0
}
}
const compFilter= (item:TricksterItem): boolean => {
return (item.item_desc.toLowerCase().includes("compound item"))
}
class Quest implements ColumnInfo {
name:ColumnName = "Quest"
@ -238,7 +250,8 @@ class Consume implements ColumnInfo {
}
const consumeFilter= (item:TricksterItem): boolean => {
return false
const tl = item.item_use.toLowerCase()
return tl.includes("recover") || tl.includes("restores")
}
class AP implements ColumnInfo {
@ -473,4 +486,5 @@ export const Columns:{[Property in ColumnName]:ColumnInfo}= {
RefineNumber: new RefineNumber(),
RefineState: new RefineState(),
All: new All(),
Compound: new Compound(),
}

View File

@ -1,48 +1,92 @@
import { Axios, AxiosResponse } from "axios"
import log from "loglevel"
import { RefStore } from "../state/state"
import { Session } from "./session"
import { TricksterInventory, TricksterItem, TricksterWallet } from "./trickster"
import { dummyChar, TricksterInventory, TricksterItem, TricksterWallet } from "./trickster"
export interface LTOApi {
GetCharacters:(name:string)=>Promise<Array<TricksterInventory>>
GetAccount:(name:string) =>Promise<[TricksterInventory, Array<string>]>
GetInventory:(path:string)=>Promise<TricksterInventory>
GetAccounts:() =>Promise<Array<string>>
GetLoggedin: ()=>Promise<boolean>
}
export class LTOApiv0 implements LTOApi {
export interface SessionBinding {
new(s:Session):LTOApi
}
export const getLTOState = <A extends LTOApi>(c: new (s:Session) => A,s:Session, r:RefStore): LTOApi => {
return new StatefulLTOApi(new c(s),r);
}
export class StatefulLTOApi implements LTOApi {
u: LTOApi
r: RefStore
constructor(s:LTOApi, r:RefStore){
this.u = s
this.r=r
}
GetAccount = async (name:string):Promise<[TricksterInventory, Array<string>]> =>{
const account = await this.u.GetAccount(name)
this.r.invs.value.set(account[0].path,account[0])
account[1].forEach((s)=>{
const d = dummyChar(s)
this.r.invs.value.set(d.path,d)
})
this.r.dirty.value = this.r.dirty.value + 1
return account
}
GetInventory = async (path:string):Promise<TricksterInventory>=>{
if(!path.includes("/")) {
const a = await this.GetAccount(path)
return a[0]
}
const inv = await this.u.GetInventory(path)
this.r.invs.value.set(inv.path,inv)
this.r.dirty.value = this.r.dirty.value + 1
return inv
}
GetAccounts = async ():Promise<Array<string>> =>{
return this.u.GetAccounts()
}
GetLoggedin= async ():Promise<boolean>=>{
return this.u.GetLoggedin()
}
}
export class LTOApiv0 implements LTOApi {
s: Session
constructor(s:Session) {
this.s = s
}
GetCharacters = async (account: string):Promise<Array<TricksterInventory>> =>{
GetAccount = async (account: string):Promise<[TricksterInventory, Array<string>]> => {
return this.s.authed_request("GET", `item-manager/items/account/${account}`,undefined).then(async (ans:AxiosResponse)=>{
const o = ans.data
log.debug("GetCharacters", o)
let out = [{
log.debug("GetAccount", o)
let out:string[] = []
Object.entries(o.characters).forEach((x:[string,any])=>{
out.push(`${account}/${x[1].name}`)
})
return [{
name: account,
id: ":" + account,
id:account,
wallet: {
galders: 0,
state: 0,
job_img: "bank",
},
path: account,
wallet:{
galders:0,
state:0,
job_img: "BANK",
} as TricksterWallet,
items:(Object.entries(o.items) as any).map(([k, v]: [string, TricksterItem]):TricksterItem=>{
v.unique_id = Number(k)
return v
}),
} as TricksterInventory]
await Promise.all(Object.entries(o.characters).map(async (x:[string,any])=>{
return this.GetInventory(`${account}/${x[1].name}`).then((ans)=>{
out.push(ans)
})
}))
return out
},out]
})
}
GetInventory = async (char_path: string):Promise<TricksterInventory> =>{
if(char_path.startsWith(":")) {
char_path = char_path.replace(":","")

View File

@ -0,0 +1,49 @@
//class helper {
// Revive<T>(t:string, _type:string):string {
// return t
// }
// Revive<T>(t:string, _type:string[]):string[]{
// return t.split(",")
// }
// Revive<T>(t:string, _type:number):number {
// return Number(t)
// }
// Revive<T>(t:string, _type:number[]):number[]{
// return t.split(",").map(Number)
// }
//}
import { ColumnSet } from "./table"
export const ARRAY_SEPERATOR = ","
let as = ARRAY_SEPERATOR
export interface Reviver<T> {
Murder(t:T):string
Revive(s:string):T
}
export const StoreStr= {
Murder: (s:string):string=>s,
Revive: (s:string):string=>s
}
export const StoreNum = {
Murder: (s:number):string=>s.toString(),
Revive: (s:string):number=>Number(s)
}
export const StoreStrSet = {
Murder: (s:Set<string>):string=>Array.from(s).join(as),
Revive: (s:string):Set<string>=>new Set(s.split(as))
}
export const StoreColSet = {
Murder: (s:ColumnSet):string=>Array.from(s).join(as),
Revive: (s:string):ColumnSet=>new ColumnSet(s.split(as))
}

View File

@ -15,8 +15,6 @@ export interface InventoryTableOptions {
export interface Mappable<T> {
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
}
export class ColumnSet implements Set<ColumnInfo>, Mappable<ColumnInfo>{
s: Set<ColumnName> = new Set()
size: number;
@ -24,9 +22,11 @@ export class ColumnSet implements Set<ColumnInfo>, Mappable<ColumnInfo>{
constructor(i?:Iterable<ColumnInfo | ColumnName>){
if(i){
for (const a of i) {
if(Columns[LazyColumn(a)]){
this.s.add(LazyColumn(a))
}
}
}
this.size = 0
this.mark()
}
@ -106,13 +106,26 @@ export class InventoryTable {
return Object.values(this.inv.items)
.filter((item):boolean=>{
let found = false
if(this.o.tags.s.size > 0) {
let comparer = 1
for(const tag of this.o.tags.values()) {
let chk = tag.getter(item)
if(chk === comparer) {
if(this.o.tags.has("All")) {
found = true
}
if(this.o.tags.s.size > 0) {
for(const tag of this.o.tags.values()) {
if(tag.name =="All") {
continue
}
let chk = tag.getter(item)
if(this.o.tags.has("All")) {
if(chk === 1) {
found = false
break
}
}else {
if(chk === 1) {
found = true
break
}
}
}
}else {
found = true
@ -152,6 +165,10 @@ export const DefaultSettings = ():HotTableProps=>{
filters: true,
manualRowMove: false,
manualColumnMove: false,
autoColumnSize: {
syncLimit: 1000,
useHeaders: true,
},
allowInsertRow: false,
allowInsertColumn: false,
allowRemoveRow: false,
@ -164,6 +181,7 @@ export const DefaultSettings = ():HotTableProps=>{
},
className: 'htLeft',
contextMenu: false,
dropdownMenu: false,
readOnlyCellClassName: "",
licenseKey:"non-commercial-and-evaluation",
}

View File

@ -32,13 +32,22 @@ export interface TricksterWallet {
}
export interface TricksterInventory {
name:string
path:string
name:string
id:string
wallet?:TricksterWallet
items:{[key:string]:TricksterItem}
}
export const dummyChar = (s:string):TricksterInventory => {
return {
path: s,
name: s.split("/").pop()!,
id: s,
items:{}
}
}
export const SampleData:{[key:string]:TricksterInventory} = {

View File

@ -10,7 +10,6 @@ export const nameCookie = (...s:string[]):string=>{
}
export class Storage {
GetSession():Session {
const {user, xsrf, csrf} = {
user: getCookie(nameCookie("user"))!,
@ -25,8 +24,6 @@ export class Storage {
setCookie(nameCookie("xsrf"),"")
setCookie(nameCookie("csrf"),"")
}
AddSession(s:Session) {
setCookie(nameCookie("user"),s.user)
setCookie(nameCookie("xsrf"),s.xsrf)

View File

@ -1,7 +1,11 @@
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, StoreColSet, StoreStr, StoreStrSet } from '../lib/storage'
import { ColumnSet } from '../lib/table'
import { TricksterInventory } from '../lib/trickster'
import { nameCookie} from '../session_storage'
const _defaultColumn:(ColumnInfo| ColumnName)[] = [
...BasicColumns,
@ -10,16 +14,70 @@ const _defaultColumn:(ColumnInfo| ColumnName)[] = [
]
export const useStore = defineStore('state', {
state: ()=> {
const last_table = getCookie(nameCookie("last_table"))
const last_screen = getCookie(nameCookie("last_screen"))
const last_columns = getCookie(nameCookie("last_columns"))?.split(",")
const last_tags = getCookie(nameCookie("last_tags"))?.split(",")
return {
accounts: new Set() as Set<string>,
invs: new Map() as Map<string,TricksterInventory>,
activeTable: "none",
screen: "default",
columns: new ColumnSet(_defaultColumn),
tags: new ColumnSet(),
accounts: new Set() as Set<string>,
activeTable: last_table ? last_table: "none",
screen: last_screen ? last_screen : "default",
columns: last_columns ? new ColumnSet([..._defaultColumn,...last_columns]) : new ColumnSet(_defaultColumn),
tags: last_tags ? new ColumnSet(last_tags) : new ColumnSet(),
dirty: 0,
}
}
})
export const useStoreRef = ()=>{return storeToRefs(useStore())};
export const StoreReviver = {
accounts: StoreStrSet,
activeTable: StoreStr,
screen: StoreStr,
columns: StoreColSet,
tags: StoreColSet,
}
export interface StoreProps {
invs: Map<string,TricksterInventory>
accounts: Set<string>
activeTable: string
screen: string
columns: ColumnSet
tags: ColumnSet
dirty: number
}
export const loadStore = ()=> {
let store = useStoreRef()
for(const [k, v] of Object.entries(StoreReviver)){
const coke = getCookie(nameCookie("last_"+k))
if(coke){
if((store[k as keyof StoreProps]) != undefined){
store[k as keyof StoreProps].value = v.Revive(coke)
}
}
}
}
export const saveStore = ()=> {
let store = useStoreRef()
for(const [k, v] of Object.entries(StoreReviver)){
let coke;
if((store[k as keyof StoreProps]) != undefined){
coke = v.Murder(store[k as keyof StoreProps].value as any)
}
if(coke){
setCookie(nameCookie("last_"+k),coke)
}
}
}
export const useStoreRef = ()=>{
const refs = storeToRefs(useStore())
return refs
};
export type RefStore = ReturnType<typeof useStoreRef>;