Compare commits
15
Commits
0d61826c70
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
617650929a | ||
|
|
b70585f01d | ||
|
|
f7a193d1c5 | ||
|
|
0040a5c33b | ||
|
|
fb9567eee5 | ||
|
|
3419f3d4c9 | ||
|
|
d1237bf1d2 | ||
|
|
d4b48b05ee | ||
|
|
38e1063ac5 | ||
|
|
04a9f197e8 | ||
|
|
27b7cecfdc | ||
|
|
e814aabcc8 | ||
|
|
4c8a3d5dfc | ||
|
|
187c6b0f99 | ||
|
|
24c7ec4917 |
+363
-20
@@ -43,8 +43,7 @@ paths:
|
|||||||
"400":
|
"400":
|
||||||
description: |-
|
description: |-
|
||||||
Returned when:
|
Returned when:
|
||||||
- a binding references a ledger the caller does not own
|
- a ledger scope reference is not one of the caller's own main ledgers
|
||||||
- a binding references a ledger that is not a main ledger
|
|
||||||
/ledgers/main/{ledgerId}:
|
/ledgers/main/{ledgerId}:
|
||||||
put:
|
put:
|
||||||
tags:
|
tags:
|
||||||
@@ -359,6 +358,23 @@ paths:
|
|||||||
description: The link is seeded; follow with a full-page nav to /oauth2/authorization/esi
|
description: The link is seeded; follow with a full-page nav to /oauth2/authorization/esi
|
||||||
"401":
|
"401":
|
||||||
description: Missing or expired access token
|
description: Missing or expired access token
|
||||||
|
/balances/rebuild:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- balance-rebuild-admin-controller
|
||||||
|
operationId: rebuild
|
||||||
|
parameters:
|
||||||
|
- name: ledgerIds
|
||||||
|
in: query
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
/activity/consume:
|
/activity/consume:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -405,6 +421,15 @@ paths:
|
|||||||
- activity
|
- activity
|
||||||
summary: Process new activities for the authenticated user's characters
|
summary: Process new activities for the authenticated user's characters
|
||||||
operationId: processNewActivities
|
operationId: processNewActivities
|
||||||
|
parameters:
|
||||||
|
- name: from
|
||||||
|
in: query
|
||||||
|
description: Reprocess by walking the processed tail back to this UTC datetime
|
||||||
|
(ISO-8601); omit to only process new activities
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
responses:
|
responses:
|
||||||
"202":
|
"202":
|
||||||
description: Processing started in the background
|
description: Processing started in the background
|
||||||
@@ -412,11 +437,38 @@ paths:
|
|||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- rule-script
|
- rule-script
|
||||||
summary: Download the TypeScript definitions for the rule script runtime
|
summary: List the available rule script type definition files
|
||||||
operationId: getScriptDefinitions
|
operationId: listScriptDefinitions
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: The rule-runner.d.ts type definitions
|
description: The names of the available .d.ts type definitions
|
||||||
|
content:
|
||||||
|
'*/*':
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
/rule-scripts/definitions/{name}:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- rule-script
|
||||||
|
summary: Download a rule script type definition file by name
|
||||||
|
operationId: getScriptDefinition
|
||||||
|
parameters:
|
||||||
|
- name: name
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The requested .d.ts type definitions
|
||||||
|
content:
|
||||||
|
text/plain:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
"404":
|
||||||
|
description: No type definition with that name exists
|
||||||
content:
|
content:
|
||||||
text/plain:
|
text/plain:
|
||||||
schema:
|
schema:
|
||||||
@@ -904,6 +956,64 @@ paths:
|
|||||||
$ref: "#/components/schemas/TransactionResponse"
|
$ref: "#/components/schemas/TransactionResponse"
|
||||||
"404":
|
"404":
|
||||||
description: No ledger with this id
|
description: No ledger with this id
|
||||||
|
/ledgers/{ledgerId}/profit:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- transaction
|
||||||
|
summary: Get the daily profit series for a single ledger
|
||||||
|
operationId: profitPerDayInLedger
|
||||||
|
parameters:
|
||||||
|
- name: ledgerId
|
||||||
|
in: path
|
||||||
|
description: Id of the ledger
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "Daily profit for the ledger, ascending by date, only for days\
|
||||||
|
\ with ISK activity"
|
||||||
|
content:
|
||||||
|
'*/*':
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/DailyProfitResponse"
|
||||||
|
"400":
|
||||||
|
description: The ledger is the system ledger or a combined ledger
|
||||||
|
"404":
|
||||||
|
description: No ledger with this id
|
||||||
|
/ledgers/{ledgerId}/margin:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- transaction
|
||||||
|
summary: Get the daily FIFO-realized profit series for a single ledger
|
||||||
|
operationId: marginPerDayInLedger
|
||||||
|
parameters:
|
||||||
|
- name: ledgerId
|
||||||
|
in: path
|
||||||
|
description: Id of the ledger
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "Daily FIFO-realized profit for the ledger, ascending by date,\
|
||||||
|
\ only for days with a sale. iskIn is the sum of that day's profitable\
|
||||||
|
\ trades, iskOut is the sum of that day's losing trades (as a positive\
|
||||||
|
\ deficit); profit is iskIn minus iskOut."
|
||||||
|
content:
|
||||||
|
'*/*':
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/DailyProfitResponse"
|
||||||
|
"400":
|
||||||
|
description: The ledger is the system ledger or a combined ledger
|
||||||
|
"404":
|
||||||
|
description: No ledger with this id
|
||||||
/ledgers/{ledgerId}/balance:
|
/ledgers/{ledgerId}/balance:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -927,6 +1037,56 @@ paths:
|
|||||||
$ref: "#/components/schemas/BalanceResponse"
|
$ref: "#/components/schemas/BalanceResponse"
|
||||||
"404":
|
"404":
|
||||||
description: No ledger with this id
|
description: No ledger with this id
|
||||||
|
/corporations:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- corporation
|
||||||
|
summary: "Resolve public information for several corporation ids at once, silently\
|
||||||
|
\ omitting ids ESI cannot resolve"
|
||||||
|
operationId: findCorporations
|
||||||
|
parameters:
|
||||||
|
- name: ids
|
||||||
|
in: query
|
||||||
|
description: "Corporation ids to resolve, e.g. ids=98000001,98000002"
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The corporations that resolved; unknown ids are omitted
|
||||||
|
content:
|
||||||
|
'*/*':
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/CorporationResponse"
|
||||||
|
/corporations/{corporationId}:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- corporation
|
||||||
|
summary: "Resolve public information (name, ticker, alliance) for a corporation\
|
||||||
|
\ id"
|
||||||
|
operationId: findCorporation
|
||||||
|
parameters:
|
||||||
|
- name: corporationId
|
||||||
|
in: path
|
||||||
|
description: "Corporation id to resolve, e.g. 98000001"
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The resolved corporation
|
||||||
|
content:
|
||||||
|
'*/*':
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/CorporationResponse"
|
||||||
|
"404":
|
||||||
|
description: Returned when ESI has no corporation with the given id
|
||||||
/characters:
|
/characters:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -995,50 +1155,180 @@ paths:
|
|||||||
$ref: "#/components/schemas/AcquisitionResponse"
|
$ref: "#/components/schemas/AcquisitionResponse"
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
UpdateRuleBookRequest:
|
RuleScopeRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Request to update the caller's rule book; replaces its mutable
|
description: The ledgers and other resources to bind to a rule script.
|
||||||
fields.
|
|
||||||
properties:
|
properties:
|
||||||
bindings:
|
ledgers:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
description: "Ledger references the script writes to, each bound to one\
|
description: "Ledger references the script writes to, each bound to one\
|
||||||
\ of the user's ledgers."
|
\ of the user's own main ledgers."
|
||||||
|
characters:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: "Character references the script can read, each bound to one\
|
||||||
|
\ of the user's own characters."
|
||||||
|
corporations:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: "Corporation references the script can read, each bound to\
|
||||||
|
\ a corporation of one of the user's own characters."
|
||||||
|
walletDivisions:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
$ref: "#/components/schemas/WalletDivisionTargetRequest"
|
||||||
|
description: "Corporation wallet division references the script can read,\
|
||||||
|
\ each bound to a corporation of one of the user's own characters."
|
||||||
|
required:
|
||||||
|
- characters
|
||||||
|
- corporations
|
||||||
|
- ledgers
|
||||||
|
- walletDivisions
|
||||||
|
RuleScriptRequest:
|
||||||
|
type: object
|
||||||
|
description: "A named rule script to store in the book, together with its scope."
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: Unique script name within the book; a lowercase alphanumeric
|
||||||
|
identifier.
|
||||||
|
example: sales
|
||||||
|
scope:
|
||||||
|
$ref: "#/components/schemas/RuleScopeRequest"
|
||||||
|
description: The ledgers and other resources bound to this script.
|
||||||
script:
|
script:
|
||||||
type: string
|
type: string
|
||||||
description: The classification script source.
|
description: The classification script source.
|
||||||
example: transfer.to('sales')
|
example: transfer.to('wallet')
|
||||||
required:
|
required:
|
||||||
- bindings
|
- name
|
||||||
|
- scope
|
||||||
- script
|
- script
|
||||||
|
UpdateRuleBookRequest:
|
||||||
|
type: object
|
||||||
|
description: Request to update the caller's rule book; replaces its rule scripts.
|
||||||
|
properties:
|
||||||
|
scripts:
|
||||||
|
type: array
|
||||||
|
description: The rule scripts making up the book.
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/RuleScriptRequest"
|
||||||
|
required:
|
||||||
|
- scripts
|
||||||
|
WalletDivisionTargetRequest:
|
||||||
|
type: object
|
||||||
|
description: A corporation wallet division to bind.
|
||||||
|
properties:
|
||||||
|
corporationId:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: The corporation the wallet division belongs to.
|
||||||
|
example: 98000001
|
||||||
|
division:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
description: "The wallet division number, from 1 to 7."
|
||||||
|
example: 1
|
||||||
|
required:
|
||||||
|
- corporationId
|
||||||
|
- division
|
||||||
RuleBookResponse:
|
RuleBookResponse:
|
||||||
type: object
|
type: object
|
||||||
description: "The caller's rule book: a script that classifies transactions,\
|
description: "The caller's rule book: the named rule scripts that classify transactions,\
|
||||||
\ together with its ledger bindings."
|
\ each with its scope."
|
||||||
properties:
|
properties:
|
||||||
userId:
|
userId:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
description: Owning user identifier.
|
description: Owning user identifier.
|
||||||
example: 3fa85f64-5717-4562-b3fc-2c963f66afa6
|
example: 3fa85f64-5717-4562-b3fc-2c963f66afa6
|
||||||
bindings:
|
scripts:
|
||||||
|
type: array
|
||||||
|
description: The rule scripts making up the book.
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/RuleScriptResponse"
|
||||||
|
required:
|
||||||
|
- scripts
|
||||||
|
- userId
|
||||||
|
RuleScopeResponse:
|
||||||
|
type: object
|
||||||
|
description: The ledgers and other resources bound to a rule script.
|
||||||
|
properties:
|
||||||
|
ledgers:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
description: "Ledger references the script writes to, each bound to one\
|
description: "Ledger references the script writes to, each bound to one\
|
||||||
\ of the user's ledgers."
|
\ of the user's own main ledgers."
|
||||||
|
characters:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: "Character references the script can read, each bound to one\
|
||||||
|
\ of the user's own characters."
|
||||||
|
corporations:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: "Corporation references the script can read, each bound to\
|
||||||
|
\ a corporation of one of the user's own characters."
|
||||||
|
walletDivisions:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
$ref: "#/components/schemas/WalletDivisionTargetResponse"
|
||||||
|
description: "Corporation wallet division references the script can read,\
|
||||||
|
\ each bound to a corporation of one of the user's own characters."
|
||||||
|
required:
|
||||||
|
- characters
|
||||||
|
- corporations
|
||||||
|
- ledgers
|
||||||
|
- walletDivisions
|
||||||
|
RuleScriptResponse:
|
||||||
|
type: object
|
||||||
|
description: "A named rule script within the book, together with its scope."
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: Unique script name within the book.
|
||||||
|
example: sales
|
||||||
|
scope:
|
||||||
|
$ref: "#/components/schemas/RuleScopeResponse"
|
||||||
|
description: The ledgers and other resources bound to this script.
|
||||||
script:
|
script:
|
||||||
type: string
|
type: string
|
||||||
description: The classification script source.
|
description: The classification script source.
|
||||||
example: transfer.to('sales')
|
example: transfer.to('wallet')
|
||||||
required:
|
required:
|
||||||
- bindings
|
- name
|
||||||
|
- scope
|
||||||
- script
|
- script
|
||||||
- userId
|
WalletDivisionTargetResponse:
|
||||||
|
type: object
|
||||||
|
description: A corporation wallet division bound to the script.
|
||||||
|
properties:
|
||||||
|
corporationId:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: The corporation the wallet division belongs to.
|
||||||
|
example: 98000001
|
||||||
|
division:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
description: "The wallet division number, from 1 to 7."
|
||||||
|
example: 1
|
||||||
|
required:
|
||||||
|
- corporationId
|
||||||
|
- division
|
||||||
UpdateMainLedgerRequest:
|
UpdateMainLedgerRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Request to update an existing main ledger.
|
description: Request to update an existing main ledger.
|
||||||
@@ -1682,7 +1972,7 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
description: When the order was issued.
|
description: When the order was issued.
|
||||||
example: 2026-06-22T05:12:25Z
|
example: 2026-06-22T05:12:25
|
||||||
escrow:
|
escrow:
|
||||||
type: number
|
type: number
|
||||||
description: ISK held in escrow for a buy order; null for sell orders.
|
description: ISK held in escrow for a buy order; null for sell orders.
|
||||||
@@ -1910,6 +2200,32 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- type
|
- type
|
||||||
|
DailyProfitResponse:
|
||||||
|
type: object
|
||||||
|
description: "Profit for a single day: ISK in, ISK out, and their difference."
|
||||||
|
properties:
|
||||||
|
date:
|
||||||
|
type: string
|
||||||
|
format: date
|
||||||
|
description: The UTC (EVE) day this profit is for.
|
||||||
|
example: 2026-06-22
|
||||||
|
iskIn:
|
||||||
|
type: number
|
||||||
|
description: Total ISK that entered the ledger on this day.
|
||||||
|
example: 1500000.0
|
||||||
|
iskOut:
|
||||||
|
type: number
|
||||||
|
description: Total ISK that left the ledger on this day.
|
||||||
|
example: 500000.0
|
||||||
|
profit:
|
||||||
|
type: number
|
||||||
|
description: "Profit for the day: iskIn minus iskOut."
|
||||||
|
example: 1000000.0
|
||||||
|
required:
|
||||||
|
- date
|
||||||
|
- iskIn
|
||||||
|
- iskOut
|
||||||
|
- profit
|
||||||
BalanceResponse:
|
BalanceResponse:
|
||||||
type: object
|
type: object
|
||||||
description: "The balance of a ledger: its ISK total plus the quantity of each\
|
description: "The balance of a ledger: its ISK total plus the quantity of each\
|
||||||
@@ -1944,6 +2260,33 @@ components:
|
|||||||
required:
|
required:
|
||||||
- quantity
|
- quantity
|
||||||
- typeId
|
- typeId
|
||||||
|
CorporationResponse:
|
||||||
|
type: object
|
||||||
|
description: An EVE Online corporation.
|
||||||
|
properties:
|
||||||
|
corporationId:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: EVE corporation id.
|
||||||
|
example: 98000001
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: Corporation name.
|
||||||
|
example: Center for Advanced Studies
|
||||||
|
ticker:
|
||||||
|
type: string
|
||||||
|
description: Corporation ticker.
|
||||||
|
example: CAS
|
||||||
|
allianceId:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: "EVE alliance id, null when the corporation is not in an alliance."
|
||||||
|
example: 99000001
|
||||||
|
required:
|
||||||
|
- allianceId
|
||||||
|
- corporationId
|
||||||
|
- name
|
||||||
|
- ticker
|
||||||
SseEmitter:
|
SseEmitter:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
Generated
+30
@@ -14,6 +14,7 @@
|
|||||||
"@vueuse/integrations": "^14.3.0",
|
"@vueuse/integrations": "^14.3.0",
|
||||||
"@vueuse/router": "^14.3.0",
|
"@vueuse/router": "^14.3.0",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
|
"chart.js": "^4.5.1",
|
||||||
"gemory": "file:",
|
"gemory": "file:",
|
||||||
"loglevel": "^1.8.1",
|
"loglevel": "^1.8.1",
|
||||||
"loglevel-plugin-prefix": "^0.8.4",
|
"loglevel-plugin-prefix": "^0.8.4",
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"sortablejs": "^1.15.7",
|
"sortablejs": "^1.15.7",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
|
"vue-chartjs": "^5.3.4",
|
||||||
"vue-router": "^5.0.7"
|
"vue-router": "^5.0.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -229,6 +231,12 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@kurkle/color": {
|
||||||
|
"version": "0.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
|
||||||
|
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@napi-rs/wasm-runtime": {
|
"node_modules/@napi-rs/wasm-runtime": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz",
|
||||||
@@ -1483,6 +1491,18 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chart.js": {
|
||||||
|
"version": "4.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz",
|
||||||
|
"integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@kurkle/color": "^0.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"pnpm": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chokidar": {
|
"node_modules/chokidar": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
|
||||||
@@ -2975,6 +2995,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-chartjs": {
|
||||||
|
"version": "5.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.4.tgz",
|
||||||
|
"integrity": "sha512-x3Fqob8RQvrTdssfi9ecsCzEkFOd8JPmNwSkSQzdfKj/uBsRJs/Y88cZcZIEcPsTVfMGwMo4MOoihoDG2DoE/g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"chart.js": "^4.1.1",
|
||||||
|
"vue": "^3.0.0-0 || ^2.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vue-router": {
|
"node_modules/vue-router": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.1.0.tgz",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"@vueuse/integrations": "^14.3.0",
|
"@vueuse/integrations": "^14.3.0",
|
||||||
"@vueuse/router": "^14.3.0",
|
"@vueuse/router": "^14.3.0",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
|
"chart.js": "^4.5.1",
|
||||||
"gemory": "file:",
|
"gemory": "file:",
|
||||||
"loglevel": "^1.8.1",
|
"loglevel": "^1.8.1",
|
||||||
"loglevel-plugin-prefix": "^0.8.4",
|
"loglevel-plugin-prefix": "^0.8.4",
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"sortablejs": "^1.15.7",
|
"sortablejs": "^1.15.7",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
|
"vue-chartjs": "^5.3.4",
|
||||||
"vue-router": "^5.0.7"
|
"vue-router": "^5.0.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
+16
-1
@@ -1,8 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed} from 'vue';
|
import {computed, watchEffect} from 'vue';
|
||||||
import {RouterView, useRoute} from 'vue-router';
|
import {RouterView, useRoute} from 'vue-router';
|
||||||
import {Sidebar} from './sidebar';
|
import {Sidebar} from './sidebar';
|
||||||
import {ConfirmModal} from '@/confirm';
|
import {ConfirmModal} from '@/confirm';
|
||||||
|
import {toast, ToastContainer} from '@/toast';
|
||||||
|
import {onActivitiesProcessed} from '@/activity';
|
||||||
|
import {useAuthStore} from '@/auth';
|
||||||
import {routeNames} from '@/routes';
|
import {routeNames} from '@/routes';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@@ -10,6 +13,17 @@ const route = useRoute();
|
|||||||
const hideSidebar = computed(() => {
|
const hideSidebar = computed(() => {
|
||||||
return route.name === routeNames.callback || route.name === routeNames.about;
|
return route.name === routeNames.callback || route.name === routeNames.about;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
|
watchEffect(onCleanup => {
|
||||||
|
if (!authStore.isAuthenticated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const unsubscribe = onActivitiesProcessed(() => toast.info('New activities have been processed'));
|
||||||
|
|
||||||
|
onCleanup(unsubscribe);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -23,6 +37,7 @@ const hideSidebar = computed(() => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<ConfirmModal />
|
<ConfirmModal />
|
||||||
|
<ToastContainer />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {computed} from "vue";
|
|||||||
import {computedAsync} from "@vueuse/core";
|
import {computedAsync} from "@vueuse/core";
|
||||||
import {ActivitySourceResponse, ActivitySourceResponseTypeEnum} from "@/generated/mammon";
|
import {ActivitySourceResponse, ActivitySourceResponseTypeEnum} from "@/generated/mammon";
|
||||||
import {CharacterLabel, useCharactersStore} from "@/characters";
|
import {CharacterLabel, useCharactersStore} from "@/characters";
|
||||||
import {CorporationLabel} from "@/corporations";
|
import {CorporationLabel, useCorporationsStore} from "@/corporations";
|
||||||
import {LedgerLabel, useLedgersStore} from "@/ledger";
|
import {LedgerLabel, useLedgersStore} from "@/ledger";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -17,6 +17,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const charactersStore = useCharactersStore();
|
const charactersStore = useCharactersStore();
|
||||||
|
const corporationsStore = useCorporationsStore();
|
||||||
const ledgersStore = useLedgersStore();
|
const ledgersStore = useLedgersStore();
|
||||||
|
|
||||||
const character = computedAsync(async () => {
|
const character = computedAsync(async () => {
|
||||||
@@ -26,6 +27,13 @@ const character = computedAsync(async () => {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}, undefined);
|
}, undefined);
|
||||||
|
|
||||||
|
const corporation = computedAsync(async () => {
|
||||||
|
if (props.source.type === ActivitySourceResponseTypeEnum.Corporation && props.source.corporationId) {
|
||||||
|
return await corporationsStore.findById(props.source.corporationId);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}, undefined);
|
||||||
|
|
||||||
const ledger = computed(() =>
|
const ledger = computed(() =>
|
||||||
props.source.type === ActivitySourceResponseTypeEnum.Ledger && props.source.ledgerId
|
props.source.type === ActivitySourceResponseTypeEnum.Ledger && props.source.ledgerId
|
||||||
? ledgersStore.findById(props.source.ledgerId)
|
? ledgersStore.findById(props.source.ledgerId)
|
||||||
@@ -34,6 +42,6 @@ const ledger = computed(() =>
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CharacterLabel v-if="source.type === ActivitySourceResponseTypeEnum.Character && character" :character="character" :size="size" />
|
<CharacterLabel v-if="source.type === ActivitySourceResponseTypeEnum.Character && character" :character="character" :size="size" />
|
||||||
<CorporationLabel v-else-if="source.type === ActivitySourceResponseTypeEnum.Corporation && source.corporationId" :corporation-id="source.corporationId" :division="source.division" :size="size" />
|
<CorporationLabel v-else-if="source.type === ActivitySourceResponseTypeEnum.Corporation && source.corporationId" :corporation-id="source.corporationId" :corporation="corporation" :division="source.division" :size="size" />
|
||||||
<LedgerLabel v-else-if="ledger" :ledger="ledger" link />
|
<LedgerLabel v-else-if="ledger" :ledger="ledger" link />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -41,12 +41,11 @@ useEventListener('keyup', e => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div ref="root" class="dropdown" :class="{'dropdown-open': isOpen, 'dropdown-close': !isOpen}" v-on-click-outside="[doAutoClose, { ignore: [floating] }]">
|
<div ref="root" class="dropdown" :class="{'dropdown-open': isOpen, 'dropdown-close': !isOpen}" v-on-click-outside="[doAutoClose, { ignore: [floating] }]">
|
||||||
<button @click="isOpen = !isOpen" class="cursor-pointer">
|
<button @click="isOpen = !isOpen" class="flex items-center cursor-pointer border-none bg-transparent hover:bg-transparent p-0">
|
||||||
<Transition
|
<Transition
|
||||||
|
mode="out-in"
|
||||||
enter-active-class="transition-transform"
|
enter-active-class="transition-transform"
|
||||||
enter-from-class="rotate-180"
|
enter-from-class="rotate-180">
|
||||||
leave-active-class="hidden"
|
|
||||||
leave-to-class="rotate-180">
|
|
||||||
<ChevronDownIcon v-if="!isOpen" class="chevron" />
|
<ChevronDownIcon v-if="!isOpen" class="chevron" />
|
||||||
<ChevronUpIcon v-else class="chevron" />
|
<ChevronUpIcon v-else class="chevron" />
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import {computed, ref, watch} from "vue";
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<{ min?: number; max?: number }>(), {
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
const from = defineModel<number>('from', {default: 0});
|
||||||
|
const to = defineModel<number>('to', {default: 0});
|
||||||
|
|
||||||
|
const container = ref<HTMLElement>();
|
||||||
|
|
||||||
|
const dragFill = (event: PointerEvent) => {
|
||||||
|
const rect = container.value?.getBoundingClientRect();
|
||||||
|
|
||||||
|
if (!rect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const span = (props.max - props.min) || 1;
|
||||||
|
const width = to.value - from.value;
|
||||||
|
const startX = event.clientX;
|
||||||
|
const startFrom = from.value;
|
||||||
|
|
||||||
|
const onMove = (moveEvent: PointerEvent) => {
|
||||||
|
const delta = Math.round(((moveEvent.clientX - startX) / rect.width) * span);
|
||||||
|
const newFrom = Math.min(Math.max(startFrom + delta, props.min), props.max - width);
|
||||||
|
|
||||||
|
from.value = newFrom;
|
||||||
|
to.value = newFrom + width;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onUp = () => {
|
||||||
|
window.removeEventListener('pointermove', onMove);
|
||||||
|
window.removeEventListener('pointerup', onUp);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('pointermove', onMove);
|
||||||
|
window.addEventListener('pointerup', onUp);
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(from, value => {
|
||||||
|
if (value > to.value) {
|
||||||
|
to.value = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
watch(to, value => {
|
||||||
|
if (value < from.value) {
|
||||||
|
from.value = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fillStyle = computed(() => {
|
||||||
|
const span = (props.max - props.min) || 1;
|
||||||
|
|
||||||
|
return {
|
||||||
|
left: `${((from.value - props.min) / span) * 100}%`,
|
||||||
|
width: `${((to.value - from.value) / span) * 100}%`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div ref="container" class="dual-range relative h-6 select-none">
|
||||||
|
<div class="absolute inset-x-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-gray-700 pointer-events-none"></div>
|
||||||
|
<div class="absolute top-1/2 h-2 -translate-y-1/2 rounded-full bg-emerald-500 cursor-grab active:cursor-grabbing"
|
||||||
|
:style="fillStyle" @pointerdown="dragFill"></div>
|
||||||
|
<input type="range" :min="min" :max="max" v-model.number="from"
|
||||||
|
class="absolute inset-0 w-full h-full m-0 bg-transparent appearance-none pointer-events-none" />
|
||||||
|
<input type="range" :min="min" :max="max" v-model.number="to"
|
||||||
|
class="absolute inset-0 w-full h-full m-0 bg-transparent appearance-none pointer-events-none" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@reference "@/style.css";
|
||||||
|
|
||||||
|
.dual-range input[type="range"]::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
@apply w-4 h-4 rounded-full bg-emerald-500 border-2 border-gray-200 cursor-pointer pointer-events-auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dual-range input[type="range"]::-moz-range-thumb {
|
||||||
|
@apply w-4 h-4 rounded-full bg-emerald-500 border-2 border-gray-200 cursor-pointer pointer-events-auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts" generic="T">
|
<script setup lang="ts" generic="T">
|
||||||
import {vOnClickOutside} from '@vueuse/components';
|
import {vOnClickOutside} from '@vueuse/components';
|
||||||
import {useVirtualList} from '@vueuse/core';
|
import {useVirtualList} from '@vueuse/core';
|
||||||
import {computed, ref} from 'vue';
|
import {computed, ref, watch} from 'vue';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
items: T[];
|
items: T[];
|
||||||
@@ -15,6 +15,12 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
const modelValue = defineModel<T>();
|
const modelValue = defineModel<T>();
|
||||||
|
|
||||||
const isOpen = ref(false);
|
const isOpen = ref(false);
|
||||||
|
|
||||||
|
watch(() => props.items, items => {
|
||||||
|
if (items.length > 0) {
|
||||||
|
isOpen.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
const currentIndex = ref(-1);
|
const currentIndex = ref(-1);
|
||||||
const {list, scrollTo, containerProps, wrapperProps} = useVirtualList(computed(() => props.items), {
|
const {list, scrollTo, containerProps, wrapperProps} = useVirtualList(computed(() => props.items), {
|
||||||
itemHeight: () => props.itemHeight,
|
itemHeight: () => props.itemHeight,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export { default as ClipboardButton } from './ClipboardButton.vue';
|
export { default as ClipboardButton } from './ClipboardButton.vue';
|
||||||
export { default as Dropdown } from './Dropdown.vue';
|
export { default as Dropdown } from './Dropdown.vue';
|
||||||
|
export { default as DualRangeSlider } from './DualRangeSlider.vue';
|
||||||
export { default as LoadingSpinner } from './LoadingSpinner.vue';
|
export { default as LoadingSpinner } from './LoadingSpinner.vue';
|
||||||
export { default as Modal } from './Modal.vue';
|
export { default as Modal } from './Modal.vue';
|
||||||
export { default as ProgressBar } from './ProgressBar.vue';
|
export { default as ProgressBar } from './ProgressBar.vue';
|
||||||
|
|||||||
@@ -8,20 +8,27 @@ const open = defineModel('open', { default: false });
|
|||||||
|
|
||||||
const { width, height } = useSharedWindowSize();
|
const { width, height } = useSharedWindowSize();
|
||||||
const mainDiv = ref<HTMLDivElement | null>(null);
|
const mainDiv = ref<HTMLDivElement | null>(null);
|
||||||
const { top, left } = useElementBounding(mainDiv);
|
const { top, bottom, left, right } = useElementBounding(mainDiv);
|
||||||
|
|
||||||
const positions = computed(() => {
|
const positions = computed(() => [
|
||||||
if (top.value < height.value / 2) {
|
top.value < height.value / 2 ? 'top' : 'bottom',
|
||||||
if (left.value < width.value / 2) {
|
left.value < width.value / 2 ? 'left' : 'right',
|
||||||
return ['top', 'left'];
|
]);
|
||||||
}
|
|
||||||
return ['top', 'right'];
|
const floatingStyle = computed(() => {
|
||||||
|
const style: Record<string, string> = {};
|
||||||
|
if (positions.value.includes('top')) {
|
||||||
|
style.top = `${bottom.value}px`;
|
||||||
|
} else {
|
||||||
|
style.bottom = `${height.value - top.value}px`;
|
||||||
}
|
}
|
||||||
if (left.value < width.value / 2) {
|
if (positions.value.includes('left')) {
|
||||||
return ['bottom', 'left'];
|
style.left = `${left.value}px`;
|
||||||
|
} else {
|
||||||
|
style.right = `${width.value - right.value}px`;
|
||||||
}
|
}
|
||||||
return ['bottom', 'right'];
|
return style;
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -35,12 +42,18 @@ const positions = computed(() => {
|
|||||||
<div v-element-hover="(h: boolean) => open = h" class="m-auto header">
|
<div v-element-hover="(h: boolean) => open = h" class="m-auto header">
|
||||||
<slot name="header" />
|
<slot name="header" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="open" class="m-auto">
|
<Teleport to="body">
|
||||||
<div class="z-10 relative">
|
<div v-if="open" class="tooltip-floating" :style="floatingStyle">
|
||||||
<div class="absolute">
|
<slot />
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Teleport>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@reference "@/style.css";
|
||||||
|
|
||||||
|
.tooltip-floating {
|
||||||
|
@apply fixed z-30;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import {Corporation} from "./corporations.ts";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
corporationId: number;
|
corporationId: number;
|
||||||
|
corporation?: Corporation | null;
|
||||||
division?: number | null;
|
division?: number | null;
|
||||||
size?: number;
|
size?: number;
|
||||||
}
|
}
|
||||||
@@ -14,6 +17,6 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<img class="me-2" :src="`https://images.evetech.net/corporations/${corporationId}/logo?size=${size}`" />
|
<img class="me-2" :src="`https://images.evetech.net/corporations/${corporationId}/logo?size=${size}`" />
|
||||||
<span>Corporation<template v-if="division"> · Division {{ division }}</template></span>
|
<span>{{ corporation?.name ?? 'Corporation' }}<template v-if="division"> · Division {{ division }}</template></span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import {corporationApi} from "@/mammon";
|
||||||
|
import {defineStore} from "pinia";
|
||||||
|
import {ref} from "vue";
|
||||||
|
import {CorporationResponse} from "@/generated/mammon";
|
||||||
|
|
||||||
|
export type Corporation = CorporationResponse
|
||||||
|
|
||||||
|
export const useCorporationsStore = defineStore('corporations', () => {
|
||||||
|
const corporations = ref<Record<number, Corporation | null>>({});
|
||||||
|
const inFlight = new Map<number, Promise<Corporation | undefined>>();
|
||||||
|
|
||||||
|
const findById = async (corporationId: number): Promise<Corporation | undefined> => {
|
||||||
|
const cached = corporations.value[corporationId];
|
||||||
|
|
||||||
|
if (cached !== undefined) {
|
||||||
|
return cached ?? undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let request = inFlight.get(corporationId);
|
||||||
|
|
||||||
|
if (!request) {
|
||||||
|
request = corporationApi.findCorporation(corporationId)
|
||||||
|
.then(response => {
|
||||||
|
corporations.value[corporationId] = response.data;
|
||||||
|
return response.data;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
corporations.value[corporationId] = null;
|
||||||
|
return undefined;
|
||||||
|
})
|
||||||
|
.finally(() => inFlight.delete(corporationId));
|
||||||
|
inFlight.set(corporationId, request);
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {corporations, findById};
|
||||||
|
})
|
||||||
@@ -1 +1,3 @@
|
|||||||
|
export * from './corporations.ts'
|
||||||
|
|
||||||
export {default as CorporationLabel} from './CorporationLabel.vue';
|
export {default as CorporationLabel} from './CorporationLabel.vue';
|
||||||
|
|||||||
+649
-28
@@ -168,6 +168,27 @@ export interface CombinedLedgerResponse extends LedgerResponse {
|
|||||||
*/
|
*/
|
||||||
'memberLedgerIds': Array<string>;
|
'memberLedgerIds': Array<string>;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* An EVE Online corporation.
|
||||||
|
*/
|
||||||
|
export interface CorporationResponse {
|
||||||
|
/**
|
||||||
|
* EVE corporation id.
|
||||||
|
*/
|
||||||
|
'corporationId': number;
|
||||||
|
/**
|
||||||
|
* Corporation name.
|
||||||
|
*/
|
||||||
|
'name': string;
|
||||||
|
/**
|
||||||
|
* Corporation ticker.
|
||||||
|
*/
|
||||||
|
'ticker': string;
|
||||||
|
/**
|
||||||
|
* EVE alliance id, null when the corporation is not in an alliance.
|
||||||
|
*/
|
||||||
|
'allianceId': number;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Request to create a new combined ledger aggregating the given member ledgers.
|
* Request to create a new combined ledger aggregating the given member ledgers.
|
||||||
*/
|
*/
|
||||||
@@ -190,6 +211,27 @@ export interface CreateMainLedgerRequest {
|
|||||||
*/
|
*/
|
||||||
'name': string;
|
'name': string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Profit for a single day: ISK in, ISK out, and their difference.
|
||||||
|
*/
|
||||||
|
export interface DailyProfitResponse {
|
||||||
|
/**
|
||||||
|
* The UTC (EVE) day this profit is for.
|
||||||
|
*/
|
||||||
|
'date': string;
|
||||||
|
/**
|
||||||
|
* Total ISK that entered the ledger on this day.
|
||||||
|
*/
|
||||||
|
'iskIn': number;
|
||||||
|
/**
|
||||||
|
* Total ISK that left the ledger on this day.
|
||||||
|
*/
|
||||||
|
'iskOut': number;
|
||||||
|
/**
|
||||||
|
* Profit for the day: iskIn minus iskOut.
|
||||||
|
*/
|
||||||
|
'profit': number;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* A market location (NPC station) with its containing solar system and region.
|
* A market location (NPC station) with its containing solar system and region.
|
||||||
*/
|
*/
|
||||||
@@ -690,7 +732,7 @@ export interface ReprocessingResultResponse {
|
|||||||
'output': Array<MarketTypeStackAppraisalResponse>;
|
'output': Array<MarketTypeStackAppraisalResponse>;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* The caller\'s rule book: a script that classifies transactions, together with its ledger bindings.
|
* The caller\'s rule book: the named rule scripts that classify transactions, each with its scope.
|
||||||
*/
|
*/
|
||||||
export interface RuleBookResponse {
|
export interface RuleBookResponse {
|
||||||
/**
|
/**
|
||||||
@@ -698,9 +740,81 @@ export interface RuleBookResponse {
|
|||||||
*/
|
*/
|
||||||
'userId': string;
|
'userId': string;
|
||||||
/**
|
/**
|
||||||
* Ledger references the script writes to, each bound to one of the user\'s ledgers.
|
* The rule scripts making up the book.
|
||||||
*/
|
*/
|
||||||
'bindings': { [key: string]: string; };
|
'scripts': Array<RuleScriptResponse>;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* The ledgers and other resources to bind to a rule script.
|
||||||
|
*/
|
||||||
|
export interface RuleScopeRequest {
|
||||||
|
/**
|
||||||
|
* Ledger references the script writes to, each bound to one of the user\'s own main ledgers.
|
||||||
|
*/
|
||||||
|
'ledgers': { [key: string]: string; };
|
||||||
|
/**
|
||||||
|
* Character references the script can read, each bound to one of the user\'s own characters.
|
||||||
|
*/
|
||||||
|
'characters': { [key: string]: number; };
|
||||||
|
/**
|
||||||
|
* Corporation references the script can read, each bound to a corporation of one of the user\'s own characters.
|
||||||
|
*/
|
||||||
|
'corporations': { [key: string]: number; };
|
||||||
|
/**
|
||||||
|
* Corporation wallet division references the script can read, each bound to a corporation of one of the user\'s own characters.
|
||||||
|
*/
|
||||||
|
'walletDivisions': { [key: string]: WalletDivisionTargetRequest; };
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* The ledgers and other resources bound to a rule script.
|
||||||
|
*/
|
||||||
|
export interface RuleScopeResponse {
|
||||||
|
/**
|
||||||
|
* Ledger references the script writes to, each bound to one of the user\'s own main ledgers.
|
||||||
|
*/
|
||||||
|
'ledgers': { [key: string]: string; };
|
||||||
|
/**
|
||||||
|
* Character references the script can read, each bound to one of the user\'s own characters.
|
||||||
|
*/
|
||||||
|
'characters': { [key: string]: number; };
|
||||||
|
/**
|
||||||
|
* Corporation references the script can read, each bound to a corporation of one of the user\'s own characters.
|
||||||
|
*/
|
||||||
|
'corporations': { [key: string]: number; };
|
||||||
|
/**
|
||||||
|
* Corporation wallet division references the script can read, each bound to a corporation of one of the user\'s own characters.
|
||||||
|
*/
|
||||||
|
'walletDivisions': { [key: string]: WalletDivisionTargetResponse; };
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* A named rule script to store in the book, together with its scope.
|
||||||
|
*/
|
||||||
|
export interface RuleScriptRequest {
|
||||||
|
/**
|
||||||
|
* Unique script name within the book; a lowercase alphanumeric identifier.
|
||||||
|
*/
|
||||||
|
'name': string;
|
||||||
|
/**
|
||||||
|
* The ledgers and other resources bound to this script.
|
||||||
|
*/
|
||||||
|
'scope': RuleScopeRequest;
|
||||||
|
/**
|
||||||
|
* The classification script source.
|
||||||
|
*/
|
||||||
|
'script': string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* A named rule script within the book, together with its scope.
|
||||||
|
*/
|
||||||
|
export interface RuleScriptResponse {
|
||||||
|
/**
|
||||||
|
* Unique script name within the book.
|
||||||
|
*/
|
||||||
|
'name': string;
|
||||||
|
/**
|
||||||
|
* The ledgers and other resources bound to this script.
|
||||||
|
*/
|
||||||
|
'scope': RuleScopeResponse;
|
||||||
/**
|
/**
|
||||||
* The classification script source.
|
* The classification script source.
|
||||||
*/
|
*/
|
||||||
@@ -763,17 +877,39 @@ export interface UpdateMainLedgerRequest {
|
|||||||
'name': string;
|
'name': string;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Request to update the caller\'s rule book; replaces its mutable fields.
|
* Request to update the caller\'s rule book; replaces its rule scripts.
|
||||||
*/
|
*/
|
||||||
export interface UpdateRuleBookRequest {
|
export interface UpdateRuleBookRequest {
|
||||||
/**
|
/**
|
||||||
* Ledger references the script writes to, each bound to one of the user\'s ledgers.
|
* The rule scripts making up the book.
|
||||||
*/
|
*/
|
||||||
'bindings': { [key: string]: string; };
|
'scripts': Array<RuleScriptRequest>;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* A corporation wallet division to bind.
|
||||||
|
*/
|
||||||
|
export interface WalletDivisionTargetRequest {
|
||||||
/**
|
/**
|
||||||
* The classification script source.
|
* The corporation the wallet division belongs to.
|
||||||
*/
|
*/
|
||||||
'script': string;
|
'corporationId': number;
|
||||||
|
/**
|
||||||
|
* The wallet division number, from 1 to 7.
|
||||||
|
*/
|
||||||
|
'division': number;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* A corporation wallet division bound to the script.
|
||||||
|
*/
|
||||||
|
export interface WalletDivisionTargetResponse {
|
||||||
|
/**
|
||||||
|
* The corporation the wallet division belongs to.
|
||||||
|
*/
|
||||||
|
'corporationId': number;
|
||||||
|
/**
|
||||||
|
* The wallet division number, from 1 to 7.
|
||||||
|
*/
|
||||||
|
'division': number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -970,10 +1106,11 @@ export const ActivityApiAxiosParamCreator = function (configuration?: Configurat
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Process new activities for the authenticated user\'s characters
|
* @summary Process new activities for the authenticated user\'s characters
|
||||||
|
* @param {string} [from] Reprocess by walking the processed tail back to this UTC datetime (ISO-8601); omit to only process new activities
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
processNewActivities: async (options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
processNewActivities: async (from?: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
const localVarPath = `/activities/process`;
|
const localVarPath = `/activities/process`;
|
||||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
@@ -986,6 +1123,12 @@ export const ActivityApiAxiosParamCreator = function (configuration?: Configurat
|
|||||||
const localVarHeaderParameter = {} as any;
|
const localVarHeaderParameter = {} as any;
|
||||||
const localVarQueryParameter = {} as any;
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
if (from !== undefined) {
|
||||||
|
localVarQueryParameter['from'] = (from as any instanceof Date) ?
|
||||||
|
(from as any).toISOString() :
|
||||||
|
from;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
@@ -1064,11 +1207,12 @@ export const ActivityApiFp = function(configuration?: Configuration) {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Process new activities for the authenticated user\'s characters
|
* @summary Process new activities for the authenticated user\'s characters
|
||||||
|
* @param {string} [from] Reprocess by walking the processed tail back to this UTC datetime (ISO-8601); omit to only process new activities
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async processNewActivities(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
async processNewActivities(from?: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.processNewActivities(options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.processNewActivities(from, options);
|
||||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
const localVarOperationServerBasePath = operationServerMap['ActivityApi.processNewActivities']?.[localVarOperationServerIndex]?.url;
|
const localVarOperationServerBasePath = operationServerMap['ActivityApi.processNewActivities']?.[localVarOperationServerIndex]?.url;
|
||||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
@@ -1117,11 +1261,12 @@ export const ActivityApiFactory = function (configuration?: Configuration, baseP
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Process new activities for the authenticated user\'s characters
|
* @summary Process new activities for the authenticated user\'s characters
|
||||||
|
* @param {string} [from] Reprocess by walking the processed tail back to this UTC datetime (ISO-8601); omit to only process new activities
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
processNewActivities(options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
processNewActivities(from?: string, options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
||||||
return localVarFp.processNewActivities(options).then((request) => request(axios, basePath));
|
return localVarFp.processNewActivities(from, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -1164,11 +1309,12 @@ export class ActivityApi extends BaseAPI {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Process new activities for the authenticated user\'s characters
|
* @summary Process new activities for the authenticated user\'s characters
|
||||||
|
* @param {string} [from] Reprocess by walking the processed tail back to this UTC datetime (ISO-8601); omit to only process new activities
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
public processNewActivities(options?: RawAxiosRequestConfig) {
|
public processNewActivities(from?: string, options?: RawAxiosRequestConfig) {
|
||||||
return ActivityApiFp(this.configuration).processNewActivities(options).then((request) => request(this.axios, this.basePath));
|
return ActivityApiFp(this.configuration).processNewActivities(from, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1459,6 +1605,105 @@ export class AuthApi extends BaseAPI {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BalanceRebuildAdminControllerApi - axios parameter creator
|
||||||
|
*/
|
||||||
|
export const BalanceRebuildAdminControllerApiAxiosParamCreator = function (configuration?: Configuration) {
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Array<string>} ledgerIds
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
rebuild: async (ledgerIds: Array<string>, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'ledgerIds' is not null or undefined
|
||||||
|
assertParamExists('rebuild', 'ledgerIds', ledgerIds)
|
||||||
|
const localVarPath = `/balances/rebuild`;
|
||||||
|
// 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: 'POST', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
if (ledgerIds) {
|
||||||
|
localVarQueryParameter['ledgerIds'] = ledgerIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BalanceRebuildAdminControllerApi - functional programming interface
|
||||||
|
*/
|
||||||
|
export const BalanceRebuildAdminControllerApiFp = function(configuration?: Configuration) {
|
||||||
|
const localVarAxiosParamCreator = BalanceRebuildAdminControllerApiAxiosParamCreator(configuration)
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Array<string>} ledgerIds
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async rebuild(ledgerIds: Array<string>, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.rebuild(ledgerIds, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['BalanceRebuildAdminControllerApi.rebuild']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BalanceRebuildAdminControllerApi - factory interface
|
||||||
|
*/
|
||||||
|
export const BalanceRebuildAdminControllerApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
|
||||||
|
const localVarFp = BalanceRebuildAdminControllerApiFp(configuration)
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Array<string>} ledgerIds
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
rebuild(ledgerIds: Array<string>, options?: RawAxiosRequestConfig): AxiosPromise<void> {
|
||||||
|
return localVarFp.rebuild(ledgerIds, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BalanceRebuildAdminControllerApi - object-oriented interface
|
||||||
|
*/
|
||||||
|
export class BalanceRebuildAdminControllerApi extends BaseAPI {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Array<string>} ledgerIds
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
public rebuild(ledgerIds: Array<string>, options?: RawAxiosRequestConfig) {
|
||||||
|
return BalanceRebuildAdminControllerApiFp(this.configuration).rebuild(ledgerIds, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CharacterApi - axios parameter creator
|
* CharacterApi - axios parameter creator
|
||||||
*/
|
*/
|
||||||
@@ -1553,6 +1798,178 @@ export class CharacterApi extends BaseAPI {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CorporationApi - axios parameter creator
|
||||||
|
*/
|
||||||
|
export const CorporationApiAxiosParamCreator = function (configuration?: Configuration) {
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Resolve public information (name, ticker, alliance) for a corporation id
|
||||||
|
* @param {number} corporationId Corporation id to resolve, e.g. 98000001
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
findCorporation: async (corporationId: number, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'corporationId' is not null or undefined
|
||||||
|
assertParamExists('findCorporation', 'corporationId', corporationId)
|
||||||
|
const localVarPath = `/corporations/{corporationId}`
|
||||||
|
.replace('{corporationId}', encodeURIComponent(String(corporationId)));
|
||||||
|
// 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'] = '*/*';
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Resolve public information for several corporation ids at once, silently omitting ids ESI cannot resolve
|
||||||
|
* @param {Array<number>} ids Corporation ids to resolve, e.g. ids=98000001,98000002
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
findCorporations: async (ids: Array<number>, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'ids' is not null or undefined
|
||||||
|
assertParamExists('findCorporations', 'ids', ids)
|
||||||
|
const localVarPath = `/corporations`;
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
if (ids) {
|
||||||
|
localVarQueryParameter['ids'] = ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
localVarHeaderParameter['Accept'] = '*/*';
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CorporationApi - functional programming interface
|
||||||
|
*/
|
||||||
|
export const CorporationApiFp = function(configuration?: Configuration) {
|
||||||
|
const localVarAxiosParamCreator = CorporationApiAxiosParamCreator(configuration)
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Resolve public information (name, ticker, alliance) for a corporation id
|
||||||
|
* @param {number} corporationId Corporation id to resolve, e.g. 98000001
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async findCorporation(corporationId: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<CorporationResponse>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.findCorporation(corporationId, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['CorporationApi.findCorporation']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Resolve public information for several corporation ids at once, silently omitting ids ESI cannot resolve
|
||||||
|
* @param {Array<number>} ids Corporation ids to resolve, e.g. ids=98000001,98000002
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async findCorporations(ids: Array<number>, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<CorporationResponse>>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.findCorporations(ids, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['CorporationApi.findCorporations']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CorporationApi - factory interface
|
||||||
|
*/
|
||||||
|
export const CorporationApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
|
||||||
|
const localVarFp = CorporationApiFp(configuration)
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Resolve public information (name, ticker, alliance) for a corporation id
|
||||||
|
* @param {number} corporationId Corporation id to resolve, e.g. 98000001
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
findCorporation(corporationId: number, options?: RawAxiosRequestConfig): AxiosPromise<CorporationResponse> {
|
||||||
|
return localVarFp.findCorporation(corporationId, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Resolve public information for several corporation ids at once, silently omitting ids ESI cannot resolve
|
||||||
|
* @param {Array<number>} ids Corporation ids to resolve, e.g. ids=98000001,98000002
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
findCorporations(ids: Array<number>, options?: RawAxiosRequestConfig): AxiosPromise<Array<CorporationResponse>> {
|
||||||
|
return localVarFp.findCorporations(ids, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CorporationApi - object-oriented interface
|
||||||
|
*/
|
||||||
|
export class CorporationApi extends BaseAPI {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Resolve public information (name, ticker, alliance) for a corporation id
|
||||||
|
* @param {number} corporationId Corporation id to resolve, e.g. 98000001
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
public findCorporation(corporationId: number, options?: RawAxiosRequestConfig) {
|
||||||
|
return CorporationApiFp(this.configuration).findCorporation(corporationId, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Resolve public information for several corporation ids at once, silently omitting ids ESI cannot resolve
|
||||||
|
* @param {Array<number>} ids Corporation ids to resolve, e.g. ids=98000001,98000002
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
public findCorporations(ids: Array<number>, options?: RawAxiosRequestConfig) {
|
||||||
|
return CorporationApiFp(this.configuration).findCorporations(ids, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LedgerApi - axios parameter creator
|
* LedgerApi - axios parameter creator
|
||||||
*/
|
*/
|
||||||
@@ -3586,12 +4003,16 @@ export const RuleScriptApiAxiosParamCreator = function (configuration?: Configur
|
|||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Download the TypeScript definitions for the rule script runtime
|
* @summary Download a rule script type definition file by name
|
||||||
|
* @param {string} name
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
getScriptDefinitions: async (options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
getScriptDefinition: async (name: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
const localVarPath = `/rule-scripts/definitions`;
|
// verify required parameter 'name' is not null or undefined
|
||||||
|
assertParamExists('getScriptDefinition', 'name', name)
|
||||||
|
const localVarPath = `/rule-scripts/definitions/{name}`
|
||||||
|
.replace('{name}', encodeURIComponent(String(name)));
|
||||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
let baseOptions;
|
let baseOptions;
|
||||||
@@ -3609,6 +4030,36 @@ export const RuleScriptApiAxiosParamCreator = function (configuration?: Configur
|
|||||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary List the available rule script type definition files
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
listScriptDefinitions: async (options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
const localVarPath = `/rule-scripts/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'] = '*/*';
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: toPathString(localVarUrlObj),
|
url: toPathString(localVarUrlObj),
|
||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
@@ -3625,14 +4076,27 @@ export const RuleScriptApiFp = function(configuration?: Configuration) {
|
|||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Download the TypeScript definitions for the rule script runtime
|
* @summary Download a rule script type definition file by name
|
||||||
|
* @param {string} name
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async getScriptDefinitions(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<string>> {
|
async getScriptDefinition(name: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<string>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getScriptDefinitions(options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.getScriptDefinition(name, options);
|
||||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
const localVarOperationServerBasePath = operationServerMap['RuleScriptApi.getScriptDefinitions']?.[localVarOperationServerIndex]?.url;
|
const localVarOperationServerBasePath = operationServerMap['RuleScriptApi.getScriptDefinition']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary List the available rule script type definition files
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async listScriptDefinitions(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.listScriptDefinitions(options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['RuleScriptApi.listScriptDefinitions']?.[localVarOperationServerIndex]?.url;
|
||||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -3646,12 +4110,22 @@ export const RuleScriptApiFactory = function (configuration?: Configuration, bas
|
|||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Download the TypeScript definitions for the rule script runtime
|
* @summary Download a rule script type definition file by name
|
||||||
|
* @param {string} name
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
getScriptDefinitions(options?: RawAxiosRequestConfig): AxiosPromise<string> {
|
getScriptDefinition(name: string, options?: RawAxiosRequestConfig): AxiosPromise<string> {
|
||||||
return localVarFp.getScriptDefinitions(options).then((request) => request(axios, basePath));
|
return localVarFp.getScriptDefinition(name, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary List the available rule script type definition files
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
listScriptDefinitions(options?: RawAxiosRequestConfig): AxiosPromise<Array<string>> {
|
||||||
|
return localVarFp.listScriptDefinitions(options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -3662,12 +4136,23 @@ export const RuleScriptApiFactory = function (configuration?: Configuration, bas
|
|||||||
export class RuleScriptApi extends BaseAPI {
|
export class RuleScriptApi extends BaseAPI {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Download the TypeScript definitions for the rule script runtime
|
* @summary Download a rule script type definition file by name
|
||||||
|
* @param {string} name
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
public getScriptDefinitions(options?: RawAxiosRequestConfig) {
|
public getScriptDefinition(name: string, options?: RawAxiosRequestConfig) {
|
||||||
return RuleScriptApiFp(this.configuration).getScriptDefinitions(options).then((request) => request(this.axios, this.basePath));
|
return RuleScriptApiFp(this.configuration).getScriptDefinition(name, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary List the available rule script type definition files
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
public listScriptDefinitions(options?: RawAxiosRequestConfig) {
|
||||||
|
return RuleScriptApiFp(this.configuration).listScriptDefinitions(options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3707,6 +4192,74 @@ export const TransactionApiAxiosParamCreator = function (configuration?: Configu
|
|||||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Get the daily FIFO-realized profit series for a single ledger
|
||||||
|
* @param {string} ledgerId Id of the ledger
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
marginPerDayInLedger: async (ledgerId: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'ledgerId' is not null or undefined
|
||||||
|
assertParamExists('marginPerDayInLedger', 'ledgerId', ledgerId)
|
||||||
|
const localVarPath = `/ledgers/{ledgerId}/margin`
|
||||||
|
.replace('{ledgerId}', encodeURIComponent(String(ledgerId)));
|
||||||
|
// 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'] = '*/*';
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Get the daily profit series for a single ledger
|
||||||
|
* @param {string} ledgerId Id of the ledger
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
profitPerDayInLedger: async (ledgerId: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'ledgerId' is not null or undefined
|
||||||
|
assertParamExists('profitPerDayInLedger', 'ledgerId', ledgerId)
|
||||||
|
const localVarPath = `/ledgers/{ledgerId}/profit`
|
||||||
|
.replace('{ledgerId}', encodeURIComponent(String(ledgerId)));
|
||||||
|
// 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'] = '*/*';
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: toPathString(localVarUrlObj),
|
url: toPathString(localVarUrlObj),
|
||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
@@ -3734,6 +4287,32 @@ export const TransactionApiFp = function(configuration?: Configuration) {
|
|||||||
const localVarOperationServerBasePath = operationServerMap['TransactionApi.finAllTransactionsInLedger']?.[localVarOperationServerIndex]?.url;
|
const localVarOperationServerBasePath = operationServerMap['TransactionApi.finAllTransactionsInLedger']?.[localVarOperationServerIndex]?.url;
|
||||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Get the daily FIFO-realized profit series for a single ledger
|
||||||
|
* @param {string} ledgerId Id of the ledger
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async marginPerDayInLedger(ledgerId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<DailyProfitResponse>>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.marginPerDayInLedger(ledgerId, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['TransactionApi.marginPerDayInLedger']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Get the daily profit series for a single ledger
|
||||||
|
* @param {string} ledgerId Id of the ledger
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async profitPerDayInLedger(ledgerId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<DailyProfitResponse>>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.profitPerDayInLedger(ledgerId, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['TransactionApi.profitPerDayInLedger']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3753,6 +4332,26 @@ export const TransactionApiFactory = function (configuration?: Configuration, ba
|
|||||||
finAllTransactionsInLedger(ledgerId: string, options?: RawAxiosRequestConfig): AxiosPromise<Array<TransactionResponse>> {
|
finAllTransactionsInLedger(ledgerId: string, options?: RawAxiosRequestConfig): AxiosPromise<Array<TransactionResponse>> {
|
||||||
return localVarFp.finAllTransactionsInLedger(ledgerId, options).then((request) => request(axios, basePath));
|
return localVarFp.finAllTransactionsInLedger(ledgerId, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Get the daily FIFO-realized profit series for a single ledger
|
||||||
|
* @param {string} ledgerId Id of the ledger
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
marginPerDayInLedger(ledgerId: string, options?: RawAxiosRequestConfig): AxiosPromise<Array<DailyProfitResponse>> {
|
||||||
|
return localVarFp.marginPerDayInLedger(ledgerId, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Get the daily profit series for a single ledger
|
||||||
|
* @param {string} ledgerId Id of the ledger
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
profitPerDayInLedger(ledgerId: string, options?: RawAxiosRequestConfig): AxiosPromise<Array<DailyProfitResponse>> {
|
||||||
|
return localVarFp.profitPerDayInLedger(ledgerId, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3770,6 +4369,28 @@ export class TransactionApi extends BaseAPI {
|
|||||||
public finAllTransactionsInLedger(ledgerId: string, options?: RawAxiosRequestConfig) {
|
public finAllTransactionsInLedger(ledgerId: string, options?: RawAxiosRequestConfig) {
|
||||||
return TransactionApiFp(this.configuration).finAllTransactionsInLedger(ledgerId, options).then((request) => request(this.axios, this.basePath));
|
return TransactionApiFp(this.configuration).finAllTransactionsInLedger(ledgerId, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Get the daily FIFO-realized profit series for a single ledger
|
||||||
|
* @param {string} ledgerId Id of the ledger
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
public marginPerDayInLedger(ledgerId: string, options?: RawAxiosRequestConfig) {
|
||||||
|
return TransactionApiFp(this.configuration).marginPerDayInLedger(ledgerId, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Get the daily profit series for a single ledger
|
||||||
|
* @param {string} ledgerId Id of the ledger
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
public profitPerDayInLedger(ledgerId: string, options?: RawAxiosRequestConfig) {
|
||||||
|
return TransactionApiFp(this.configuration).profitPerDayInLedger(ledgerId, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {Modal} from "@/components";
|
|||||||
import LedgerLabel from "./LedgerLabel.vue";
|
import LedgerLabel from "./LedgerLabel.vue";
|
||||||
import {PlusIcon, TrashIcon} from '@heroicons/vue/24/outline';
|
import {PlusIcon, TrashIcon} from '@heroicons/vue/24/outline';
|
||||||
import LedgerSelect from "@/ledger/LedgerSelect.vue";
|
import LedgerSelect from "@/ledger/LedgerSelect.vue";
|
||||||
|
import {toast} from "@/toast";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
ledgerId?: string;
|
ledgerId?: string;
|
||||||
@@ -59,18 +60,16 @@ const title = computed(() => {
|
|||||||
|
|
||||||
const create = () => {
|
const create = () => {
|
||||||
if (type.value === LedgerTypes.Main) {
|
if (type.value === LedgerTypes.Main) {
|
||||||
ledgersStore.createMain({name: name.value})
|
return ledgersStore.createMain({name: name.value})
|
||||||
} else {
|
|
||||||
ledgersStore.createCombined({name: name.value, memberLedgerIds: members.value.map(l => l.ledgerId)})
|
|
||||||
}
|
}
|
||||||
|
return ledgersStore.createCombined({name: name.value, memberLedgerIds: members.value.map(l => l.ledgerId)})
|
||||||
}
|
}
|
||||||
|
|
||||||
const update = () => {
|
const update = () => {
|
||||||
if (type.value === LedgerTypes.Main) {
|
if (type.value === LedgerTypes.Main) {
|
||||||
ledgersStore.updateMain(props.ledgerId, {name: name.value})
|
return ledgersStore.updateMain(props.ledgerId, {name: name.value})
|
||||||
} else {
|
|
||||||
ledgersStore.updateCombined(props.ledgerId, {name: name.value, memberLedgerIds: members.value.map(l => l.ledgerId)})
|
|
||||||
}
|
}
|
||||||
|
return ledgersStore.updateCombined(props.ledgerId, {name: name.value, memberLedgerIds: members.value.map(l => l.ledgerId)})
|
||||||
}
|
}
|
||||||
|
|
||||||
const save = () => {
|
const save = () => {
|
||||||
@@ -78,12 +77,11 @@ const save = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCreating.value) {
|
const creating = isCreating.value;
|
||||||
create();
|
const action = creating ? create() : update();
|
||||||
} else {
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
modalOpen.value = false;
|
modalOpen.value = false;
|
||||||
|
action.then(() => toast.success(creating ? 'Ledger created' : 'Ledger updated'));
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({ open });
|
defineExpose({ open });
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import {describe, expect, test} from 'vitest';
|
||||||
|
import {appraiseItemBalances} from './balanceAppraisal';
|
||||||
|
import type {MarketTypePrice} from '@/market';
|
||||||
|
|
||||||
|
const price = (id: number, buy: number, sell: number): MarketTypePrice => ({
|
||||||
|
type: {id, name: `type-${id}`} as MarketTypePrice['type'],
|
||||||
|
buy,
|
||||||
|
sell,
|
||||||
|
orderCount: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('appraiseItemBalances', () => {
|
||||||
|
test('sums quantity times buy and sell across stacks', () => {
|
||||||
|
const result = appraiseItemBalances(
|
||||||
|
[{typeId: 1, quantity: 2}, {typeId: 2, quantity: 3}],
|
||||||
|
[price(1, 10, 12), price(2, 100, 110)],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toEqual({buy: 2 * 10 + 3 * 100, sell: 2 * 12 + 3 * 110});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ignores stacks with no resolved price', () => {
|
||||||
|
const result = appraiseItemBalances(
|
||||||
|
[{typeId: 1, quantity: 2}, {typeId: 99, quantity: 5}],
|
||||||
|
[price(1, 10, 12)],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toEqual({buy: 20, sell: 24});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('returns zero totals for no items', () => {
|
||||||
|
expect(appraiseItemBalances([], [])).toEqual({buy: 0, sell: 0});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import {ItemBalanceResponse} from "@/generated/mammon";
|
||||||
|
import {MarketTypePrice} from "@/market";
|
||||||
|
|
||||||
|
export interface ItemBalanceAppraisal {
|
||||||
|
buy: number;
|
||||||
|
sell: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const appraiseItemBalances = (
|
||||||
|
itemBalances: ItemBalanceResponse[],
|
||||||
|
prices: MarketTypePrice[],
|
||||||
|
): ItemBalanceAppraisal => {
|
||||||
|
const priceByTypeId = new Map(prices.map(p => [p.type.id, p]));
|
||||||
|
|
||||||
|
return itemBalances.reduce<ItemBalanceAppraisal>((totals, {typeId, quantity}) => {
|
||||||
|
const price = priceByTypeId.get(typeId);
|
||||||
|
|
||||||
|
if (price) {
|
||||||
|
totals.buy += quantity * price.buy;
|
||||||
|
totals.sell += quantity * price.sell;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totals;
|
||||||
|
}, {buy: 0, sell: 0});
|
||||||
|
};
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './ledger';
|
export * from './ledger';
|
||||||
|
export * from './balanceAppraisal';
|
||||||
|
|
||||||
export {default as LedgerLabel} from './LedgerLabel.vue';
|
export {default as LedgerLabel} from './LedgerLabel.vue';
|
||||||
export {default as LedgerSelect} from './LedgerSelect.vue';
|
export {default as LedgerSelect} from './LedgerSelect.vue';
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import {logResource} from "@/service";
|
import {logResource} from "@/service";
|
||||||
import {getAccessToken, setAccessToken} from "@/auth/token";
|
import {getAccessToken, setAccessToken} from "@/auth/token";
|
||||||
|
import {toast} from "@/toast";
|
||||||
import axios, {InternalAxiosRequestConfig} from "axios";
|
import axios, {InternalAxiosRequestConfig} from "axios";
|
||||||
import {
|
import {
|
||||||
AcquisitionApi,
|
AcquisitionApi,
|
||||||
ActivityApi,
|
ActivityApi,
|
||||||
AuthApi,
|
AuthApi,
|
||||||
CharacterApi,
|
CharacterApi,
|
||||||
|
CorporationApi,
|
||||||
LedgerApi,
|
LedgerApi,
|
||||||
LocationApi,
|
LocationApi,
|
||||||
MarketApi,
|
MarketApi,
|
||||||
@@ -86,6 +88,12 @@ mammonAxiosInstance.interceptors.response.use(response => response, async error
|
|||||||
}
|
}
|
||||||
onAuthExpired();
|
onAuthExpired();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const status = error.response?.status;
|
||||||
|
|
||||||
|
if (status !== 401 && status !== 403) {
|
||||||
|
toast.error('Something went wrong');
|
||||||
|
}
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -101,6 +109,7 @@ export const postLogout = (): Promise<void> =>
|
|||||||
export const ledgerApi = new LedgerApi(undefined, mammonUrl, mammonAxiosInstance);
|
export const ledgerApi = new LedgerApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||||
export const transactionApi = new TransactionApi(undefined, mammonUrl, mammonAxiosInstance);
|
export const transactionApi = new TransactionApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||||
export const characterApi = new CharacterApi(undefined, mammonUrl, mammonAxiosInstance);
|
export const characterApi = new CharacterApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||||
|
export const corporationApi = new CorporationApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||||
export const ruleBookApi = new RuleBookApi(undefined, mammonUrl, mammonAxiosInstance);
|
export const ruleBookApi = new RuleBookApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||||
export const ruleScriptApi = new RuleScriptApi(undefined, mammonUrl, mammonAxiosInstance);
|
export const ruleScriptApi = new RuleScriptApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||||
export const activityApi = new ActivityApi(undefined, mammonUrl, mammonAxiosInstance);
|
export const activityApi = new ActivityApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
import { describe, expect, test } from 'vitest'
|
|
||||||
import { RegionalMarketCache } from './RegionalMarketCache'
|
|
||||||
|
|
||||||
describe('RegionalMarketCache', () => {
|
|
||||||
test('should cache and retrieve values', async () => {
|
|
||||||
const cache = new RegionalMarketCache<string>(1000)
|
|
||||||
|
|
||||||
cache.set(1, 1, 'test')
|
|
||||||
expect(cache.get(1, 1)).toBe('test')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('should remove values', async () => {
|
|
||||||
const cache = new RegionalMarketCache<string>(1000)
|
|
||||||
|
|
||||||
cache.set(1, 1, 'test')
|
|
||||||
cache.remove(1, 1)
|
|
||||||
expect(cache.get(1, 1)).toBeUndefined()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('should compute values if absent', async () => {
|
|
||||||
const cache = new RegionalMarketCache<string>(1000)
|
|
||||||
const value = await cache.computeIfAbsent(1, 1, () => Promise.resolve('test'))
|
|
||||||
|
|
||||||
expect(value).toBe('test')
|
|
||||||
expect(cache.get(1, 1)).toBe('test')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('should expire values', async () => {
|
|
||||||
const cache = new RegionalMarketCache<string>(1)
|
|
||||||
|
|
||||||
cache.set(1, 1, 'test')
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 10))
|
|
||||||
expect(cache.get(1, 1)).toBeUndefined()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
class CacheEntry<T> {
|
|
||||||
public value: T;
|
|
||||||
public expiration: Date;
|
|
||||||
|
|
||||||
constructor(value: T, expiration: Date) {
|
|
||||||
this.value = value;
|
|
||||||
this.expiration = expiration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ExpirationSupplier<T> = (v: T) => Date;
|
|
||||||
|
|
||||||
export class RegionalMarketCache<T> {
|
|
||||||
private cache: Record<number, Record<number, CacheEntry<T>>>;
|
|
||||||
private expirationSupplier: (v: T) => Date;
|
|
||||||
|
|
||||||
constructor(expiration: ExpirationSupplier<T> | number) {
|
|
||||||
this.cache = {};
|
|
||||||
this.expirationSupplier = expiration instanceof Function ? expiration : () => new Date(Date.now() + expiration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(regionId: number, typeId: number): T | undefined {
|
|
||||||
const entry = this.cache[regionId]?.[typeId];
|
|
||||||
|
|
||||||
if (entry && entry.expiration > new Date()) {
|
|
||||||
return entry.value;
|
|
||||||
}
|
|
||||||
this.remove(regionId, typeId);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set(regionId: number, typeId: number, value: T): void {
|
|
||||||
this.cache[regionId] = this.cache[regionId] ?? {};
|
|
||||||
this.cache[regionId][typeId] = new CacheEntry(value, this.expirationSupplier(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public remove(regionId: number, typeId: number): void {
|
|
||||||
delete this.cache[regionId]?.[typeId];
|
|
||||||
}
|
|
||||||
|
|
||||||
public async computeIfAbsent(regionId: number, typeId: number, supplier: () => (Promise<T> | T)): Promise<T> {
|
|
||||||
let value = this.get(regionId, typeId);
|
|
||||||
|
|
||||||
if (!value) {
|
|
||||||
value = await supplier();
|
|
||||||
this.set(regionId, typeId, value);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -43,7 +43,7 @@ const lineColor = computed(() => {
|
|||||||
<MarketTrendIcon v-else :trend="quartiles.trend" />
|
<MarketTrendIcon v-else :trend="quartiles.trend" />
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<div class="bg-slate-500 -left-1/2 relative tooltip-content" v-if="quartiles">
|
<div class="bg-slate-500 tooltip-content" v-if="quartiles">
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -74,9 +74,6 @@ const lineColor = computed(() => {
|
|||||||
&.tooltip-top>:deep(div.header) {
|
&.tooltip-top>:deep(div.header) {
|
||||||
@apply rounded-t-md bg-slate-600;
|
@apply rounded-t-md bg-slate-600;
|
||||||
}
|
}
|
||||||
&.tooltip-bottom .tooltip-content {
|
|
||||||
bottom: 75px;
|
|
||||||
}
|
|
||||||
&.tooltip-bottom>:deep(div.header) {
|
&.tooltip-bottom>:deep(div.header) {
|
||||||
@apply rounded-b-md bg-slate-600;
|
@apply rounded-b-md bg-slate-600;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {getMarketTypes, MarketTypePrice, useAppraisalStore} from "@/market";
|
import {getMarketTypes, getPrices, MarketTypePrice} from "@/market";
|
||||||
import {ref, watch} from 'vue';
|
import {ref, watch} from 'vue';
|
||||||
import {ArrowPathIcon} from '@heroicons/vue/24/outline';
|
import {ArrowPathIcon} from '@heroicons/vue/24/outline';
|
||||||
import {useAutoRefresh} from '@/composables';
|
import {useAutoRefresh} from '@/composables';
|
||||||
|
import {MarketLocationInput, useMarketLocationStore} from '@/market/location';
|
||||||
import {AcquiredType} from './AcquiredType';
|
import {AcquiredType} from './AcquiredType';
|
||||||
import {RawAcquiredType} from './acquisition';
|
import {RawAcquiredType} from './acquisition';
|
||||||
import AcquisitionResultTable from './AcquisitionResultTable.vue';
|
import AcquisitionResultTable from './AcquisitionResultTable.vue';
|
||||||
@@ -20,7 +21,7 @@ const props = defineProps<Props>();
|
|||||||
const buyModal = ref<typeof BuyModal>();
|
const buyModal = ref<typeof BuyModal>();
|
||||||
const sellModal = ref<typeof SellModal>();
|
const sellModal = ref<typeof SellModal>();
|
||||||
|
|
||||||
const appraisalStore = useAppraisalStore();
|
const marketLocationStore = useMarketLocationStore();
|
||||||
const enriched = ref<AcquiredType[]>([]);
|
const enriched = ref<AcquiredType[]>([]);
|
||||||
|
|
||||||
const refresh = async (itms: RawAcquiredType[] = props.items) => {
|
const refresh = async (itms: RawAcquiredType[] = props.items) => {
|
||||||
@@ -30,7 +31,7 @@ const refresh = async (itms: RawAcquiredType[] = props.items) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const types = await getMarketTypes([...new Set(itms.map(i => i.type))]);
|
const types = await getMarketTypes([...new Set(itms.map(i => i.type))]);
|
||||||
const prices = await appraisalStore.getPrices(types);
|
const prices = await getPrices(types, marketLocationStore.location.id);
|
||||||
|
|
||||||
enriched.value = itms.map(i => {
|
enriched.value = itms.map(i => {
|
||||||
const price = prices.find(p => p.type.id === i.type) as MarketTypePrice;
|
const price = prices.find(p => p.type.id === i.type) as MarketTypePrice;
|
||||||
@@ -44,18 +45,21 @@ const refresh = async (itms: RawAcquiredType[] = props.items) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(() => props.items, refresh, {immediate: true});
|
watch([() => props.items, () => marketLocationStore.location], ([itms]) => refresh(itms), {immediate: true});
|
||||||
|
|
||||||
const {active: autoRefresh, toggle: toggleAutoRefresh} = useAutoRefresh(() => refresh(), 5 * 60 * 1000);
|
const {active: autoRefresh, toggle: toggleAutoRefresh} = useAutoRefresh(() => refresh(), 5 * 60 * 1000);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="ms-auto flex">
|
<div class="ms-auto flex items-center gap-2">
|
||||||
<button class="rounded-e-none" @click="refresh()">Refresh</button>
|
<MarketLocationInput v-model="marketLocationStore.location" />
|
||||||
<button class="rounded-s-none border-s-0 flex items-center" :class="{ 'bg-slate-700': autoRefresh }" title="Auto refresh" @click="toggleAutoRefresh">
|
<div class="flex">
|
||||||
<ArrowPathIcon class="w-5 h-5" :class="{ 'animate-spin': autoRefresh }" />
|
<button class="rounded-e-none" @click="refresh()">Refresh</button>
|
||||||
</button>
|
<button class="rounded-s-none border-s-0 flex items-center" :class="{ 'bg-slate-700': autoRefresh }" title="Auto refresh" @click="toggleAutoRefresh">
|
||||||
|
<ArrowPathIcon class="w-5 h-5" :class="{ 'animate-spin': autoRefresh }" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="enriched.length > 0">
|
<template v-if="enriched.length > 0">
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {Ledger, LedgerSelect, isMain, useLedgersStore} from '@/ledger';
|
|||||||
import {computed, ref} from 'vue';
|
import {computed, ref} from 'vue';
|
||||||
import {fromEveDatetimeInput, toEveDatetimeInput} from './AcquiredType';
|
import {fromEveDatetimeInput, toEveDatetimeInput} from './AcquiredType';
|
||||||
import {useAcquiredTypesStore} from './acquisition';
|
import {useAcquiredTypesStore} from './acquisition';
|
||||||
|
import {toast} from '@/toast';
|
||||||
|
|
||||||
const acquiredTypesStore = useAcquiredTypesStore();
|
const acquiredTypesStore = useAcquiredTypesStore();
|
||||||
const ledgersStore = useLedgersStore();
|
const ledgersStore = useLedgersStore();
|
||||||
@@ -58,6 +59,7 @@ const add = async () => {
|
|||||||
|
|
||||||
await acquiredTypesStore.addAcquiredType(id, count.value, price.value, lid, fromEveDatetimeInput(date.value));
|
await acquiredTypesStore.addAcquiredType(id, count.value, price.value, lid, fromEveDatetimeInput(date.value));
|
||||||
modalOpen.value = false;
|
modalOpen.value = false;
|
||||||
|
toast.success('Acquisition added');
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({ open });
|
defineExpose({ open });
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Ledger, LedgerSelect, isMain, useLedgersStore } from '@/ledger';
|
|||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { AcquiredType, acquiredTypesToSorted, fromEveDatetimeInput, toEveDatetimeInput } from './AcquiredType';
|
import { AcquiredType, acquiredTypesToSorted, fromEveDatetimeInput, toEveDatetimeInput } from './AcquiredType';
|
||||||
import { useAcquiredTypesStore } from './acquisition';
|
import { useAcquiredTypesStore } from './acquisition';
|
||||||
|
import { toast } from '@/toast';
|
||||||
|
|
||||||
|
|
||||||
const acquiredTypesStore = useAcquiredTypesStore();
|
const acquiredTypesStore = useAcquiredTypesStore();
|
||||||
@@ -61,6 +62,7 @@ const remove = async () => {
|
|||||||
remaining -= quantity;
|
remaining -= quantity;
|
||||||
}
|
}
|
||||||
modalOpen.value = false;
|
modalOpen.value = false;
|
||||||
|
toast.success('Consumption added');
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({ open });
|
defineExpose({ open });
|
||||||
|
|||||||
@@ -1,47 +1,17 @@
|
|||||||
import {defineStore} from 'pinia';
|
|
||||||
import {RegionalMarketCache} from '../RegionalMarketCache';
|
|
||||||
import {jitaId} from '../market';
|
|
||||||
import {MarketType} from "../type";
|
import {MarketType} from "../type";
|
||||||
import {MarketTypePrice} from './MarketTypePrice';
|
import {MarketTypePrice} from './MarketTypePrice';
|
||||||
import {getMammonPrices} from './mammon';
|
import {getMammonPrices} from './mammon';
|
||||||
|
|
||||||
const CACHE_DURATION = 1000 * 60 * 5; // 5 minutes
|
|
||||||
const BATCH_SIZE = 100;
|
const BATCH_SIZE = 100;
|
||||||
|
|
||||||
export const useAppraisalStore = defineStore('appraisal', () => {
|
export const getPrice = async (type: MarketType, locationId?: number): Promise<MarketTypePrice> => (await getPrices([type], locationId))[0];
|
||||||
const cache: RegionalMarketCache<MarketTypePrice> = new RegionalMarketCache(CACHE_DURATION);
|
|
||||||
|
|
||||||
const getPricesUncached = getMammonPrices;
|
export const getPrices = async (types: MarketType[], locationId?: number): Promise<MarketTypePrice[]> => {
|
||||||
|
const batches: Promise<MarketTypePrice[]>[] = [];
|
||||||
|
|
||||||
const getPrice = async (type: MarketType, locationId?: number): Promise<MarketTypePrice> => (await getPrices([type], locationId))[0];
|
for (let i = 0; i < types.length; i += BATCH_SIZE) {
|
||||||
const getPrices = async (types: MarketType[], locationId?: number): Promise<MarketTypePrice[]> => {
|
batches.push(getMammonPrices(types.slice(i, i + BATCH_SIZE), locationId));
|
||||||
const cached: MarketTypePrice[] = [];
|
}
|
||||||
const uncached: MarketType[] = [];
|
|
||||||
const lId = locationId ?? jitaId;
|
|
||||||
|
|
||||||
types.forEach(t => {
|
return (await Promise.all(batches)).flat();
|
||||||
const cachedPrice = cache.get(lId, t.id);
|
};
|
||||||
|
|
||||||
if (cachedPrice) {
|
|
||||||
cached.push(cachedPrice);
|
|
||||||
} else {
|
|
||||||
uncached.push(t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (uncached.length > 0) {
|
|
||||||
const batches: Promise<MarketTypePrice[]>[] = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < uncached.length; i += BATCH_SIZE) {
|
|
||||||
batches.push(getPricesUncached(uncached.slice(i, i + BATCH_SIZE), lId));
|
|
||||||
}
|
|
||||||
|
|
||||||
const prices = (await Promise.all(batches)).flat();
|
|
||||||
|
|
||||||
prices.forEach(p => cache.set(lId, p.type.id, p));
|
|
||||||
return [ ...cached, ...prices ];
|
|
||||||
}
|
|
||||||
return cached;
|
|
||||||
};
|
|
||||||
return { getPrice, getPrices };
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
export * from './RegionalMarketCache';
|
|
||||||
export * from './history';
|
export * from './history';
|
||||||
export * from './location';
|
export * from './location';
|
||||||
export * from './order';
|
export * from './order';
|
||||||
@@ -6,7 +5,6 @@ export * from './tax';
|
|||||||
export * from './type';
|
export * from './type';
|
||||||
|
|
||||||
export * from './appraisal';
|
export * from './appraisal';
|
||||||
export * from './market';
|
|
||||||
|
|
||||||
export { default as IskLabel } from './IskLabel.vue';
|
export { default as IskLabel } from './IskLabel.vue';
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
|
export * from './location';
|
||||||
export * from './MarketLocation';
|
export * from './MarketLocation';
|
||||||
export { default as MarketLocationInput } from './MarketLocationInput.vue';
|
export { default as MarketLocationInput } from './MarketLocationInput.vue';
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import {useLocalStorage} from "@vueuse/core";
|
||||||
|
import {defineStore} from "pinia";
|
||||||
|
import type {MarketLocation} from "./MarketLocation";
|
||||||
|
|
||||||
|
const defaultLocation: MarketLocation = {
|
||||||
|
id: 60003760,
|
||||||
|
name: 'Jita IV - Moon 4 - Caldari Navy Assembly Plant',
|
||||||
|
systemId: 30000142,
|
||||||
|
systemName: 'Jita',
|
||||||
|
regionId: 10000002,
|
||||||
|
regionName: 'The Forge',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMarketLocationStore = defineStore("marketLocation", () => {
|
||||||
|
const location = useLocalStorage<MarketLocation>("market-location", defaultLocation);
|
||||||
|
|
||||||
|
return {location};
|
||||||
|
});
|
||||||
@@ -1 +0,0 @@
|
|||||||
export const jitaId = 60003760;
|
|
||||||
@@ -6,12 +6,14 @@ import {PencilSquareIcon} from "@heroicons/vue/24/outline";
|
|||||||
import {IskLabel} from "@/market";
|
import {IskLabel} from "@/market";
|
||||||
import {SortableHeader, useSort, VirtualScrollTable} from "@/components/table";
|
import {SortableHeader, useSort, VirtualScrollTable} from "@/components/table";
|
||||||
import {activityApi} from "@/mammon";
|
import {activityApi} from "@/mammon";
|
||||||
|
import {toast} from "@/toast";
|
||||||
|
|
||||||
const ledgersStore = useLedgersStore();
|
const ledgersStore = useLedgersStore();
|
||||||
|
|
||||||
const editLedgerModal = ref<typeof EditLedgerModal>();
|
const editLedgerModal = ref<typeof EditLedgerModal>();
|
||||||
|
|
||||||
const processActivities = async () => {
|
const processActivities = async () => {
|
||||||
|
toast.info('Processing started');
|
||||||
await activityApi.processNewActivities();
|
await activityApi.processNewActivities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,31 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {RouterLink, RouterView} from 'vue-router';
|
import {RouterLink, RouterView} from 'vue-router';
|
||||||
import {LedgerLabel, useLedgerParam} from "@/ledger";
|
import {appraiseItemBalances, getLedgerBalance, isMain, LedgerLabel, useLedgerParam} from "@/ledger";
|
||||||
import {routeNames} from "@/routes.ts";
|
import {routeNames} from "@/routes.ts";
|
||||||
import {IskLabel} from "@/market";
|
import {getMarketTypes, getPrices, IskLabel} from "@/market";
|
||||||
|
import {useMarketLocationStore} from '@/market/location';
|
||||||
|
import {computedAsync} from "@vueuse/core";
|
||||||
|
|
||||||
const {ledger} = useLedgerParam();
|
const {ledgerId, ledger} = useLedgerParam();
|
||||||
|
const marketLocationStore = useMarketLocationStore();
|
||||||
|
|
||||||
|
const itemAppraisal = computedAsync(async () => {
|
||||||
|
if (!ledgerId.value) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {itemBalances} = await getLedgerBalance(ledgerId.value);
|
||||||
|
|
||||||
|
if (itemBalances.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const types = await getMarketTypes([...new Set(itemBalances.map(i => i.typeId))]);
|
||||||
|
const prices = await getPrices(types, marketLocationStore.location.id);
|
||||||
|
const appraisal = appraiseItemBalances(itemBalances, prices);
|
||||||
|
|
||||||
|
return appraisal.buy === 0 && appraisal.sell === 0 ? undefined : appraisal;
|
||||||
|
}, undefined);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -14,8 +35,12 @@ const {ledger} = useLedgerParam();
|
|||||||
<div class="flex w-full">
|
<div class="flex w-full">
|
||||||
<LedgerLabel :ledger="ledger" :link="false" />
|
<LedgerLabel :ledger="ledger" :link="false" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end w-full">
|
<div class="flex justify-end items-baseline gap-3 w-full mb-2">
|
||||||
<IskLabel class="mb-2" :amount="ledger.balance" />
|
<span v-if="itemAppraisal" class="text-sm text-gray-400">
|
||||||
|
~<IskLabel :amount="itemAppraisal.buy" :colored="false" /> buy /
|
||||||
|
~<IskLabel :amount="itemAppraisal.sell" :colored="false" /> sell
|
||||||
|
</span>
|
||||||
|
<IskLabel :amount="ledger.balance" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex border-b-2 border-emerald-500 mt-4">
|
<div class="flex border-b-2 border-emerald-500 mt-4">
|
||||||
@@ -28,6 +53,9 @@ const {ledger} = useLedgerParam();
|
|||||||
<RouterLink :to="{name: routeNames.listLedgerAcquisitions}" class="tab">
|
<RouterLink :to="{name: routeNames.listLedgerAcquisitions}" class="tab">
|
||||||
<span>Acquisitions</span>
|
<span>Acquisitions</span>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
|
<RouterLink v-if="isMain(ledger)" :to="{name: routeNames.viewLedgerStatistics}" class="tab">
|
||||||
|
<span>Statistics</span>
|
||||||
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
<RouterView />
|
<RouterView />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,185 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import {computed, ref, watch} from "vue";
|
||||||
|
import {
|
||||||
|
BarController,
|
||||||
|
BarElement,
|
||||||
|
CategoryScale,
|
||||||
|
Chart as ChartJS,
|
||||||
|
type ChartData,
|
||||||
|
type ChartDataset,
|
||||||
|
type ChartOptions,
|
||||||
|
Filler,
|
||||||
|
Legend,
|
||||||
|
LinearScale,
|
||||||
|
LineController,
|
||||||
|
LineElement,
|
||||||
|
PointElement,
|
||||||
|
Tooltip,
|
||||||
|
} from "chart.js";
|
||||||
|
import {Chart} from "vue-chartjs";
|
||||||
|
import {useLedgerParam} from "@/ledger";
|
||||||
|
import {transactionApi} from "@/mammon";
|
||||||
|
import {useProcessedResource} from "@/activity";
|
||||||
|
import {DailyProfitResponse} from "@/generated/mammon";
|
||||||
|
import {IskLabel} from "@/market";
|
||||||
|
import {formatIsk} from "@/formaters";
|
||||||
|
import {DualRangeSlider} from "@/components";
|
||||||
|
|
||||||
|
ChartJS.register(
|
||||||
|
CategoryScale, LinearScale,
|
||||||
|
BarController, BarElement,
|
||||||
|
LineController, LineElement, PointElement,
|
||||||
|
Tooltip, Legend, Filler,
|
||||||
|
);
|
||||||
|
|
||||||
|
const {ledgerId} = useLedgerParam();
|
||||||
|
|
||||||
|
const ProfitModes = {
|
||||||
|
CashFlow: 'CASH_FLOW',
|
||||||
|
Margin: 'MARGIN',
|
||||||
|
} as const;
|
||||||
|
type ProfitMode = typeof ProfitModes[keyof typeof ProfitModes];
|
||||||
|
|
||||||
|
const mode = ref<ProfitMode>(ProfitModes.CashFlow);
|
||||||
|
|
||||||
|
const profits = useProcessedResource<DailyProfitResponse[]>(async () => {
|
||||||
|
if (!ledgerId.value) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const {data} = mode.value === ProfitModes.Margin
|
||||||
|
? await transactionApi.marginPerDayInLedger(ledgerId.value)
|
||||||
|
: await transactionApi.profitPerDayInLedger(ledgerId.value);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const from = ref(0);
|
||||||
|
const to = ref(0);
|
||||||
|
|
||||||
|
watch(() => profits.value.length, length => {
|
||||||
|
from.value = 0;
|
||||||
|
to.value = Math.max(length - 1, 0);
|
||||||
|
}, {immediate: true});
|
||||||
|
|
||||||
|
const maxIndex = computed(() => Math.max(profits.value.length - 1, 0));
|
||||||
|
|
||||||
|
const range = computed(() => profits.value.slice(from.value, to.value + 1));
|
||||||
|
|
||||||
|
const total = computed(() => range.value.reduce((sum, p) => sum + p.profit, 0));
|
||||||
|
|
||||||
|
const cumulativeProfit = computed(() => {
|
||||||
|
let running = 0;
|
||||||
|
|
||||||
|
return range.value.map(p => (running += p.profit));
|
||||||
|
});
|
||||||
|
|
||||||
|
const chartData = computed<ChartData<'bar' | 'line'>>(() => {
|
||||||
|
const cumulative: ChartDataset<'line'> = {
|
||||||
|
type: 'line',
|
||||||
|
label: 'Cumulative profit',
|
||||||
|
data: cumulativeProfit.value,
|
||||||
|
borderColor: '#38bdf8',
|
||||||
|
backgroundColor: 'rgba(56, 189, 248, 0.15)',
|
||||||
|
pointBackgroundColor: '#38bdf8',
|
||||||
|
fill: true,
|
||||||
|
tension: 0.2,
|
||||||
|
yAxisID: 'y',
|
||||||
|
order: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const iskIn: ChartDataset<'bar'> = {
|
||||||
|
type: 'bar',
|
||||||
|
label: 'ISK in',
|
||||||
|
data: range.value.map(p => p.iskIn),
|
||||||
|
backgroundColor: 'rgba(16, 185, 129, 0.7)',
|
||||||
|
yAxisID: 'y',
|
||||||
|
order: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const iskOut: ChartDataset<'bar'> = {
|
||||||
|
type: 'bar',
|
||||||
|
label: 'ISK out',
|
||||||
|
data: range.value.map(p => -p.iskOut),
|
||||||
|
backgroundColor: 'rgba(180, 83, 9, 0.7)',
|
||||||
|
yAxisID: 'y',
|
||||||
|
order: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
labels: range.value.map(p => p.date),
|
||||||
|
datasets: [cumulative, iskIn, iskOut],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const chartOptions = computed<ChartOptions<'bar' | 'line'>>(() => ({
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
interaction: {mode: 'index', intersect: false},
|
||||||
|
plugins: {
|
||||||
|
legend: {display: true},
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: ctx => `${ctx.dataset.label}: ${formatIsk(Math.abs(ctx.parsed.y ?? 0))}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
stacked: true,
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
position: 'left',
|
||||||
|
stacked: true,
|
||||||
|
ticks: {
|
||||||
|
callback: value => formatIsk(Math.abs(Number(value))),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="mt-4">
|
||||||
|
<div class="flex justify-center mb-4">
|
||||||
|
<div class="flex bg-slate-600 rounded-s-md p-1">
|
||||||
|
<button class="switch" :class="{active: mode === ProfitModes.CashFlow}" @click="mode = ProfitModes.CashFlow">Cash Flow</button>
|
||||||
|
</div>
|
||||||
|
<div class="switch flex bg-slate-600 rounded-e-md p-1">
|
||||||
|
<button class="switch" :class="{active: mode === ProfitModes.Margin}" @click="mode = ProfitModes.Margin">Margin</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end mb-4">
|
||||||
|
<span class="mr-2">Total profit:</span>
|
||||||
|
<IskLabel :amount="total" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p v-if="profits.length === 0" class="text-center text-gray-400 mt-8">
|
||||||
|
No trade profit recorded for this ledger
|
||||||
|
</p>
|
||||||
|
<template v-else>
|
||||||
|
<div class="h-96">
|
||||||
|
<Chart type="bar" :data="chartData" :options="chartOptions" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-3 mt-4">
|
||||||
|
<span class="text-sm w-24 text-gray-400">{{ profits[from]?.date }}</span>
|
||||||
|
<DualRangeSlider class="grow" :min="0" :max="maxIndex" v-model:from="from" v-model:to="to" />
|
||||||
|
<span class="text-sm w-24 text-right text-gray-400">{{ profits[to]?.date }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@reference "@/style.css";
|
||||||
|
|
||||||
|
button.switch {
|
||||||
|
@apply flex items-center px-4 rounded-md bg-slate-600;
|
||||||
|
&.active {
|
||||||
|
@apply bg-emerald-500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {Dropdown} from '@/components';
|
import {Dropdown} from '@/components';
|
||||||
import {AppraisalItemValue, AppraisalResultTable, appraise} from '@/market/appraisal';
|
import {AppraisalItemValue, AppraisalResultTable, appraise} from '@/market/appraisal';
|
||||||
|
import {MarketLocationInput, useMarketLocationStore} from '@/market/location';
|
||||||
import {ref} from 'vue';
|
import {ref} from 'vue';
|
||||||
|
|
||||||
const items = ref('');
|
const items = ref('');
|
||||||
const showInputs = ref(true);
|
const showInputs = ref(true);
|
||||||
|
|
||||||
|
const marketLocationStore = useMarketLocationStore();
|
||||||
const result = ref<AppraisalItemValue[]>([]);
|
const result = ref<AppraisalItemValue[]>([]);
|
||||||
|
|
||||||
const send = async () => result.value = await appraise(items.value);
|
const send = async () => result.value = await appraise(items.value, marketLocationStore.location.id);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -20,6 +22,12 @@ const send = async () => result.value = await appraise(items.value);
|
|||||||
<textarea class="mt-1" v-model="items" placeholder="Paste an EVE inventory listing" />
|
<textarea class="mt-1" v-model="items" placeholder="Paste an EVE inventory listing" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mx-1 mt-2">
|
||||||
|
<span>Location</span>
|
||||||
|
<div class="mt-1">
|
||||||
|
<MarketLocationInput v-model="marketLocationStore.location" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="grid my-2">
|
<div class="grid my-2">
|
||||||
<button class="justify-self-end" @click="send" :disabled="!items.trim()">Send</button>
|
<button class="justify-self-end" @click="send" :disabled="!items.trim()">Send</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref} from 'vue';
|
import {ref} from 'vue';
|
||||||
import {Dropdown} from '@/components';
|
import {Dropdown} from '@/components';
|
||||||
import {compareAppraisal, ComparedItem, CompareResultTable, useAppraisalStore} from '@/market/appraisal';
|
import {compareAppraisal, ComparedItem, CompareResultTable, getPrices} from '@/market/appraisal';
|
||||||
import {MarketLocation, MarketLocationInput} from '@/market/location';
|
import {MarketLocation, MarketLocationInput} from '@/market/location';
|
||||||
|
|
||||||
const store = useAppraisalStore();
|
|
||||||
|
|
||||||
const items = ref('');
|
const items = ref('');
|
||||||
const from = ref<MarketLocation>();
|
const from = ref<MarketLocation>();
|
||||||
const to = ref<MarketLocation>();
|
const to = ref<MarketLocation>();
|
||||||
@@ -19,7 +17,7 @@ const send = async () => {
|
|||||||
const selected = [from.value, to.value].filter((l): l is MarketLocation => l !== undefined);
|
const selected = [from.value, to.value].filter((l): l is MarketLocation => l !== undefined);
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
result.value = await compareAppraisal(items.value, selected.map(l => l.id), store.getPrices);
|
result.value = await compareAppraisal(items.value, selected.map(l => l.id), getPrices);
|
||||||
resultLocations.value = selected;
|
resultLocations.value = selected;
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ClipboardButton} from '@/components';
|
import {ClipboardButton} from '@/components';
|
||||||
import {getMarketType, MarketType, MarketTypeInput, useAppraisalStore, useMarketTaxStore} from "@/market";
|
import {getMarketType, getPrice, MarketType, MarketTypeInput, useMarketTaxStore} from "@/market";
|
||||||
import {AcquisitionResultTable, BuyModal} from '@/market/acquisition';
|
import {AcquisitionResultTable, BuyModal} from '@/market/acquisition';
|
||||||
|
import {MarketLocationInput, useMarketLocationStore} from '@/market/location';
|
||||||
import {ScanResultTable, toScanResult} from '@/market/scan';
|
import {ScanResultTable, toScanResult} from '@/market/scan';
|
||||||
import {acquisitionApi, marketApi} from "@/mammon";
|
import {acquisitionApi, marketApi} from "@/mammon";
|
||||||
import {ShoppingCartIcon} from '@heroicons/vue/24/outline';
|
import {ShoppingCartIcon} from '@heroicons/vue/24/outline';
|
||||||
@@ -18,10 +19,10 @@ const router = useRouter();
|
|||||||
const item = ref<MarketType>();
|
const item = ref<MarketType>();
|
||||||
const inputItem = ref<MarketType>();
|
const inputItem = ref<MarketType>();
|
||||||
|
|
||||||
const appraisalStore = useAppraisalStore();
|
|
||||||
const marketTaxStore = useMarketTaxStore();
|
const marketTaxStore = useMarketTaxStore();
|
||||||
|
const marketLocationStore = useMarketLocationStore();
|
||||||
const days = useStorage('market-scan-days', 365);
|
const days = useStorage('market-scan-days', 365);
|
||||||
const price = computedAsync(() => item.value ? appraisalStore.getPrice(item.value) : undefined);
|
const price = computedAsync(() => item.value ? getPrice(item.value, marketLocationStore.location.id) : undefined);
|
||||||
const result = computedAsync(async () => {
|
const result = computedAsync(async () => {
|
||||||
if (!item.value) {
|
if (!item.value) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -84,10 +85,11 @@ watch(useRoute(), async route => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="grid mb-2 mt-4">
|
<div class="grid mb-2 mt-4">
|
||||||
<div class="w-auto flex">
|
<div class="w-auto flex items-center">
|
||||||
<span>Item: </span>
|
<span>Item: </span>
|
||||||
<MarketTypeInput class="ms-2" v-model="inputItem" @submit="view"/>
|
<MarketTypeInput class="ms-2" v-model="inputItem" @submit="view"/>
|
||||||
<button class="justify-self-end ms-2" @click="view">View</button>
|
<button class="justify-self-end ms-2" @click="view">View</button>
|
||||||
|
<MarketLocationInput class="ms-auto" v-model="marketLocationStore.location" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="item">
|
<template v-if="item">
|
||||||
|
|||||||
@@ -4,46 +4,134 @@ import {useEventListener} from "@vueuse/core";
|
|||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import {ScriptEditor, useRuleBookStore} from "@/rules";
|
import {ScriptEditor, useRuleBookStore} from "@/rules";
|
||||||
import {PlusIcon, TrashIcon} from "@heroicons/vue/24/outline";
|
import {PlusIcon, TrashIcon} from "@heroicons/vue/24/outline";
|
||||||
|
import {Dropdown} from "@/components";
|
||||||
import {isMain, Ledger, LedgerSelect, systemLedger, useLedgersStore} from "@/ledger";
|
import {isMain, Ledger, LedgerSelect, systemLedger, useLedgersStore} from "@/ledger";
|
||||||
|
import {useCharactersStore} from "@/characters";
|
||||||
|
import {CorporationLabel, useCorporationsStore} from "@/corporations";
|
||||||
|
import {RuleScriptRequest} from "@/generated/mammon";
|
||||||
|
import {toast} from "@/toast";
|
||||||
|
import {confirm} from "@/confirm";
|
||||||
|
|
||||||
type Binding = { ref: string; ledger: Ledger };
|
type LedgerScopeEntry = { ref: string; ledger: Ledger };
|
||||||
|
type CharacterScopeEntry = { ref: string; characterId: number };
|
||||||
|
type CorporationScopeEntry = { ref: string; corporationId: number };
|
||||||
|
type WalletDivisionScopeEntry = { ref: string; corporationId: number; division: number };
|
||||||
|
|
||||||
|
interface ScriptDraft {
|
||||||
|
name: string;
|
||||||
|
script: string;
|
||||||
|
ledgers: LedgerScopeEntry[];
|
||||||
|
characters: CharacterScopeEntry[];
|
||||||
|
corporations: CorporationScopeEntry[];
|
||||||
|
walletDivisions: WalletDivisionScopeEntry[];
|
||||||
|
}
|
||||||
|
|
||||||
const ruleBookStore = useRuleBookStore();
|
const ruleBookStore = useRuleBookStore();
|
||||||
const ledgersStore = useLedgersStore();
|
const ledgersStore = useLedgersStore();
|
||||||
|
const charactersStore = useCharactersStore();
|
||||||
|
const corporationsStore = useCorporationsStore();
|
||||||
|
|
||||||
const ledgersToUse = computed(() => [systemLedger, ...ledgersStore.ledgers.filter(isMain)]);
|
const ledgersToUse = computed(() => [systemLedger, ...ledgersStore.ledgers.filter(isMain)]);
|
||||||
|
|
||||||
const bindings = ref<Binding[]>([]);
|
const scripts = ref<ScriptDraft[]>([]);
|
||||||
const script = ref<string>('');
|
const selectedIndex = ref(0);
|
||||||
|
const scopesExpanded = ref(true);
|
||||||
const ledgerRefs = computed<string[]>(() => bindings.value.map(b => b.ref));
|
const ledgersExpanded = ref(true);
|
||||||
|
const charactersExpanded = ref(true);
|
||||||
|
const corporationsExpanded = ref(true);
|
||||||
|
const walletDivisionsExpanded = ref(true);
|
||||||
|
const selected = computed<ScriptDraft | undefined>(() => scripts.value[selectedIndex.value]);
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
const ruleBook = ruleBookStore.ruleBook;
|
const ruleBook = ruleBookStore.ruleBook;
|
||||||
|
|
||||||
script.value = ruleBook?.script ?? '';
|
scripts.value = (ruleBook?.scripts ?? []).map(script => ({
|
||||||
bindings.value = Object.entries(ruleBook?.bindings ?? {})
|
name: script.name,
|
||||||
.map(([ref, id]) => ({ref, ledger: ledgersToUse.value.find(l => l.ledgerId === id) ?? systemLedger}));
|
script: script.script,
|
||||||
|
ledgers: Object.entries(script.scope.ledgers).map(([ref, id]) => ({ref, ledger: ledgersToUse.value.find(l => l.ledgerId === id) ?? systemLedger})),
|
||||||
|
characters: Object.entries(script.scope.characters).map(([ref, characterId]) => ({ref, characterId})),
|
||||||
|
corporations: Object.entries(script.scope.corporations).map(([ref, corporationId]) => ({ref, corporationId})),
|
||||||
|
walletDivisions: Object.entries(script.scope.walletDivisions).map(([ref, target]) => ({ref, corporationId: target.corporationId, division: target.division})),
|
||||||
|
}));
|
||||||
|
selectedIndex.value = 0;
|
||||||
log.info('Loaded rule book:', ruleBook);
|
log.info('Loaded rule book:', ruleBook);
|
||||||
});
|
});
|
||||||
|
|
||||||
const addBinding = () => {
|
const editorScope = computed(() => selected.value ? {
|
||||||
bindings.value = [...bindings.value, {ref: '', ledger: systemLedger}];
|
ledgers: selected.value.ledgers.map(entry => entry.ref),
|
||||||
};
|
characters: selected.value.characters.map(entry => entry.ref),
|
||||||
|
corporations: selected.value.corporations.map(entry => entry.ref),
|
||||||
|
walletDivisions: selected.value.walletDivisions.map(entry => entry.ref),
|
||||||
|
} : undefined);
|
||||||
|
|
||||||
const removeBinding = (index: number) => {
|
const scriptText = computed<string>({
|
||||||
bindings.value = bindings.value.toSpliced(index, 1);
|
get: () => selected.value?.script ?? '',
|
||||||
};
|
set: value => {
|
||||||
|
if (selected.value) {
|
||||||
const save = () => ruleBookStore.update({
|
selected.value.script = value;
|
||||||
bindings: Object.fromEntries(
|
}
|
||||||
bindings.value
|
},
|
||||||
.filter(b => b.ref)
|
|
||||||
.map(b => [b.ref, b.ledger.ledgerId])
|
|
||||||
),
|
|
||||||
script: script.value
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const addScript = () => {
|
||||||
|
scripts.value = [...scripts.value, {name: '', script: '', ledgers: [], characters: [], corporations: [], walletDivisions: []}];
|
||||||
|
selectedIndex.value = scripts.value.length - 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeScript = async (index: number) => {
|
||||||
|
const script = scripts.value[index];
|
||||||
|
|
||||||
|
if (script?.script.trim() && !await confirm({message: `Delete script "${script.name || '(unnamed)'}"? It still has content.`, danger: true})) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scripts.value = scripts.value.toSpliced(index, 1);
|
||||||
|
if (selectedIndex.value >= scripts.value.length) {
|
||||||
|
selectedIndex.value = Math.max(0, scripts.value.length - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const addLedgerScope = () => selected.value?.ledgers.push({ref: '', ledger: systemLedger});
|
||||||
|
const removeLedgerScope = (index: number) => { if (selected.value) selected.value.ledgers = selected.value.ledgers.toSpliced(index, 1); };
|
||||||
|
|
||||||
|
const addCharacterScope = () => selected.value?.characters.push({ref: '', characterId: charactersStore.characters[0]?.characterId ?? 0});
|
||||||
|
const removeCharacterScope = (index: number) => { if (selected.value) selected.value.characters = selected.value.characters.toSpliced(index, 1); };
|
||||||
|
|
||||||
|
const addCorporationScope = () => selected.value?.corporations.push({ref: '', corporationId: 0});
|
||||||
|
const removeCorporationScope = (index: number) => { if (selected.value) selected.value.corporations = selected.value.corporations.toSpliced(index, 1); };
|
||||||
|
|
||||||
|
const addWalletDivisionScope = () => selected.value?.walletDivisions.push({ref: '', corporationId: 0, division: 1});
|
||||||
|
const removeWalletDivisionScope = (index: number) => { if (selected.value) selected.value.walletDivisions = selected.value.walletDivisions.toSpliced(index, 1); };
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
const corporationIds = new Set([
|
||||||
|
...(selected.value?.corporations.map(entry => entry.corporationId) ?? []),
|
||||||
|
...(selected.value?.walletDivisions.map(entry => entry.corporationId) ?? []),
|
||||||
|
]);
|
||||||
|
|
||||||
|
for (const corporationId of corporationIds) {
|
||||||
|
if (corporationId) {
|
||||||
|
corporationsStore.findById(corporationId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const save = () => ruleBookStore.update(
|
||||||
|
scripts.value
|
||||||
|
.filter(s => s.name)
|
||||||
|
.map((s): RuleScriptRequest => ({
|
||||||
|
name: s.name,
|
||||||
|
script: s.script,
|
||||||
|
scope: {
|
||||||
|
ledgers: Object.fromEntries(s.ledgers.filter(entry => entry.ref).map(entry => [entry.ref, entry.ledger.ledgerId])),
|
||||||
|
characters: Object.fromEntries(s.characters.filter(entry => entry.ref).map(entry => [entry.ref, entry.characterId])),
|
||||||
|
corporations: Object.fromEntries(s.corporations.filter(entry => entry.ref).map(entry => [entry.ref, entry.corporationId])),
|
||||||
|
walletDivisions: Object.fromEntries(s.walletDivisions.filter(entry => entry.ref).map(entry => [entry.ref, {corporationId: entry.corporationId, division: entry.division}])),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
.then(() => toast.success('Rule book saved'));
|
||||||
|
|
||||||
useEventListener(window, 'keydown', (event: KeyboardEvent) => {
|
useEventListener(window, 'keydown', (event: KeyboardEvent) => {
|
||||||
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 's') {
|
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 's') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -53,31 +141,104 @@ useEventListener(window, 'keydown', (event: KeyboardEvent) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col mb-2 mt-4 h-[calc(100vh-4.5rem)]">
|
<div class="flex mb-2 mt-4 h-[calc(100vh-1.5rem)]">
|
||||||
<div class="flex flex-col grow min-h-0">
|
<div class="flex flex-col me-4 w-48 shrink-0">
|
||||||
<div class="border-b-1">
|
<div class="grow overflow-y-auto">
|
||||||
Ledger Bindings:
|
<div v-for="(script, index) in scripts" :key="index"
|
||||||
<div class="flex flex-wrap items-center mt-2">
|
class="flex items-center mb-1 px-1 py-0.5 border-l-4 cursor-pointer"
|
||||||
<div class="flex items-center mb-2 me-2" v-for="(binding, index) in bindings" :key="index">
|
:class="index === selectedIndex ? 'border-emerald-500' : 'border-transparent'"
|
||||||
<input class="me-1" type="text" v-model="binding.ref" />
|
@click="selectedIndex = index">
|
||||||
<span class="me-1">:</span>
|
<span class="grow truncate">{{ script.name || '(unnamed)' }}</span>
|
||||||
<LedgerSelect class="me-1" :ledgers="ledgersToUse" v-model="binding.ledger" />
|
<button class="btn-icon text-amber-700 hover:text-amber-600" @click.stop="removeScript(index)"><TrashIcon /></button>
|
||||||
<button class="btn-icon text-amber-700 hover:text-amber-600" @click="removeBinding(index)"><TrashIcon /></button>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center mb-2">
|
|
||||||
<button class="btn-icon" @click="addBinding"><PlusIcon /></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<button class="btn-icon flex items-center" @click="addScript"><PlusIcon /> Add script</button>
|
||||||
<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>
|
</div>
|
||||||
<div class="mt-2 justify-end flex">
|
|
||||||
<div>
|
<div v-if="selected" class="flex flex-col grow min-h-0">
|
||||||
|
<div class="border-b-1 mb-2 pb-2">
|
||||||
|
Name: <input class="me-1" type="text" v-model="selected.name" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Dropdown inline :auto-close="false" v-model:open="scopesExpanded" class="mb-2">
|
||||||
|
<template #button>Scopes</template>
|
||||||
|
<Dropdown inline :auto-close="false" v-model:open="ledgersExpanded" class="ms-4 mt-2">
|
||||||
|
<template #button>Ledgers</template>
|
||||||
|
<div class="flex flex-wrap items-center mt-2">
|
||||||
|
<div class="flex items-center mb-2 me-2" v-for="(entry, index) in selected.ledgers" :key="index">
|
||||||
|
<input class="me-1" type="text" v-model="entry.ref" />
|
||||||
|
<span class="me-1">:</span>
|
||||||
|
<LedgerSelect class="me-1" :ledgers="ledgersToUse" v-model="entry.ledger" />
|
||||||
|
<button class="btn-icon text-amber-700 hover:text-amber-600" @click="removeLedgerScope(index)"><TrashIcon /></button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center mb-2">
|
||||||
|
<button class="btn-icon" @click="addLedgerScope"><PlusIcon /></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
|
||||||
|
<Dropdown inline :auto-close="false" v-model:open="charactersExpanded" class="ms-4 mt-2">
|
||||||
|
<template #button>Characters</template>
|
||||||
|
<div class="flex flex-wrap items-center mt-2">
|
||||||
|
<div class="flex items-center mb-2 me-2" v-for="(entry, index) in selected.characters" :key="index">
|
||||||
|
<input class="me-1" type="text" v-model="entry.ref" />
|
||||||
|
<span class="me-1">:</span>
|
||||||
|
<select class="me-1" v-model="entry.characterId">
|
||||||
|
<option v-for="character in charactersStore.characters" :key="character.characterId" :value="character.characterId">{{ character.name }}</option>
|
||||||
|
</select>
|
||||||
|
<button class="btn-icon text-amber-700 hover:text-amber-600" @click="removeCharacterScope(index)"><TrashIcon /></button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center mb-2">
|
||||||
|
<button class="btn-icon" @click="addCharacterScope"><PlusIcon /></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
|
||||||
|
<Dropdown inline :auto-close="false" v-model:open="corporationsExpanded" class="ms-4 mt-2">
|
||||||
|
<template #button>Corporations</template>
|
||||||
|
<div class="flex flex-wrap items-center mt-2">
|
||||||
|
<div class="flex items-center mb-2 me-2" v-for="(entry, index) in selected.corporations" :key="index">
|
||||||
|
<input class="me-1" type="text" v-model="entry.ref" />
|
||||||
|
<span class="me-1">:</span>
|
||||||
|
<input class="me-1 w-32" type="number" v-model.number="entry.corporationId" placeholder="Corporation ID" />
|
||||||
|
<CorporationLabel class="me-1" :corporation-id="entry.corporationId" :corporation="corporationsStore.corporations[entry.corporationId]" :size="16" v-if="entry.corporationId" />
|
||||||
|
<button class="btn-icon text-amber-700 hover:text-amber-600" @click="removeCorporationScope(index)"><TrashIcon /></button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center mb-2">
|
||||||
|
<button class="btn-icon" @click="addCorporationScope"><PlusIcon /></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
|
||||||
|
<Dropdown inline :auto-close="false" v-model:open="walletDivisionsExpanded" class="ms-4 mt-2 mb-2">
|
||||||
|
<template #button>Wallet Divisions</template>
|
||||||
|
<div class="flex flex-wrap items-center mt-2">
|
||||||
|
<div class="flex items-center mb-2 me-2" v-for="(entry, index) in selected.walletDivisions" :key="index">
|
||||||
|
<input class="me-1" type="text" v-model="entry.ref" />
|
||||||
|
<span class="me-1">:</span>
|
||||||
|
<input class="me-1 w-32" type="number" v-model.number="entry.corporationId" placeholder="Corporation ID" />
|
||||||
|
<input class="me-1 w-16" type="number" min="1" max="7" v-model.number="entry.division" placeholder="Division" />
|
||||||
|
<CorporationLabel class="me-1" :corporation-id="entry.corporationId" :corporation="corporationsStore.corporations[entry.corporationId]" :division="entry.division" :size="16" v-if="entry.corporationId" />
|
||||||
|
<button class="btn-icon text-amber-700 hover:text-amber-600" @click="removeWalletDivisionScope(index)"><TrashIcon /></button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center mb-2">
|
||||||
|
<button class="btn-icon" @click="addWalletDivisionScope"><PlusIcon /></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
</Dropdown>
|
||||||
|
|
||||||
|
<div class="flex flex-col grow min-h-0 border-b-1">
|
||||||
|
Script:
|
||||||
|
<ScriptEditor class="mt-2 mb-2" v-model="scriptText" :scope="editorScope" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-2 justify-end flex">
|
||||||
<button @click="save">Save</button>
|
<button @click="save">Save</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else class="flex grow items-center justify-center text-neutral-500">
|
||||||
|
No scripts yet
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export const routeNames = {
|
|||||||
viewLedgerBalance: 'view-ledger-balance',
|
viewLedgerBalance: 'view-ledger-balance',
|
||||||
listLedgerTransactions: 'list-ledger-transactions',
|
listLedgerTransactions: 'list-ledger-transactions',
|
||||||
listLedgerAcquisitions: 'list-ledger-acquisitions',
|
listLedgerAcquisitions: 'list-ledger-acquisitions',
|
||||||
|
viewLedgerStatistics: 'view-ledger-statistics',
|
||||||
editRuleBook: 'edit-rule-book',
|
editRuleBook: 'edit-rule-book',
|
||||||
marketTypes: 'market-types',
|
marketTypes: 'market-types',
|
||||||
appraise: 'appraise',
|
appraise: 'appraise',
|
||||||
@@ -31,6 +32,7 @@ export const routes: RouteRecordRaw[] = [
|
|||||||
{path: 'balance', name: routeNames.viewLedgerBalance, component: () => import('@/pages/ledger/ViewLedgerBalance.vue')},
|
{path: 'balance', name: routeNames.viewLedgerBalance, component: () => import('@/pages/ledger/ViewLedgerBalance.vue')},
|
||||||
{path: 'transactions', name: routeNames.listLedgerTransactions, component: () => import('@/pages/ledger/ListLedgerTransactions.vue')},
|
{path: 'transactions', name: routeNames.listLedgerTransactions, component: () => import('@/pages/ledger/ListLedgerTransactions.vue')},
|
||||||
{path: 'acquisitions', name: routeNames.listLedgerAcquisitions, component: () => import('@/pages/ledger/ViewLedgerAcquisitions.vue')},
|
{path: 'acquisitions', name: routeNames.listLedgerAcquisitions, component: () => import('@/pages/ledger/ViewLedgerAcquisitions.vue')},
|
||||||
|
{path: 'statistics', name: routeNames.viewLedgerStatistics, component: () => import('@/pages/ledger/ViewLedgerStatistics.vue')},
|
||||||
]},
|
]},
|
||||||
]},
|
]},
|
||||||
|
|
||||||
|
|||||||
+27
-13
@@ -22,27 +22,41 @@ const loadScriptDefinitions = async () => {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const definitions = await fetchScriptDefinitions();
|
const definitions = await fetchScriptDefinitions();
|
||||||
monaco.typescript.javascriptDefaults.addExtraLib(definitions, 'ts:rule-runner.d.ts');
|
monaco.typescript.javascriptDefaults.addExtraLib(definitions, 'file:///node_modules/@eveal/runtime/index.d.ts');
|
||||||
extraLibLoaded = true;
|
extraLibLoaded = true;
|
||||||
} catch {
|
} catch {
|
||||||
// type definitions are optional — the editor still works without autocomplete
|
// type definitions are optional — the editor still works without autocomplete
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const props = defineProps<{ ledgerRefs?: string[] }>();
|
export interface ScriptEditorScope {
|
||||||
|
ledgers?: string[];
|
||||||
|
characters?: string[];
|
||||||
|
corporations?: string[];
|
||||||
|
walletDivisions?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
let ledgersLib: monaco.IDisposable | undefined;
|
const props = defineProps<{ scope?: ScriptEditorScope }>();
|
||||||
|
|
||||||
const updateLedgerRefs = (refs: readonly string[]) => {
|
let scopeLib: monaco.IDisposable | undefined;
|
||||||
ledgersLib?.dispose();
|
|
||||||
|
const declareInterface = (name: string, type: string, refs: readonly string[]) => {
|
||||||
const members = refs
|
const members = refs
|
||||||
.filter(ref => ref && ref !== 'system')
|
.filter(ref => ref && ref !== 'system')
|
||||||
.map(ref => ` readonly ${JSON.stringify(ref)}: Ledger;`)
|
.map(ref => ` readonly ${JSON.stringify(ref)}: ${type};`)
|
||||||
.join('\n');
|
.join('\n');
|
||||||
ledgersLib = monaco.typescript.javascriptDefaults.addExtraLib(
|
return ` interface ${name} {\n${members}\n }\n`;
|
||||||
`declare interface Ledgers {\n${members}\n}\n`,
|
};
|
||||||
'ts:rule-runner.ledgers.d.ts'
|
|
||||||
);
|
const updateScope = (scope: ScriptEditorScope) => {
|
||||||
|
scopeLib?.dispose();
|
||||||
|
const source = `declare module '@eveal/runtime' {\n${[
|
||||||
|
declareInterface('Ledgers', 'Ledger', scope.ledgers ?? []),
|
||||||
|
declareInterface('Characters', 'Character', scope.characters ?? []),
|
||||||
|
declareInterface('Corporations', 'Corporation', scope.corporations ?? []),
|
||||||
|
declareInterface('WalletDivisions', 'WalletDivision', scope.walletDivisions ?? []),
|
||||||
|
].join('\n')}}\n`;
|
||||||
|
scopeLib = monaco.typescript.javascriptDefaults.addExtraLib(source, 'ts:rule-runner.scope.d.ts');
|
||||||
};
|
};
|
||||||
|
|
||||||
const model = defineModel<string>({default: ''});
|
const model = defineModel<string>({default: ''});
|
||||||
@@ -51,7 +65,7 @@ let editor: monaco.editor.IStandaloneCodeEditor | undefined;
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await loadScriptDefinitions();
|
await loadScriptDefinitions();
|
||||||
updateLedgerRefs(props.ledgerRefs ?? []);
|
updateScope(props.scope ?? {});
|
||||||
|
|
||||||
if (!container.value) {
|
if (!container.value) {
|
||||||
return;
|
return;
|
||||||
@@ -83,11 +97,11 @@ watch(model, value => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(() => props.ledgerRefs, refs => updateLedgerRefs(refs ?? []), {deep: true});
|
watch(() => props.scope, scope => updateScope(scope ?? {}), {deep: true});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
editor?.dispose();
|
editor?.dispose();
|
||||||
ledgersLib?.dispose();
|
scopeLib?.dispose();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
+16
-3
@@ -1,10 +1,19 @@
|
|||||||
import {ruleBookApi, ruleScriptApi} from "@/mammon";
|
import {ruleBookApi, ruleScriptApi} from "@/mammon";
|
||||||
import {RuleBookResponse, UpdateRuleBookRequest} from "@/generated/mammon";
|
import {RuleBookResponse, RuleScopeRequest, RuleScriptRequest, RuleScriptResponse, UpdateRuleBookRequest} from "@/generated/mammon";
|
||||||
import {isAxiosError} from "axios";
|
import {isAxiosError} from "axios";
|
||||||
import {defineStore} from "pinia";
|
import {defineStore} from "pinia";
|
||||||
import {ref} from "vue";
|
import {ref} from "vue";
|
||||||
|
|
||||||
export type RuleBook = RuleBookResponse;
|
export type RuleBook = RuleBookResponse;
|
||||||
|
export type RuleScript = RuleScriptResponse;
|
||||||
|
export type RuleScope = RuleScriptResponse['scope'];
|
||||||
|
|
||||||
|
export const emptyScope = (): RuleScopeRequest => ({
|
||||||
|
ledgers: {},
|
||||||
|
characters: {},
|
||||||
|
corporations: {},
|
||||||
|
walletDivisions: {},
|
||||||
|
});
|
||||||
|
|
||||||
export const useRuleBookStore = defineStore('rule-book', () => {
|
export const useRuleBookStore = defineStore('rule-book', () => {
|
||||||
const ruleBook = ref<RuleBook | null>(null);
|
const ruleBook = ref<RuleBook | null>(null);
|
||||||
@@ -19,7 +28,7 @@ export const useRuleBookStore = defineStore('rule-book', () => {
|
|||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
|
|
||||||
const update = (request: UpdateRuleBookRequest) => ruleBookApi.updateRuleBook(request)
|
const update = (scripts: RuleScriptRequest[]) => ruleBookApi.updateRuleBook({scripts} satisfies UpdateRuleBookRequest)
|
||||||
.then(response => ruleBook.value = response.data);
|
.then(response => ruleBook.value = response.data);
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
@@ -28,4 +37,8 @@ export const useRuleBookStore = defineStore('rule-book', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const fetchScriptDefinitions = (): Promise<string> =>
|
export const fetchScriptDefinitions = (): Promise<string> =>
|
||||||
ruleScriptApi.getScriptDefinitions({responseType: 'text'}).then(response => response.data);
|
ruleScriptApi.listScriptDefinitions()
|
||||||
|
.then(response => Promise.all(
|
||||||
|
response.data.map(name => ruleScriptApi.getScriptDefinition(name, {responseType: 'text'}).then(r => r.data))
|
||||||
|
))
|
||||||
|
.then(definitions => definitions.join('\n'));
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import {
|
||||||
|
CheckCircleIcon,
|
||||||
|
InformationCircleIcon,
|
||||||
|
XCircleIcon,
|
||||||
|
XMarkIcon,
|
||||||
|
} from '@heroicons/vue/24/outline';
|
||||||
|
import type {ToastType} from './useToast';
|
||||||
|
import {useToastStore} from './useToast';
|
||||||
|
|
||||||
|
const toastStore = useToastStore();
|
||||||
|
|
||||||
|
const icons = {
|
||||||
|
success: CheckCircleIcon,
|
||||||
|
error: XCircleIcon,
|
||||||
|
info: InformationCircleIcon,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const accent = (type: ToastType) => `accent-${type}`;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="toast-container">
|
||||||
|
<TransitionGroup name="toast">
|
||||||
|
<div v-for="toast in toastStore.toasts" :key="toast.id" class="toast" :class="accent(toast.type)">
|
||||||
|
<component :is="icons[toast.type]" class="icon" />
|
||||||
|
<div class="body">
|
||||||
|
<span v-if="toast.title" class="title">{{ toast.title }}</span>
|
||||||
|
<span class="message">{{ toast.message }}</span>
|
||||||
|
</div>
|
||||||
|
<button class="btn-icon close" @click="toastStore.dismiss(toast.id)">
|
||||||
|
<XMarkIcon />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</TransitionGroup>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@reference "@/style.css";
|
||||||
|
|
||||||
|
div.toast-container {
|
||||||
|
@apply fixed top-4 right-4 z-50 flex flex-col gap-2 w-80 max-w-[calc(100vw-2rem)];
|
||||||
|
}
|
||||||
|
|
||||||
|
div.toast {
|
||||||
|
@apply flex items-start gap-2 p-3 rounded bg-slate-700 border-l-4 shadow-lg;
|
||||||
|
|
||||||
|
&.accent-success {
|
||||||
|
@apply border-emerald-500;
|
||||||
|
> .icon { @apply text-emerald-500; }
|
||||||
|
}
|
||||||
|
&.accent-error {
|
||||||
|
@apply border-amber-700;
|
||||||
|
> .icon { @apply text-amber-700; }
|
||||||
|
}
|
||||||
|
&.accent-info {
|
||||||
|
@apply border-sky-600;
|
||||||
|
> .icon { @apply text-sky-600; }
|
||||||
|
}
|
||||||
|
|
||||||
|
> .icon {
|
||||||
|
@apply w-6 h-6 shrink-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .body {
|
||||||
|
@apply flex flex-col grow min-w-0;
|
||||||
|
|
||||||
|
> .title {
|
||||||
|
@apply font-semibold;
|
||||||
|
}
|
||||||
|
> .message {
|
||||||
|
@apply break-words;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .close {
|
||||||
|
@apply shrink-0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toast-enter-active,
|
||||||
|
.toast-leave-active,
|
||||||
|
.toast-move {
|
||||||
|
@apply transition-all duration-300;
|
||||||
|
}
|
||||||
|
.toast-enter-from {
|
||||||
|
@apply opacity-0 translate-x-8;
|
||||||
|
}
|
||||||
|
.toast-leave-to {
|
||||||
|
@apply opacity-0 -translate-y-8;
|
||||||
|
}
|
||||||
|
.toast-leave-active {
|
||||||
|
@apply absolute w-full;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export { default as ToastContainer } from './ToastContainer.vue';
|
||||||
|
export { toast, useToastStore } from './useToast';
|
||||||
|
export type { ToastOptions, ToastType } from './useToast';
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import {defineStore} from "pinia";
|
||||||
|
import {ref} from "vue";
|
||||||
|
|
||||||
|
export type ToastType = 'success' | 'error' | 'info';
|
||||||
|
|
||||||
|
export interface ToastOptions {
|
||||||
|
message: string;
|
||||||
|
title?: string;
|
||||||
|
type?: ToastType;
|
||||||
|
duration?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Toast {
|
||||||
|
id: number;
|
||||||
|
message: string;
|
||||||
|
title?: string;
|
||||||
|
type: ToastType;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_DURATION = 5000;
|
||||||
|
|
||||||
|
export const useToastStore = defineStore('toast', () => {
|
||||||
|
const toasts = ref<Toast[]>([]);
|
||||||
|
let nextId = 0;
|
||||||
|
|
||||||
|
const dismiss = (id: number) => {
|
||||||
|
toasts.value = toasts.value.filter(toast => toast.id !== id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const push = (opts: ToastOptions | string): number => {
|
||||||
|
const options = typeof opts === "string" ? {message: opts} : opts;
|
||||||
|
const id = nextId++;
|
||||||
|
toasts.value.push({
|
||||||
|
id,
|
||||||
|
message: options.message,
|
||||||
|
title: options.title,
|
||||||
|
type: options.type ?? 'info',
|
||||||
|
});
|
||||||
|
const duration = options.duration ?? DEFAULT_DURATION;
|
||||||
|
if (duration > 0) {
|
||||||
|
setTimeout(() => dismiss(id), duration);
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {toasts, push, dismiss};
|
||||||
|
});
|
||||||
|
|
||||||
|
interface ToastHelper {
|
||||||
|
(opts: ToastOptions | string): number;
|
||||||
|
success: (message: string) => number;
|
||||||
|
error: (message: string) => number;
|
||||||
|
info: (message: string) => number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const toast: ToastHelper = Object.assign(
|
||||||
|
(opts: ToastOptions | string): number => useToastStore().push(opts),
|
||||||
|
{
|
||||||
|
success: (message: string): number => useToastStore().push({message, type: 'success'}),
|
||||||
|
error: (message: string): number => useToastStore().push({message, type: 'error'}),
|
||||||
|
info: (message: string): number => useToastStore().push({message, type: 'info'}),
|
||||||
|
},
|
||||||
|
);
|
||||||
+4
-1
@@ -1 +1,4 @@
|
|||||||
export const copyToClipboard = (s: string) => navigator.clipboard.writeText(s);
|
import {toast} from '@/toast';
|
||||||
|
|
||||||
|
export const copyToClipboard = (s: string) => navigator.clipboard.writeText(s)
|
||||||
|
.then(() => toast({message: 'Copied', type: 'info', duration: 500}));
|
||||||
|
|||||||
Reference in New Issue
Block a user