6 Commits

Author SHA1 Message Date
Sirttas 9cd0d5fb5e rule book dup/delete 2026-06-09 23:44:16 +02:00
Sirttas 5ac369a643 fix 2026-06-09 21:56:12 +02:00
Sophie-Gaëlle CALLOCH b2c97c1327 rulebook name 2026-06-09 18:00:25 +02:00
Sirttas 4ae044dace win size 2026-06-08 18:54:53 +02:00
Sirttas c444f51423 js editor + fix js runner 2026-06-08 08:27:42 +02:00
Sirttas a201a95756 js editor + fix js runner 2026-06-07 23:18:53 +02:00
13 changed files with 368 additions and 31 deletions
+34 -3
View File
@@ -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:
@@ -426,7 +457,7 @@ components:
type: array
items:
type: string
pattern: "[a-z]+(-[a-z]+)*"
pattern: "[a-z][a-zA-Z0-9]*"
script:
type: string
required:
@@ -448,7 +479,7 @@ components:
type: array
items:
type: string
pattern: "[a-z]+(-[a-z]+)*"
pattern: "[a-z][a-zA-Z0-9]*"
script:
type: string
required:
@@ -558,7 +589,7 @@ components:
type: array
items:
type: string
pattern: "[a-z]+(-[a-z]+)*"
pattern: "[a-z][a-zA-Z0-9]*"
script:
type: string
required:
+2
View File
@@ -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>
+45
View File
@@ -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>
+3
View File
@@ -0,0 +1,3 @@
export { default as ConfirmModal } from './ConfirmModal.vue';
export { confirm, useConfirmStore } from './useConfirm';
export type { ConfirmOptions } from './useConfirm';
+37
View File
@@ -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);
+128
View File
@@ -1313,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
@@ -1377,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
@@ -1438,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
@@ -1463,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
@@ -1496,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
@@ -1515,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
@@ -1544,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
@@ -1565,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
-6
View File
@@ -23,12 +23,6 @@ const mammonAxiosInstance = axios.create({
})
logResource(mammonAxiosInstance)
export const fetchScriptDefinitions = (): Promise<string> =>
mammonAxiosInstance.get<string>('rule-books/script-definitions', {
responseType: 'text',
headers: {Accept: 'text/plain'},
}).then(response => response.data);
export const ledgerApi = new LedgerApi(undefined, mammonUrl, mammonAxiosInstance);
export const transactionApi = new TransactionApi(undefined, mammonUrl, mammonAxiosInstance);
export const characterApi = new CharacterApi(undefined, mammonUrl, mammonAxiosInstance);
+2 -2
View File
@@ -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])
+12 -5
View File
@@ -1,7 +1,7 @@
<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 {ScriptEditor, useRuleBooksStore} from "@/rules";
import {PlusIcon, TrashIcon} from "@heroicons/vue/24/outline";
@@ -37,6 +37,13 @@ const save = async () => {
}
}
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, '']
}
@@ -76,8 +83,8 @@ watch(useRoute(), async route => {
</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" />
@@ -98,9 +105,9 @@ watch(useRoute(), async route => {
</div>
</div>
</div>
<div class="flex flex-col grow border-b-1">
<div class="flex flex-col grow min-h-0 border-b-1">
Script:
<ScriptEditor class="mt-2 mb-2" v-model="script" />
<ScriptEditor class="mt-2 mb-2" v-model="script" :ledgerRefs="ledgerRefs" />
</div>
</div>
<div class="mt-2 justify-end flex">
+45 -6
View File
@@ -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>
+19 -4
View File
@@ -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>
+26 -3
View File
@@ -3,7 +3,7 @@ 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 '@/mammon';
import {fetchScriptDefinitions} from './rules';
(self as unknown as { MonacoEnvironment: { getWorker(workerId: string, label: string): Worker } }).MonacoEnvironment = {
getWorker(_workerId: string, label: string) {
@@ -29,12 +29,29 @@ const loadScriptDefinitions = async () => {
}
};
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;
@@ -66,7 +83,12 @@ watch(model, value => {
}
});
onBeforeUnmount(() => editor?.dispose());
watch(() => props.ledgerRefs, refs => updateLedgerRefs(refs ?? []), {deep: true});
onBeforeUnmount(() => {
editor?.dispose();
ledgersLib?.dispose();
});
</script>
<template>
@@ -76,6 +98,7 @@ onBeforeUnmount(() => editor?.dispose());
<style scoped>
.script-editor {
width: 100%;
height: 24rem;
flex: 1 1 auto;
min-height: 12rem;
}
</style>
+15 -2
View File
@@ -32,12 +32,22 @@ 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 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)
@@ -45,4 +55,7 @@ export const findCharacterRuleBookByCharacterId = (characterId: number): Promise
.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);