Compare commits

...

2 Commits

Author SHA1 Message Date
Sirttas 676ff961ed rename rule set to rule 2026-05-28 13:15:15 +02:00
Sirttas b40b58f866 rename rule to rule clause 2026-05-28 11:37:09 +02:00
7 changed files with 107 additions and 107 deletions
+8 -8
View File
@@ -79,15 +79,15 @@ export type MainLedgerResponseTypeEnum = typeof MainLedgerResponseTypeEnum[keyof
export interface RuleBookResponse {
'characterId': number;
'ruleSets': { [key: string]: RuleSetResponse; };
'rules': { [key: string]: RuleResponse; };
}
export interface RuleResponse {
'rate': RuleResponseRateEnum;
export interface RuleClauseResponse {
'rate': RuleClauseResponseRateEnum;
'fromLedgerId'?: string;
'toLedgerId'?: string;
}
export const RuleResponseRateEnum = {
export const RuleClauseResponseRateEnum = {
None: 'NONE',
Value: 'VALUE',
JitaBuy: 'JITA_BUY',
@@ -95,13 +95,13 @@ export const RuleResponseRateEnum = {
EveEstimate: 'EVE_ESTIMATE',
} as const;
export type RuleResponseRateEnum = typeof RuleResponseRateEnum[keyof typeof RuleResponseRateEnum];
export type RuleClauseResponseRateEnum = typeof RuleClauseResponseRateEnum[keyof typeof RuleClauseResponseRateEnum];
export interface RuleSetResponse {
'rules': Array<RuleResponse>;
export interface RuleResponse {
'rules': Array<RuleClauseResponse>;
}
export interface SetCharacterRuleBookRequest {
'ruleSets': { [key: string]: RuleSetResponse; };
'rules': { [key: string]: RuleResponse; };
}
export interface UpdateCombinedLedgerRequest {
'name': string;
+2 -2
View File
@@ -3,7 +3,7 @@ import {Character, CharacterLabel, useCharactersStore} from "@/characters";
import {useRoute} from "vue-router";
import {ref, watch, watchEffect} from "vue";
import log from "loglevel";
import {activityTypes, findByCharacterId, RuleBook, RuleSetInput, setCharacterRuleBook} from "@/rules";
import {activityTypes, findByCharacterId, RuleBook, RuleInput, setCharacterRuleBook} from "@/rules";
const {findById: findCharacterById} = useCharactersStore();
const character = ref<Character>();
@@ -50,7 +50,7 @@ watch(useRoute(), async route => {
<div v-if="ruleBook" class="flex-col">
<div class="flex-col grow border-b-1" v-for="activityType in activityTypes" :key="activityType.key">
<span>{{ activityType.name }}</span>
<RuleSetInput v-model="ruleBook.ruleSets[activityType.key]" />
<RuleInput v-model="ruleBook.rules[activityType.key]" />
</div>
</div>
</div>
+37
View File
@@ -0,0 +1,37 @@
<script setup lang="ts">
import {RuleClauseResponse} from "@/generated/mammon";
import {computed} from "vue";
import {isMain, Ledger, LedgerSelect, systemLedger, useLedgersStore} from "@/ledger";
import {ratesTypes} from "@/rules/rules.ts";
const rule = defineModel<RuleClauseResponse>();
const ledgersStore = useLedgersStore();
const {findById} = ledgersStore;
const ledgers = computed<Ledger[]>(() => [systemLedger, ...ledgersStore.ledgers.filter(isMain)]);
const ledgerComputed = (key: 'fromLedgerId' | 'toLedgerId') => computed<Ledger>({
get: () => rule.value && rule.value[key] ? findById(rule.value[key]) ?? systemLedger : systemLedger,
set: value => {
if (value) {
rule.value = {...rule.value, [key]: value.ledgerId.length ? value.ledgerId : undefined}
}
}
})
const fromLedger = ledgerComputed('fromLedgerId')
const toLedger = ledgerComputed('toLedgerId')
</script>
<template>
From:
<LedgerSelect class="me-2 grow" v-model="fromLedger" :ledgers="ledgers" />
To:
<LedgerSelect class="me-2 grow" v-model="toLedger" :ledgers="ledgers" />
At:
<select class="me-2 grow" v-model="rule.rate">
<option v-for="rateType in ratesTypes" :key="rateType.key" :value="rateType.key">{{ rateType.name }}</option>
</select>
</template>
+55 -27
View File
@@ -1,37 +1,65 @@
<script setup lang="ts">
import {RuleResponse} from "@/generated/mammon";
import {computed} from "vue";
import {isMain, Ledger, LedgerSelect, systemLedger, useLedgersStore} from "@/ledger";
import {ratesTypes} from "@/rules/rules.ts";
import {RuleClauseResponse, RuleClauseResponseRateEnum, RuleResponse} from "@/generated/mammon";
import RuleClauseInput from "@/rules/RuleClauseInput.vue";
import {computed, useTemplateRef} from "vue";
import {Bars4Icon, PlusIcon, TrashIcon} from '@heroicons/vue/24/outline';
import {useSortable} from "@vueuse/integrations/useSortable";
const rule = defineModel<RuleResponse>();
const ledgersStore = useLedgersStore();
const {findById} = ledgersStore;
const ledgers = computed<Ledger[]>(() => [systemLedger, ...ledgersStore.ledgers.filter(isMain)]);
const ledgerComputed = (key: 'fromLedgerId' | 'toLedgerId') => computed<Ledger>({
get: () => rule.value && rule.value[key] ? findById(rule.value[key]) ?? systemLedger : systemLedger,
set: value => {
if (value) {
rule.value = {...rule.value, [key]: value.ledgerId.length ? value.ledgerId : undefined}
}
}
const rules = computed<RuleClauseResponse[]>({
get: () => rule.value && rule.value.rules ? rule.value.rules : [],
set: value => rule.value = {rules: value}
})
const fromLedger = ledgerComputed('fromLedgerId')
const toLedger = ledgerComputed('toLedgerId')
const addRule = () => {
rules.value = [...rules.value, {rate: RuleClauseResponseRateEnum.None}]
}
const setRule = (index: number, rule?: RuleClauseResponse) => {
if (!rule) {
return;
}
rules.value = rules.value.with(index, rule)
}
const removeRule = (index: number) => {
rules.value = rules.value.toSpliced(index, 1)
}
const sortableContainer = useTemplateRef('sortable-container')
useSortable(sortableContainer, rules, { handle: '.sortable-handle'});
</script>
<template>
From:
<LedgerSelect class="me-2 grow" v-model="fromLedger" :ledgers="ledgers" />
To:
<LedgerSelect class="me-2 grow" v-model="toLedger" :ledgers="ledgers" />
At:
<select class="me-2 grow" v-model="rule.rate">
<option v-for="rateType in ratesTypes" :key="rateType.key" :value="rateType.key">{{ rateType.name }}</option>
</select>
</template>
<div class="flex-col">
<div ref="sortable-container" class="flex-col">
<div class="flex items-end gap-2 mt-2" v-for="(rule, index) in rules" :key="index">
<span class="sortable-handle flex">
<Bars4Icon class="w-6"/>
</span>
<RuleClauseInput :modelValue="rule" @update:modelValue="v => setRule(index, v)" />
<button class="btn-icon" @click="removeRule(index)"><TrashIcon /></button>
</div>
</div>
<div class="flex justify-end mb-2 mt-2">
<button class="btn-icon" @click="addRule"><PlusIcon /></button>
</div>
</div>
</template>
<style scoped>
.sortable-handle {
@apply cursor-grab;
}
.sortable-chosen {
@apply cursor-grabbing;
}
.sortable-chosen .sortable-handle {
@apply cursor-grabbing;
}
</style>
-65
View File
@@ -1,65 +0,0 @@
<script setup lang="ts">
import {RuleResponse, RuleResponseRateEnum, RuleSetResponse} from "@/generated/mammon";
import RuleInput from "@/rules/RuleInput.vue";
import {computed, useTemplateRef} from "vue";
import {Bars4Icon, PlusIcon, TrashIcon} from '@heroicons/vue/24/outline';
import {useSortable} from "@vueuse/integrations/useSortable";
const ruleSet = defineModel<RuleSetResponse>();
const rules = computed<RuleResponse[]>({
get: () => ruleSet.value && ruleSet.value.rules ? ruleSet.value.rules : [],
set: value => ruleSet.value = {rules: value}
})
const addRule = () => {
rules.value = [...rules.value, {rate: RuleResponseRateEnum.None}]
}
const setRule = (index: number, rule?: RuleResponse) => {
if (!rule) {
return;
}
rules.value = rules.value.with(index, rule)
}
const removeRule = (index: number) => {
rules.value = rules.value.toSpliced(index, 1)
}
const sortableContainer = useTemplateRef('sortable-container')
useSortable(sortableContainer, rules, { handle: '.sortable-handle'});
</script>
<template>
<div class="flex-col">
<div ref="sortable-container" class="flex-col">
<div class="flex items-end gap-2 mt-2" v-for="(rule, index) in rules" :key="index">
<span class="sortable-handle flex">
<Bars4Icon class="w-6"/>
</span>
<RuleInput :modelValue="rule" @update:modelValue="v => setRule(index, v)" />
<button class="btn-icon" @click="removeRule(index)"><TrashIcon /></button>
</div>
</div>
<div class="flex justify-end mb-2 mt-2">
<button class="btn-icon" @click="addRule"><PlusIcon /></button>
</div>
</div>
</template>
<style scoped>
.sortable-handle {
@apply cursor-grab;
}
.sortable-chosen {
@apply cursor-grabbing;
}
.sortable-chosen .sortable-handle {
@apply cursor-grabbing;
}
</style>
+1 -1
View File
@@ -1,3 +1,3 @@
export * from "./rules";
export {default as RuleSetInput} from './RuleSetInput.vue';
export {default as RuleInput} from './RuleInput.vue';
+4 -4
View File
@@ -1,5 +1,5 @@
import {ruleBookControllerApi} from "@/mammon";
import {RuleBookResponse, RuleResponseRateEnum, RuleSetResponse} from "@/generated/mammon";
import {RuleBookResponse, RuleClauseResponseRateEnum, RuleResponse} from "@/generated/mammon";
export const activityTypes = {
itemBought: {key: "ITEM_BOUGHT", name: "Item Bought"},
@@ -10,7 +10,7 @@ export const activityTypes = {
export type Activity = { key: ActivityType, name: string }
export type ActivityType = typeof activityTypes[keyof typeof activityTypes]['key'];
export type RuleBook = RuleBookResponse & { ruleSets: { [key: ActivityType]: RuleSetResponse; } }
export type RuleBook = RuleBookResponse & { rules: { [key: ActivityType]: RuleResponse; } }
export const ratesTypes = {
None: {key: "NONE", name: "0 ISK"},
@@ -20,11 +20,11 @@ export const ratesTypes = {
EveEstimate: {key: "EVE_ESTIMATE", name: "Eve Estimate"},
} as const;
export type Rate = { key: RuleResponseRateEnum, name: string }
export type Rate = { key: RuleClauseResponseRateEnum, name: string }
export const findByCharacterId = (characterId: number): Promise<RuleBook> => ruleBookControllerApi.findByCharacterId(characterId)
.then(response => response.data)
.catch(() => ({characterId, ruleSets: {}}));
.catch(() => ({characterId, rules: {}}));
export const setCharacterRuleBook = (characterId: number, ruleBook: RuleBook): Promise<RuleBook> => ruleBookControllerApi.setCharacterRuleBook(characterId, ruleBook)
.then(response => response.data);