Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9cd0d5fb5e | |||
| 5ac369a643 | |||
| b2c97c1327 | |||
| 4ae044dace | |||
| c444f51423 | |||
| a201a95756 | |||
| b32169f433 | |||
| 023693c4c8 | |||
| 47bd728530 |
+43
-78
@@ -58,6 +58,24 @@ paths:
|
||||
$ref: "#/components/schemas/RuleBookResponse"
|
||||
"400":
|
||||
description: Invalid request (e.g. blank name)
|
||||
delete:
|
||||
tags:
|
||||
- rule-book
|
||||
summary: Delete a rule book
|
||||
operationId: deleteRuleBook
|
||||
parameters:
|
||||
- name: ruleBookId
|
||||
in: path
|
||||
description: Id of the rule book
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
"204":
|
||||
description: The rule book was deleted
|
||||
"400":
|
||||
description: The rule book is associated to a character
|
||||
/ledgers/main/{ledgerId}:
|
||||
put:
|
||||
tags:
|
||||
@@ -295,6 +313,19 @@ paths:
|
||||
description: New activities fetched and stored
|
||||
"400":
|
||||
description: No character with this id
|
||||
/rule-books/script-definitions:
|
||||
get:
|
||||
tags:
|
||||
- rule-book
|
||||
summary: Download the TypeScript definitions for the rule script runtime
|
||||
operationId: getScriptDefinitions
|
||||
responses:
|
||||
"200":
|
||||
description: The rule-runner.d.ts type definitions
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
/ledgers:
|
||||
get:
|
||||
tags:
|
||||
@@ -415,66 +446,6 @@ paths:
|
||||
$ref: "#/components/schemas/AcquisitionResponse"
|
||||
components:
|
||||
schemas:
|
||||
IskRuleClauseResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/RuleClauseResponse"
|
||||
- type: object
|
||||
properties:
|
||||
fromLedgerRef:
|
||||
type: string
|
||||
pattern: "[a-z]+(-[a-z]+)*"
|
||||
toLedgerRef:
|
||||
type: string
|
||||
pattern: "[a-z]+(-[a-z]+)*"
|
||||
required:
|
||||
- fromLedgerRef
|
||||
- toLedgerRef
|
||||
ItemExchangeRuleClauseResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/RuleClauseResponse"
|
||||
- type: object
|
||||
properties:
|
||||
rate:
|
||||
type: string
|
||||
enum:
|
||||
- NONE
|
||||
- VALUE
|
||||
- JITA_BUY
|
||||
- JITA_SELL
|
||||
- EVE_ESTIMATE
|
||||
fromLedgerRef:
|
||||
type: string
|
||||
pattern: "[a-z]+(-[a-z]+)*"
|
||||
toLedgerRef:
|
||||
type: string
|
||||
pattern: "[a-z]+(-[a-z]+)*"
|
||||
required:
|
||||
- fromLedgerRef
|
||||
- rate
|
||||
- toLedgerRef
|
||||
RuleClauseResponse:
|
||||
discriminator:
|
||||
propertyName: type
|
||||
mapping:
|
||||
ISK: "#/components/schemas/IskRuleClauseResponse"
|
||||
ITEM_EXCHANGE: "#/components/schemas/ItemExchangeRuleClauseResponse"
|
||||
oneOf:
|
||||
- $ref: "#/components/schemas/IskRuleClauseResponse"
|
||||
- $ref: "#/components/schemas/ItemExchangeRuleClauseResponse"
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
RuleResponse:
|
||||
type: object
|
||||
properties:
|
||||
clauses:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/RuleClauseResponse"
|
||||
required:
|
||||
- clauses
|
||||
UpdateRuleBookRequest:
|
||||
type: object
|
||||
properties:
|
||||
@@ -486,15 +457,13 @@ components:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
pattern: "[a-z]+(-[a-z]+)*"
|
||||
rules:
|
||||
type: object
|
||||
additionalProperties:
|
||||
$ref: "#/components/schemas/RuleResponse"
|
||||
pattern: "[a-z][a-zA-Z0-9]*"
|
||||
script:
|
||||
type: string
|
||||
required:
|
||||
- ledgerRefs
|
||||
- name
|
||||
- rules
|
||||
- script
|
||||
- usedForAcquisitions
|
||||
RuleBookResponse:
|
||||
type: object
|
||||
@@ -510,16 +479,14 @@ components:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
pattern: "[a-z]+(-[a-z]+)*"
|
||||
rules:
|
||||
type: object
|
||||
additionalProperties:
|
||||
$ref: "#/components/schemas/RuleResponse"
|
||||
pattern: "[a-z][a-zA-Z0-9]*"
|
||||
script:
|
||||
type: string
|
||||
required:
|
||||
- ledgerRefs
|
||||
- name
|
||||
- ruleBookId
|
||||
- rules
|
||||
- script
|
||||
- usedForAcquisitions
|
||||
UpdateMainLedgerRequest:
|
||||
type: object
|
||||
@@ -622,15 +589,13 @@ components:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
pattern: "[a-z]+(-[a-z]+)*"
|
||||
rules:
|
||||
type: object
|
||||
additionalProperties:
|
||||
$ref: "#/components/schemas/RuleResponse"
|
||||
pattern: "[a-z][a-zA-Z0-9]*"
|
||||
script:
|
||||
type: string
|
||||
required:
|
||||
- ledgerRefs
|
||||
- name
|
||||
- rules
|
||||
- script
|
||||
- usedForAcquisitions
|
||||
CreateMainLedgerRequest:
|
||||
type: object
|
||||
|
||||
Generated
+39
@@ -18,6 +18,7 @@
|
||||
"gemory": "file:",
|
||||
"loglevel": "^1.8.1",
|
||||
"loglevel-plugin-prefix": "^0.8.4",
|
||||
"monaco-editor": "^0.55.1",
|
||||
"pinia": "^3.0.4",
|
||||
"sortablejs": "^1.15.7",
|
||||
"vue": "^3.3.4",
|
||||
@@ -866,6 +867,13 @@
|
||||
"undici-types": ">=7.24.0 <7.24.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/trusted-types": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
||||
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@types/web-bluetooth": {
|
||||
"version": "0.0.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
|
||||
@@ -1585,6 +1593,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz",
|
||||
"integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||
"optionalDependencies": {
|
||||
"@types/trusted-types": "^2.0.7"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
@@ -2265,6 +2282,18 @@
|
||||
"url": "https://github.com/sponsors/sxzz"
|
||||
}
|
||||
},
|
||||
"node_modules/marked": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz",
|
||||
"integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"marked": "bin/marked.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
@@ -2330,6 +2359,16 @@
|
||||
"pathe": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/monaco-editor": {
|
||||
"version": "0.55.1",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz",
|
||||
"integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dompurify": "3.2.7",
|
||||
"marked": "14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"gemory": "file:",
|
||||
"loglevel": "^1.8.1",
|
||||
"loglevel-plugin-prefix": "^0.8.4",
|
||||
"monaco-editor": "^0.55.1",
|
||||
"pinia": "^3.0.4",
|
||||
"sortablejs": "^1.15.7",
|
||||
"vue": "^3.3.4",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import {computed} from 'vue';
|
||||
import {RouterView, useRoute} from 'vue-router';
|
||||
import {Sidebar} from './sidebar';
|
||||
import {ConfirmModal} from '@/confirm';
|
||||
import {routeNames} from '@/routes';
|
||||
|
||||
const route = useRoute();
|
||||
@@ -21,6 +22,7 @@ const hideSidebar = computed(() => {
|
||||
<RouterView />
|
||||
</div>
|
||||
</template>
|
||||
<ConfirmModal />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -12,7 +12,8 @@ const modelValue = defineModel({ default: false });
|
||||
|
||||
<style scoped>
|
||||
@reference "@/style.css";
|
||||
input:checked ~ span:last-child {
|
||||
--tw-translate-x: 1.25rem;
|
||||
}
|
||||
|
||||
input:checked ~ span:last-child {
|
||||
transform: translateX(1.25rem);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,45 @@
|
||||
<script setup lang="ts">
|
||||
import {computed} from "vue";
|
||||
import {storeToRefs} from "pinia";
|
||||
import {Modal} from "@/components";
|
||||
import {useConfirmStore} from "./useConfirm";
|
||||
|
||||
const confirmStore = useConfirmStore();
|
||||
const {open, options} = storeToRefs(confirmStore);
|
||||
const {accept, cancel} = confirmStore;
|
||||
|
||||
const modalOpen = computed({
|
||||
get: () => open.value,
|
||||
set: value => {
|
||||
if (!value) {
|
||||
cancel();
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal v-model:open="modalOpen">
|
||||
<div class="bg-slate-800 rounded pb-4 w-96">
|
||||
<span class="m-2">{{ options.title ?? "Confirm" }}</span>
|
||||
<hr />
|
||||
<div class="m-4">{{ options.message }}</div>
|
||||
<div class="flex justify-end">
|
||||
<button class="me-2" @click="cancel">{{ options.cancelLabel ?? "Cancel" }}</button>
|
||||
<button class="confirm me-4" :class="options.danger ? 'danger' : ''" @click="accept">{{ options.confirmLabel ?? "Confirm" }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "@/style.css";
|
||||
|
||||
button.confirm {
|
||||
@apply border-emerald-500 bg-emerald-500 hover:bg-emerald-600;
|
||||
|
||||
&.danger {
|
||||
@apply border-amber-900 bg-amber-900 hover:bg-amber-800;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,3 @@
|
||||
export { default as ConfirmModal } from './ConfirmModal.vue';
|
||||
export { confirm, useConfirmStore } from './useConfirm';
|
||||
export type { ConfirmOptions } from './useConfirm';
|
||||
@@ -0,0 +1,37 @@
|
||||
import {defineStore} from "pinia";
|
||||
import {ref} from "vue";
|
||||
|
||||
export interface ConfirmOptions {
|
||||
title?: string;
|
||||
message: string;
|
||||
confirmLabel?: string;
|
||||
cancelLabel?: string;
|
||||
danger?: boolean;
|
||||
}
|
||||
|
||||
export const useConfirmStore = defineStore('confirm', () => {
|
||||
const open = ref(false);
|
||||
const options = ref<ConfirmOptions>({message: ""});
|
||||
let resolver: ((value: boolean) => void) | undefined;
|
||||
|
||||
const settle = (value: boolean) => {
|
||||
open.value = false;
|
||||
resolver?.(value);
|
||||
resolver = undefined;
|
||||
};
|
||||
|
||||
const confirm = (opts: ConfirmOptions | string): Promise<boolean> => {
|
||||
options.value = typeof opts === "string" ? {message: opts} : opts;
|
||||
open.value = true;
|
||||
return new Promise<boolean>(resolve => {
|
||||
resolver = resolve;
|
||||
});
|
||||
};
|
||||
|
||||
const accept = () => settle(true);
|
||||
const cancel = () => settle(false);
|
||||
|
||||
return {open, options, confirm, accept, cancel};
|
||||
});
|
||||
|
||||
export const confirm = (opts: ConfirmOptions | string): Promise<boolean> => useConfirmStore().confirm(opts);
|
||||
+131
-33
@@ -71,14 +71,8 @@ export interface CreateRuleBookRequest {
|
||||
'name': string;
|
||||
'usedForAcquisitions': boolean;
|
||||
'ledgerRefs': Array<string>;
|
||||
'rules': { [key: string]: RuleResponse; };
|
||||
'script': string;
|
||||
}
|
||||
export interface IskRuleClauseResponse extends RuleClauseResponse {
|
||||
'fromLedgerRef': string;
|
||||
'toLedgerRef': string;
|
||||
}
|
||||
|
||||
|
||||
export interface IskTransferResponse extends TransferResponse {
|
||||
'fromLedgerId': string;
|
||||
'toLedgerId': string;
|
||||
@@ -88,22 +82,6 @@ export interface ItemBalanceResponse {
|
||||
'typeId': number;
|
||||
'quantity': number;
|
||||
}
|
||||
export interface ItemExchangeRuleClauseResponse extends RuleClauseResponse {
|
||||
'rate': ItemExchangeRuleClauseResponseRateEnum;
|
||||
'fromLedgerRef': string;
|
||||
'toLedgerRef': string;
|
||||
}
|
||||
|
||||
export const ItemExchangeRuleClauseResponseRateEnum = {
|
||||
None: 'NONE',
|
||||
Value: 'VALUE',
|
||||
JitaBuy: 'JITA_BUY',
|
||||
JitaSell: 'JITA_SELL',
|
||||
EveEstimate: 'EVE_ESTIMATE',
|
||||
} as const;
|
||||
|
||||
export type ItemExchangeRuleClauseResponseRateEnum = typeof ItemExchangeRuleClauseResponseRateEnum[keyof typeof ItemExchangeRuleClauseResponseRateEnum];
|
||||
|
||||
export interface ItemTransferResponse extends TransferResponse {
|
||||
'fromLedgerId': string;
|
||||
'toLedgerId': string;
|
||||
@@ -125,15 +103,7 @@ export interface RuleBookResponse {
|
||||
'name': string;
|
||||
'usedForAcquisitions': boolean;
|
||||
'ledgerRefs': Array<string>;
|
||||
'rules': { [key: string]: RuleResponse; };
|
||||
}
|
||||
/**
|
||||
* @type RuleClauseResponse
|
||||
*/
|
||||
export type RuleClauseResponse = { type: 'ISK' } & IskRuleClauseResponse | { type: 'ITEM_EXCHANGE' } & ItemExchangeRuleClauseResponse;
|
||||
|
||||
export interface RuleResponse {
|
||||
'clauses': Array<RuleClauseResponse>;
|
||||
'script': string;
|
||||
}
|
||||
export interface SetCharacterRuleBookRequest {
|
||||
'ruleBookId': string;
|
||||
@@ -162,7 +132,7 @@ export interface UpdateRuleBookRequest {
|
||||
'name': string;
|
||||
'usedForAcquisitions': boolean;
|
||||
'ledgerRefs': Array<string>;
|
||||
'rules': { [key: string]: RuleResponse; };
|
||||
'script': string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1343,6 +1313,39 @@ export const RuleBookApiAxiosParamCreator = function (configuration?: Configurat
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Delete a rule book
|
||||
* @param {string} ruleBookId Id of the rule book
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
deleteRuleBook: async (ruleBookId: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'ruleBookId' is not null or undefined
|
||||
assertParamExists('deleteRuleBook', 'ruleBookId', ruleBookId)
|
||||
const localVarPath = `/rule-books/{ruleBookId}`
|
||||
.replace('{ruleBookId}', encodeURIComponent(String(ruleBookId)));
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Find all rule books
|
||||
@@ -1407,6 +1410,36 @@ export const RuleBookApiAxiosParamCreator = function (configuration?: Configurat
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Download the TypeScript definitions for the rule script runtime
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getScriptDefinitions: async (options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
const localVarPath = `/rule-books/script-definitions`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
localVarHeaderParameter['Accept'] = 'text/plain';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Update a rule book
|
||||
@@ -1468,6 +1501,19 @@ export const RuleBookApiFp = function(configuration?: Configuration) {
|
||||
const localVarOperationServerBasePath = operationServerMap['RuleBookApi.createRuleBook']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Delete a rule book
|
||||
* @param {string} ruleBookId Id of the rule book
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async deleteRuleBook(ruleBookId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.deleteRuleBook(ruleBookId, options);
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||
const localVarOperationServerBasePath = operationServerMap['RuleBookApi.deleteRuleBook']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Find all rule books
|
||||
@@ -1493,6 +1539,18 @@ export const RuleBookApiFp = function(configuration?: Configuration) {
|
||||
const localVarOperationServerBasePath = operationServerMap['RuleBookApi.findRuleBookById']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Download the TypeScript definitions for the rule script runtime
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async getScriptDefinitions(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<string>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getScriptDefinitions(options);
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||
const localVarOperationServerBasePath = operationServerMap['RuleBookApi.getScriptDefinitions']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Update a rule book
|
||||
@@ -1526,6 +1584,16 @@ export const RuleBookApiFactory = function (configuration?: Configuration, baseP
|
||||
createRuleBook(createRuleBookRequest: CreateRuleBookRequest, options?: RawAxiosRequestConfig): AxiosPromise<RuleBookResponse> {
|
||||
return localVarFp.createRuleBook(createRuleBookRequest, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Delete a rule book
|
||||
* @param {string} ruleBookId Id of the rule book
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
deleteRuleBook(ruleBookId: string, options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
||||
return localVarFp.deleteRuleBook(ruleBookId, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Find all rule books
|
||||
@@ -1545,6 +1613,15 @@ export const RuleBookApiFactory = function (configuration?: Configuration, baseP
|
||||
findRuleBookById(ruleBookId: string, options?: RawAxiosRequestConfig): AxiosPromise<RuleBookResponse> {
|
||||
return localVarFp.findRuleBookById(ruleBookId, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Download the TypeScript definitions for the rule script runtime
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getScriptDefinitions(options?: RawAxiosRequestConfig): AxiosPromise<string> {
|
||||
return localVarFp.getScriptDefinitions(options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @summary Update a rule book
|
||||
@@ -1574,6 +1651,17 @@ export class RuleBookApi extends BaseAPI {
|
||||
return RuleBookApiFp(this.configuration).createRuleBook(createRuleBookRequest, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @summary Delete a rule book
|
||||
* @param {string} ruleBookId Id of the rule book
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
public deleteRuleBook(ruleBookId: string, options?: RawAxiosRequestConfig) {
|
||||
return RuleBookApiFp(this.configuration).deleteRuleBook(ruleBookId, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @summary Find all rule books
|
||||
@@ -1595,6 +1683,16 @@ export class RuleBookApi extends BaseAPI {
|
||||
return RuleBookApiFp(this.configuration).findRuleBookById(ruleBookId, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @summary Download the TypeScript definitions for the rule script runtime
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
public getScriptDefinitions(options?: RawAxiosRequestConfig) {
|
||||
return RuleBookApiFp(this.configuration).getScriptDefinitions(options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @summary Update a rule book
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import {
|
||||
BalanceResponse,
|
||||
CombinedLedgerResponse,
|
||||
CombinedLedgerResponseTypeEnum,
|
||||
CreateCombinedLedgerRequest,
|
||||
CreateMainLedgerRequest,
|
||||
LedgerResponseTypeEnum,
|
||||
LedgerResponse,
|
||||
MainLedgerResponse,
|
||||
MainLedgerResponseTypeEnum,
|
||||
TransactionResponse,
|
||||
UpdateCombinedLedgerRequest,
|
||||
UpdateMainLedgerRequest
|
||||
@@ -16,11 +14,14 @@ import {computed, ref, triggerRef} from "vue";
|
||||
import {ledgerApi, transactionApi} from "@/mammon";
|
||||
import {useRouteParams} from "@vueuse/router";
|
||||
|
||||
export const LedgerTypes = LedgerResponseTypeEnum;
|
||||
export const LedgerTypes = {
|
||||
Main: 'MAIN',
|
||||
Combined: 'COMBINED',
|
||||
};
|
||||
|
||||
export type LedgerType = LedgerResponseTypeEnum;
|
||||
export type MainLedger = MainLedgerResponse & {type: MainLedgerResponseTypeEnum}
|
||||
export type CombinedLedger = CombinedLedgerResponse & {type: CombinedLedgerResponseTypeEnum}
|
||||
export type LedgerType = LedgerResponse['type'];
|
||||
export type MainLedger = MainLedgerResponse
|
||||
export type CombinedLedger = CombinedLedgerResponse
|
||||
export type Ledger = MainLedger | CombinedLedger;
|
||||
|
||||
export const systemLedgerRef = 'system';
|
||||
|
||||
@@ -15,7 +15,7 @@ import {isMain, Ledger, LedgerSelect, systemLedger, useLedgersStore} from "@/led
|
||||
type Bindings = { [key: string]: Ledger; };
|
||||
|
||||
const ruleBookStore = useRuleBooksStore();
|
||||
const {findById: findCharacterRuleBookById} = ruleBookStore;
|
||||
const {findById: findRuleBookById} = ruleBookStore;
|
||||
const {ruleBooks} = storeToRefs(ruleBookStore);
|
||||
const {findById: findCharacterById} = useCharactersStore();
|
||||
const {ledgers} = storeToRefs(useLedgersStore());
|
||||
@@ -33,7 +33,7 @@ watchEffect(async () => {
|
||||
if (characterId) {
|
||||
const characterRuleBook = await findCharacterRuleBookByCharacterId(characterId);
|
||||
|
||||
ruleBook.value = findCharacterRuleBookById(characterRuleBook.ruleBookId);
|
||||
ruleBook.value = findRuleBookById(characterRuleBook.ruleBookId);
|
||||
bindings.value = Object.fromEntries(
|
||||
Object.entries(characterRuleBook.bindings)
|
||||
.map(([key, id]) => [key, ledgersToUse.value.find(l => l.ledgerId === id) ?? systemLedger])
|
||||
@@ -88,7 +88,7 @@ watch(useRoute(), async route => {
|
||||
<div class="flex flex-wrap items-center mb-2 mt-2">
|
||||
<div class="me-2" v-for="ref in ledgerRefs" :ref="ref">
|
||||
<span class="me-1">{{ref}}:</span>
|
||||
<LedgerSelect :ledgers="ledgersToUse" :modelValue="bindings[ref] ?? systemLedger" @update:modelValue="value => bindings[ref] = value" />
|
||||
<LedgerSelect :ledgers="ledgersToUse" :modelValue="bindings[ref] ?? systemLedger" @update:modelValue="value => { if (value) bindings[ref] = value }" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import {ref, watch} from "vue";
|
||||
import {useDebounceFn} from "@vueuse/core";
|
||||
import {useDebounceFn, useEventListener} from "@vueuse/core";
|
||||
import log from "loglevel";
|
||||
import {activityTypes, RuleInput, Rules, useRuleBooksStore} from "@/rules";
|
||||
import {ScriptEditor, useRuleBooksStore} from "@/rules";
|
||||
import {PlusIcon, TrashIcon} from "@heroicons/vue/24/outline";
|
||||
import {routeNames} from "@/routes";
|
||||
import {Dropdown} from "@/components";
|
||||
import {SliderCheckbox} from "@/components";
|
||||
|
||||
const ruleBookId = ref<string>();
|
||||
const name = ref<string>('');
|
||||
const usedForAcquisitions = ref<boolean>(false);
|
||||
const ledgerRefs = ref<string[]>([]);
|
||||
const rules = ref<Rules>({});
|
||||
const script = ref<string>('');
|
||||
|
||||
const {findById, create, update, refresh} = useRuleBooksStore();
|
||||
const router = useRouter();
|
||||
@@ -20,20 +21,29 @@ const save = async () => {
|
||||
if (!ruleBookId.value) {
|
||||
const created = await create({
|
||||
name: name.value,
|
||||
usedForAcquisitions: usedForAcquisitions.value,
|
||||
ledgerRefs: ledgerRefs.value,
|
||||
rules: rules.value
|
||||
script: script.value
|
||||
})
|
||||
await router.push({ name: routeNames.editRuleBook, params: {ruleBookId: created.ruleBookId}})
|
||||
|
||||
} else {
|
||||
await update(ruleBookId.value, {
|
||||
name: name.value,
|
||||
usedForAcquisitions: usedForAcquisitions.value,
|
||||
ledgerRefs: ledgerRefs.value,
|
||||
rules: rules.value
|
||||
script: script.value
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
useEventListener(window, 'keydown', (event: KeyboardEvent) => {
|
||||
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 's') {
|
||||
event.preventDefault();
|
||||
save();
|
||||
}
|
||||
}, {capture: true});
|
||||
|
||||
const addLedgerRef = () => {
|
||||
ledgerRefs.value = [...ledgerRefs.value, '']
|
||||
}
|
||||
@@ -57,31 +67,37 @@ watch(useRoute(), async route => {
|
||||
|
||||
ruleBookId.value = id;
|
||||
name.value = ruleBook?.name ?? '';
|
||||
ledgerRefs.value = [...ruleBook?.ledgerRefs];
|
||||
rules.value = {...ruleBook?.rules}; // TODO fully clone rules
|
||||
usedForAcquisitions.value = ruleBook?.usedForAcquisitions ?? false;
|
||||
ledgerRefs.value = [...(ruleBook?.ledgerRefs ?? [])];
|
||||
script.value = ruleBook?.script ?? '';
|
||||
log.info('Loaded rule book:', ruleBook);
|
||||
} else {
|
||||
ruleBookId.value = undefined;
|
||||
name.value = '';
|
||||
usedForAcquisitions.value = false;
|
||||
ledgerRefs.value = [];
|
||||
rules.value = {};
|
||||
script.value = '';
|
||||
log.info('No rule book to load');
|
||||
}
|
||||
}, { immediate: true })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid mb-2 mt-4">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-col mb-2 mt-4 h-[calc(100vh-4.5rem)]">
|
||||
<div class="flex flex-col grow min-h-0">
|
||||
<div class="flex grow border-b-1">
|
||||
Name:
|
||||
<input class="mb-2 ms-2" type="text" v-model="name" />
|
||||
<label class="flex items-center ms-2 mb-2">
|
||||
<SliderCheckbox class="me-2" v-model="usedForAcquisitions" />
|
||||
Used for acquisitions
|
||||
</label>
|
||||
</div>
|
||||
<div class="border-b-1">
|
||||
Ledgers References:
|
||||
<div class="flex flex-wrap items-center">
|
||||
<div class="flex flex-wrap items-center mt-2">
|
||||
<div class="flex items-center mb-2" v-for="(ledgerRef, index) in ledgerRefs" :key="index">
|
||||
<input class="me-1" type="text" :value="ledgerRefs[index]" @input="updateLedgerRef(index, ($event.target as HTMLInputElement).value)" />
|
||||
<input class="me-1" type="text" :value="ledgerRef" @input="updateLedgerRef(index, ($event.target as HTMLInputElement).value)" />
|
||||
<button class="btn-icon me-2" @click="removeLedgerRef(index)"><TrashIcon /></button>
|
||||
</div>
|
||||
<div class="flex items-center mb-2">
|
||||
@@ -89,14 +105,9 @@ watch(useRoute(), async route => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col grow border-b-1" v-for="activityType in activityTypes" :key="activityType.key">
|
||||
<Dropdown :inline="true" :autoClose="false" class="rule-dropdown">
|
||||
<template #button>
|
||||
<span>{{ activityType.name }}</span>
|
||||
</template>
|
||||
<RuleInput :ledgerRefs="ledgerRefs" :activityType="activityType.key" v-model="rules[activityType.key]" />
|
||||
</Dropdown>
|
||||
|
||||
<div class="flex flex-col grow min-h-0 border-b-1">
|
||||
Script:
|
||||
<ScriptEditor class="mt-2 mb-2" v-model="script" :ledgerRefs="ledgerRefs" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 justify-end flex">
|
||||
@@ -105,16 +116,4 @@ watch(useRoute(), async route => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "@/style.css";
|
||||
|
||||
.rule-dropdown :deep(>button) {
|
||||
@apply bg-slate-800 hover:bg-slate-800 border-none flex items-center w-full;
|
||||
}
|
||||
|
||||
.rule-dropdown.dropdown-open :deep(>button) {
|
||||
@apply bg-slate-800 rounded-b-none;
|
||||
}
|
||||
</style>
|
||||
</template>
|
||||
@@ -1,18 +1,57 @@
|
||||
<script setup lang="ts">
|
||||
import {storeToRefs} from "pinia";
|
||||
import {CharacterLabel, useCharactersStore} from "@/characters";
|
||||
import {Character, CharacterLabel, useCharactersStore} from "@/characters";
|
||||
import {PencilSquareIcon} from "@heroicons/vue/24/outline";
|
||||
import {routeNames} from "@/routes";
|
||||
import {findCharacterRuleBookByCharacterId, useRuleBooksStore} from "@/rules";
|
||||
import {computedAsync} from "@vueuse/core";
|
||||
import {routeNames} from "@/routes.ts";
|
||||
import {SortableHeader, useSort} from "@/components/table";
|
||||
|
||||
type CharacterRuleBookView = {
|
||||
character: Character;
|
||||
characterName: string;
|
||||
characterId: number;
|
||||
ruleBookName: string;
|
||||
}
|
||||
|
||||
const {characters} = storeToRefs(useCharactersStore());
|
||||
const {findById: findRuleBookById} = useRuleBooksStore();
|
||||
|
||||
|
||||
const { sortedArray, headerProps } = useSort(computedAsync<CharacterRuleBookView[]>(async () => await Promise.all(characters.value.map(async (character: Character): Promise<CharacterRuleBookView> => {
|
||||
const characterRuleBook = await findCharacterRuleBookByCharacterId(character.characterId);
|
||||
const ruleBook = findRuleBookById(characterRuleBook.ruleBookId);
|
||||
|
||||
return {
|
||||
character,
|
||||
characterName: character.name,
|
||||
characterId: character.characterId,
|
||||
ruleBookName: ruleBook?.name ?? ''
|
||||
}
|
||||
})), []))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid mb-2 mt-4">
|
||||
<div v-for="character in characters" :key="character.characterId" class="flex items-center mb-2">
|
||||
<CharacterLabel class="flex grow" :character="character" />
|
||||
<RouterLink class="btn-icon ms-2" :to="{ name: routeNames.editCharacterRulebook, params: { characterId: character.characterId } }"><PencilSquareIcon /></RouterLink>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<SortableHeader v-bind="headerProps" sortKey="characterName">Character</SortableHeader>
|
||||
<SortableHeader v-bind="headerProps" sortKey="ruleBookName">Rule Book</SortableHeader>
|
||||
<SortableHeader v-bind="headerProps" sortKey="buttons" unsortable />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="characterRuleBookView in sortedArray" :key="characterRuleBookView.characterId" >
|
||||
<td>
|
||||
<CharacterLabel :character="characterRuleBookView.character" />
|
||||
</td>
|
||||
<td>{{characterRuleBookView.ruleBookName}}</td>
|
||||
<td class="text-right">
|
||||
<RouterLink class="btn-icon" :to="{ name: routeNames.editCharacterRulebook, params: { characterId: characterRuleBookView.characterId } }"><PencilSquareIcon /></RouterLink>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,10 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import {storeToRefs} from "pinia";
|
||||
import {PencilSquareIcon, TrashIcon} from "@heroicons/vue/24/outline";
|
||||
import {useRuleBooksStore} from "@/rules";
|
||||
import {DocumentDuplicateIcon, PencilSquareIcon, TrashIcon} from "@heroicons/vue/24/outline";
|
||||
import {confirm} from "@/confirm";
|
||||
import {RuleBook, useRuleBooksStore} from "@/rules";
|
||||
import {routeNames} from "@/routes";
|
||||
|
||||
const {ruleBooks} = storeToRefs(useRuleBooksStore());
|
||||
const ruleBooksStore = useRuleBooksStore();
|
||||
const {ruleBooks} = storeToRefs(ruleBooksStore);
|
||||
|
||||
const duplicate = async (ruleBook: RuleBook) => {
|
||||
if (await confirm({title: "Duplicate Rule Book", message: `Duplicate ${ruleBook.name}?`, confirmLabel: "Duplicate"})) {
|
||||
await ruleBooksStore.duplicate(ruleBook);
|
||||
}
|
||||
};
|
||||
|
||||
const remove = async (ruleBook: RuleBook) => {
|
||||
if (await confirm({title: "Delete Rule Book", message: `Delete ${ruleBook.name}?`, confirmLabel: "Delete", danger: true})) {
|
||||
await ruleBooksStore.remove(ruleBook.ruleBookId);
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
@@ -16,7 +30,8 @@ const {ruleBooks} = storeToRefs(useRuleBooksStore());
|
||||
<div v-for="ruleBook in ruleBooks" :key="ruleBook.ruleBookId" class="flex items-center mt-2">
|
||||
<span class="flex grow me-2">{{ruleBook.name}}</span>
|
||||
<RouterLink class="btn-icon me-1" :to="{ name: routeNames.editRuleBook, params: { ruleBookId: ruleBook.ruleBookId } }"><PencilSquareIcon /></RouterLink>
|
||||
<button class="btn-icon"><TrashIcon /></button>
|
||||
<button class="btn-icon me-1" @click="duplicate(ruleBook)"><DocumentDuplicateIcon /></button>
|
||||
<button class="btn-icon text-amber-700 hover:text-amber-600" @click="remove(ruleBook)"><TrashIcon /></button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,26 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {systemLedger, systemLedgerRef} from "@/ledger";
|
||||
|
||||
interface Props {
|
||||
ledgerRefs: string[];
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
|
||||
const ledgerRef = defineModel<string>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<select v-model="ledgerRef" :class="{'system-ledger': ledgerRef === systemLedgerRef}">
|
||||
<option v-for="l in ledgerRefs" :key="l" :value="l" :class="{'system-ledger': l === systemLedgerRef}">{{ l === systemLedgerRef ? systemLedger.name : l }}</option>
|
||||
</select>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "@/style.css";
|
||||
|
||||
.system-ledger {
|
||||
@apply text-emerald-400;
|
||||
}
|
||||
</style>
|
||||
@@ -1,53 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {ItemExchangeRuleClauseResponse, ItemExchangeRuleClauseResponseRateEnum, RuleClauseResponse} from "@/generated/mammon";
|
||||
import {computed, watch} from "vue";
|
||||
import {systemLedgerRef} from "@/ledger";
|
||||
import {ratesTypes} from "@/rules/rules.ts";
|
||||
import LedgerRefSelect from "./LedgerRefSelect.vue";
|
||||
|
||||
interface Props {
|
||||
ledgerRefs: string[];
|
||||
hasRate: boolean;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const rule = defineModel<RuleClauseResponse>({ default: {
|
||||
type: 'ITEM_EXCHANGE',
|
||||
rate: ItemExchangeRuleClauseResponseRateEnum.None,
|
||||
fromLedgerRef: systemLedgerRef,
|
||||
toLedgerRef: systemLedgerRef,
|
||||
}});
|
||||
|
||||
// Only item-exchange clauses carry a rate; narrow for the rate <select>.
|
||||
const itemRule = computed(() => rule.value as ItemExchangeRuleClauseResponse)
|
||||
|
||||
const ledgerRefsWithSystem = computed<string[]>(() => [systemLedgerRef, ...props.ledgerRefs])
|
||||
|
||||
watch(ledgerRefsWithSystem, (newVal, oldVal) => {
|
||||
if (newVal.length !== oldVal.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rule.value.fromLedgerRef && rule.value.fromLedgerRef !== systemLedgerRef) {
|
||||
rule.value.fromLedgerRef = newVal[oldVal.findIndex(v => v === rule.value.fromLedgerRef)]
|
||||
}
|
||||
if (rule.value.toLedgerRef && rule.value.toLedgerRef !== systemLedgerRef) {
|
||||
rule.value.toLedgerRef = newVal[oldVal.findIndex(v => v === rule.value.toLedgerRef)]
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
From:
|
||||
<LedgerRefSelect class="me-2 grow" v-model="rule.fromLedgerRef" :ledger-refs="ledgerRefsWithSystem"/>
|
||||
To:
|
||||
<LedgerRefSelect class="me-2 grow" v-model="rule.toLedgerRef" :ledger-refs="ledgerRefsWithSystem"/>
|
||||
<template v-if="hasRate">
|
||||
At:
|
||||
<select class="me-2 grow" v-model="itemRule.rate">
|
||||
<option v-for="rateType in ratesTypes" :key="rateType.key" :value="rateType.key">{{ rateType.name }}</option>
|
||||
</select>
|
||||
</template>
|
||||
</template>
|
||||
@@ -1,79 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {ItemExchangeRuleClauseResponseRateEnum, RuleClauseResponse, 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";
|
||||
import {systemLedgerRef} from "@/ledger";
|
||||
import {ActivityType, activityTypeHasRate} from "@/rules/rules.ts";
|
||||
|
||||
interface Props {
|
||||
ledgerRefs: string[];
|
||||
activityType: ActivityType;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const hasRate = computed<boolean>(() => activityTypeHasRate(props.activityType));
|
||||
|
||||
const rule = defineModel<RuleResponse>({default: {clauses:[]}});
|
||||
const clauses = computed<RuleClauseResponse[]>({
|
||||
get: () => rule.value && rule.value.clauses ? rule.value.clauses : [],
|
||||
set: value => rule.value = {clauses: value}
|
||||
})
|
||||
|
||||
const addClause = () => {
|
||||
const clause: RuleClauseResponse = hasRate.value
|
||||
? {type: 'ITEM_EXCHANGE', rate: ItemExchangeRuleClauseResponseRateEnum.None, fromLedgerRef: systemLedgerRef, toLedgerRef: systemLedgerRef}
|
||||
: {type: 'ISK', fromLedgerRef: systemLedgerRef, toLedgerRef: systemLedgerRef};
|
||||
clauses.value = [...clauses.value, clause]
|
||||
}
|
||||
|
||||
const setClause = (index: number, clause?: RuleClauseResponse) => {
|
||||
if (!clause) {
|
||||
return;
|
||||
}
|
||||
clauses.value = clauses.value.with(index, clause)
|
||||
}
|
||||
|
||||
const removeClause = (index: number) => {
|
||||
clauses.value = clauses.value.toSpliced(index, 1)
|
||||
}
|
||||
|
||||
const sortableContainer = useTemplateRef('sortable-container')
|
||||
useSortable(sortableContainer, clauses, { 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="(clause, index) in clauses" :key="index">
|
||||
<span class="sortable-handle flex">
|
||||
<Bars4Icon class="w-6"/>
|
||||
</span>
|
||||
<RuleClauseInput :ledgerRefs="ledgerRefs" :hasRate="hasRate" :modelValue="clause" @update:modelValue="v => setClause(index, v)" />
|
||||
<button class="btn-icon" @click="removeClause(index)"><TrashIcon /></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end mb-2 mt-2">
|
||||
<button class="btn-icon" @click="addClause"><PlusIcon /></button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "@/style.css";
|
||||
|
||||
.sortable-handle {
|
||||
@apply cursor-grab;
|
||||
}
|
||||
|
||||
.sortable-chosen {
|
||||
@apply cursor-grabbing;
|
||||
}
|
||||
|
||||
.sortable-chosen .sortable-handle {
|
||||
@apply cursor-grabbing;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,104 @@
|
||||
<script setup lang="ts">
|
||||
import * as monaco from 'monaco-editor';
|
||||
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
|
||||
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
|
||||
import {onBeforeUnmount, onMounted, ref, watch} from 'vue';
|
||||
import {fetchScriptDefinitions} from './rules';
|
||||
|
||||
(self as unknown as { MonacoEnvironment: { getWorker(workerId: string, label: string): Worker } }).MonacoEnvironment = {
|
||||
getWorker(_workerId: string, label: string) {
|
||||
if (label === 'typescript' || label === 'javascript') {
|
||||
return new tsWorker();
|
||||
}
|
||||
return new editorWorker();
|
||||
}
|
||||
};
|
||||
|
||||
let extraLibLoaded = false;
|
||||
|
||||
const loadScriptDefinitions = async () => {
|
||||
if (extraLibLoaded) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const definitions = await fetchScriptDefinitions();
|
||||
monaco.typescript.javascriptDefaults.addExtraLib(definitions, 'ts:rule-runner.d.ts');
|
||||
extraLibLoaded = true;
|
||||
} catch {
|
||||
// type definitions are optional — the editor still works without autocomplete
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps<{ ledgerRefs?: string[] }>();
|
||||
|
||||
let ledgersLib: monaco.IDisposable | undefined;
|
||||
|
||||
const updateLedgerRefs = (refs: readonly string[]) => {
|
||||
ledgersLib?.dispose();
|
||||
const members = refs
|
||||
.filter(ref => ref && ref !== 'system')
|
||||
.map(ref => ` readonly ${JSON.stringify(ref)}: Ledger;`)
|
||||
.join('\n');
|
||||
ledgersLib = monaco.typescript.javascriptDefaults.addExtraLib(
|
||||
`declare interface Ledgers {\n${members}\n}\n`,
|
||||
'ts:rule-runner.ledgers.d.ts'
|
||||
);
|
||||
};
|
||||
|
||||
const model = defineModel<string>({default: ''});
|
||||
const container = ref<HTMLElement>();
|
||||
let editor: monaco.editor.IStandaloneCodeEditor | undefined;
|
||||
|
||||
onMounted(async () => {
|
||||
await loadScriptDefinitions();
|
||||
updateLedgerRefs(props.ledgerRefs ?? []);
|
||||
|
||||
if (!container.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
editor = monaco.editor.create(container.value, {
|
||||
value: model.value,
|
||||
language: 'javascript',
|
||||
theme: 'vs-dark',
|
||||
automaticLayout: true,
|
||||
minimap: {enabled: false},
|
||||
scrollBeyondLastLine: false,
|
||||
fontSize: 13,
|
||||
tabSize: 2,
|
||||
});
|
||||
|
||||
editor.onDidChangeModelContent(() => {
|
||||
const value = editor!.getValue();
|
||||
|
||||
if (value !== model.value) {
|
||||
model.value = value;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
watch(model, value => {
|
||||
if (editor && value !== editor.getValue()) {
|
||||
editor.setValue(value ?? '');
|
||||
}
|
||||
});
|
||||
|
||||
watch(() => props.ledgerRefs, refs => updateLedgerRefs(refs ?? []), {deep: true});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
editor?.dispose();
|
||||
ledgersLib?.dispose();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="container" class="script-editor"></div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.script-editor {
|
||||
width: 100%;
|
||||
flex: 1 1 auto;
|
||||
min-height: 12rem;
|
||||
}
|
||||
</style>
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
export * from "./rules";
|
||||
|
||||
export {default as RuleInput} from './RuleInput.vue';
|
||||
export {default as ScriptEditor} from './ScriptEditor.vue';
|
||||
+18
-31
@@ -2,39 +2,13 @@ import {characterRuleBookApi, ruleBookApi} from "@/mammon";
|
||||
import {
|
||||
CharacterRuleBookResponse,
|
||||
CreateRuleBookRequest,
|
||||
ItemExchangeRuleClauseResponseRateEnum,
|
||||
RuleBookResponse,
|
||||
RuleResponse,
|
||||
SetCharacterRuleBookRequest
|
||||
} from "@/generated/mammon";
|
||||
import {defineStore} from "pinia";
|
||||
import {ref, triggerRef} from "vue";
|
||||
|
||||
export const activityTypes = {
|
||||
itemBought: {key: "ITEM_BOUGHT", name: "Item Bought"},
|
||||
itemSold: {key: "ITEM_SOLD", name: "Item Sold"},
|
||||
itemAcquiredManually: {key: "ITEM_ACQUIRED_MANUALLY", name: "Item Acquired Manually"},
|
||||
itemConsumedManually: {key: "ITEM_CONSUME_MANUALLY", name: "Item Consumed Manually"},
|
||||
bountyEarned: {key: "BOUNTY_EARNED", name: "Bounty Earned"},
|
||||
// itemManufactured: {id: "ITEM_MANUFACTURED", name: "Item Manufactured"}
|
||||
} as const;
|
||||
|
||||
export type Activity = { key: ActivityType, name: string }
|
||||
export type ActivityType = typeof activityTypes[keyof typeof activityTypes]['key'];
|
||||
export type Rules = { [key: ActivityType]: RuleResponse; };
|
||||
export type RuleBook = RuleBookResponse & { rules: Rules }
|
||||
|
||||
export const activityTypeHasRate = (key: ActivityType): boolean => key !== activityTypes.bountyEarned.key;
|
||||
|
||||
export const ratesTypes = {
|
||||
None: {key: "NONE", name: "0 ISK"},
|
||||
Value: {key: "VALUE", name: "Value"},
|
||||
JitaBuy: {key: "JITA_BUY", name: "Jita Buy Order"},
|
||||
JitaSell: {key: "JITA_SELL", name: "Jita Sell Order"},
|
||||
EveEstimate: {key: "EVE_ESTIMATE", name: "Eve Estimate"},
|
||||
} as const;
|
||||
|
||||
export type Rate = { key: ItemExchangeRuleClauseResponseRateEnum, name: string }
|
||||
export type RuleBook = RuleBookResponse;
|
||||
|
||||
export const useRuleBooksStore = defineStore('rule-books', () => {
|
||||
const ruleBooks = ref<RuleBook[]>([]);
|
||||
@@ -58,17 +32,30 @@ export const useRuleBooksStore = defineStore('rule-books', () => {
|
||||
const findById = (ruleBookId: string): RuleBook | undefined => ruleBooks.value.find(rb => rb.ruleBookId === ruleBookId);
|
||||
const create = (ruleBook: CreateRuleBookRequest) => ruleBookApi.createRuleBook(ruleBook).then(response => addRuleBook(response.data));
|
||||
const update = (ruleBookId: string, ruleBook: CreateRuleBookRequest) => ruleBookApi.updateRuleBook(ruleBookId, ruleBook).then(response => replaceRuleBook(response.data));
|
||||
const duplicate = (ruleBook: RuleBook) => create({
|
||||
name: `${ruleBook.name} (copy)`,
|
||||
usedForAcquisitions: ruleBook.usedForAcquisitions,
|
||||
ledgerRefs: [...ruleBook.ledgerRefs],
|
||||
script: ruleBook.script,
|
||||
});
|
||||
|
||||
const refresh = () => ruleBookApi.findAllRuleBooks().then(response => ruleBooks.value = response.data as RuleBook[]);
|
||||
const remove = (ruleBookId: string) => ruleBookApi.deleteRuleBook(ruleBookId).then(() => {
|
||||
ruleBooks.value = ruleBooks.value.filter(rb => rb.ruleBookId !== ruleBookId);
|
||||
});
|
||||
|
||||
const refresh = () => ruleBookApi.findAllRuleBooks().then(response => ruleBooks.value = response.data);
|
||||
|
||||
refresh();
|
||||
|
||||
return {ruleBooks, findById, create, update, refresh};
|
||||
return {ruleBooks, findById, create, update, duplicate, remove, refresh};
|
||||
})
|
||||
|
||||
export const findCharacterRuleBookByCharacterId = (characterId: number): Promise<CharacterRuleBookResponse> => characterRuleBookApi.findCharacterRuleBookByCharacterId(characterId)
|
||||
.then(response => response.data)
|
||||
.catch(() => ({characterId, rules: {}}));
|
||||
.catch(() => ({characterId, ruleBookId: '', bindings: {}}));
|
||||
|
||||
export const setCharacterRuleBookForCharacter = (characterId: number, ruleBook: SetCharacterRuleBookRequest): Promise<CharacterRuleBookResponse> => characterRuleBookApi.setCharacterRuleBookForCharacter(characterId, ruleBook)
|
||||
.then(response => response.data);
|
||||
.then(response => response.data);
|
||||
|
||||
export const fetchScriptDefinitions = (): Promise<string> =>
|
||||
ruleBookApi.getScriptDefinitions({responseType: 'text'}).then(response => response.data);
|
||||
@@ -1,14 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {Transfer, TransferTypes} from "@/transaction/transaction.ts";
|
||||
import {TransferTypes} from "@/transaction/transaction.ts";
|
||||
import {LedgerLabel, systemLedger, useLedgersStore} from "@/ledger";
|
||||
import {getMarketType, IskLabel, MarketTypeLabel} from "@/market";
|
||||
import {computedAsync} from "@vueuse/core";
|
||||
import {TransferResponse} from "@/generated/mammon";
|
||||
|
||||
type TransferWithValue = Transfer & { marketTypeId: number; };
|
||||
type TransferWithValue = TransferResponse & { marketTypeId: number; };
|
||||
|
||||
interface Props {
|
||||
transfers?: Transfer[]
|
||||
transfers?: TransferResponse[]
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import {TransactionResponseTransfersInner, TransferResponseTypeEnum} from "@/generated/mammon";
|
||||
import {TransferResponse} from "@/generated/mammon";
|
||||
|
||||
export const TransferTypes = TransferResponseTypeEnum;
|
||||
export type TransferType = TransferResponseTypeEnum;
|
||||
export type Transfer = TransactionResponseTransfersInner;
|
||||
export const TransferTypes = {
|
||||
Isk: 'ISK',
|
||||
Item: 'ITEM',
|
||||
} as const;
|
||||
export type TransferType = TransferResponse['type'];
|
||||
|
||||
Reference in New Issue
Block a user