Compare commits
2 commits
f4a37d6851
...
7f055c98be
Author | SHA1 | Date | |
---|---|---|---|
7f055c98be | |||
70e8586f8c |
58 changed files with 3910 additions and 910 deletions
39
Cargo.lock
generated
39
Cargo.lock
generated
|
@ -1776,6 +1776,44 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-embed"
|
||||||
|
version = "6.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b68543d5527e158213414a92832d2aab11a84d2571a5eb021ebe22c43aab066"
|
||||||
|
dependencies = [
|
||||||
|
"hex",
|
||||||
|
"mime_guess",
|
||||||
|
"poem",
|
||||||
|
"rust-embed-impl",
|
||||||
|
"rust-embed-utils",
|
||||||
|
"tokio",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-embed-impl"
|
||||||
|
version = "6.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4d4e0f0ced47ded9a68374ac145edd65a6c1fa13a96447b873660b2a568a0fd7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rust-embed-utils",
|
||||||
|
"syn",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-embed-utils"
|
||||||
|
version = "7.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "512b0ab6853f7e14e3c8754acb43d6f748bb9ced66aa5915a6553ac8213f7731"
|
||||||
|
dependencies = [
|
||||||
|
"sha2",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
@ -2051,6 +2089,7 @@ dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
"rmp-serde",
|
"rmp-serde",
|
||||||
"rstest",
|
"rstest",
|
||||||
|
"rust-embed",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
|
|
@ -7,6 +7,7 @@ license = "MIT"
|
||||||
description = "Static site management system"
|
description = "Static site management system"
|
||||||
|
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
default-run = "talon"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
poem = "1.3.55"
|
poem = "1.3.55"
|
||||||
|
@ -51,6 +52,7 @@ async-compression = { version = "0.3.15", features = [
|
||||||
clap = { version = "4.1.8", features = ["derive"] }
|
clap = { version = "4.1.8", features = ["derive"] }
|
||||||
shadow-rs = "0.21.0"
|
shadow-rs = "0.21.0"
|
||||||
walkdir = "2.3.2"
|
walkdir = "2.3.2"
|
||||||
|
rust-embed = { version = "6.6.1", features = ["poem-ex"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rstest = "0.16.0"
|
rstest = "0.16.0"
|
||||||
|
|
28
Justfile
Normal file
28
Justfile
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
ok: lint test
|
||||||
|
|
||||||
|
lint:
|
||||||
|
cargo fmt --all
|
||||||
|
cargo clippy --all --all-features -- -D warnings
|
||||||
|
|
||||||
|
test:
|
||||||
|
cargo test --workspace
|
||||||
|
|
||||||
|
# Run the Talon server
|
||||||
|
run:
|
||||||
|
cargo run -- run -d tmp
|
||||||
|
|
||||||
|
# Generate the openapi.json documentation
|
||||||
|
oai-doc:
|
||||||
|
cargo run --bin openapi
|
||||||
|
|
||||||
|
# Generate the JS API client
|
||||||
|
oai-client:
|
||||||
|
openapi-generator-cli generate -i openapi.json -g typescript-fetch -o ui/talon-client -p "npmName=talon-client"
|
||||||
|
|
||||||
|
# Start the dev server for the sidebar menu
|
||||||
|
menu-dev:
|
||||||
|
cd ui/menu && npm run dev
|
||||||
|
|
||||||
|
# Build the sidebar menu -> ui/menu/dist/talon.js
|
||||||
|
menu-build:
|
||||||
|
cd ui/menu && npm run build
|
836
openapi.json
Normal file
836
openapi.json
Normal file
|
@ -0,0 +1,836 @@
|
||||||
|
{
|
||||||
|
"openapi": "3.0.0",
|
||||||
|
"info": {
|
||||||
|
"title": "Talon",
|
||||||
|
"description": "API for the Talon static site management system",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"license": {
|
||||||
|
"name": "MIT License"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"servers": [],
|
||||||
|
"tags": [],
|
||||||
|
"paths": {
|
||||||
|
"/website/{subdomain}": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Get a website",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "subdomain",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/json; charset=utf-8": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Website"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"summary": "Create a new website",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "subdomain",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json; charset=utf-8": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/WebsiteNew"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuthorization": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"summary": "Update website",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "subdomain",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json; charset=utf-8": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/WebsiteUpdate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuthorization": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"summary": "Delete website",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "subdomain",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuthorization": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/websites": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Get all publicly listed websites",
|
||||||
|
"description": "Returns all publicly listed websites (visibility != `hidden`)",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "visibility",
|
||||||
|
"schema": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Visibility"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "hidden"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"description": "Mimimum visibility of the websites",
|
||||||
|
"required": false,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/json; charset=utf-8": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Website"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/websitesAll": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Get all websites",
|
||||||
|
"description": "Returns all websites from Talon's database (including hidden ones, if the current user\nhas access to them). This endpoint requires authentication (use the `/websites` endpoint\nfor unauthenticated users).",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "visibility",
|
||||||
|
"schema": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Visibility"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "hidden"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"description": "Mimimum visibility of the websites",
|
||||||
|
"required": false,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/json; charset=utf-8": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Website"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuthorization": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/website/{subdomain}/versions": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Get website versions",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "subdomain",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/json; charset=utf-8": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/website/{subdomain}/version/{version}": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Get version",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "subdomain",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "version",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint32"
|
||||||
|
},
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/json; charset=utf-8": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"summary": "Delete version",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "subdomain",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "version",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint32"
|
||||||
|
},
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuthorization": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/website/{subdomain}/version/{version}/files": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Get version files",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "subdomain",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "version",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint32"
|
||||||
|
},
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/json; charset=utf-8": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/VersionFile"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/website/{subdomain}/upload": {
|
||||||
|
"post": {
|
||||||
|
"summary": "Upload a new version",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "subdomain",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fallback",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"description": "Fallback page\n\nThe fallback page gets returned when the requested page does not exist",
|
||||||
|
"required": false,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spa",
|
||||||
|
"schema": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"description": "SPA mode (return fallback page with OK status)",
|
||||||
|
"required": false,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "version_data",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"description": "Associated version data\n\nThis is an arbitrary string map that can hold build information and other stuff\nand will be displayed in the site info dialog.",
|
||||||
|
"required": false,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/octet-stream": {
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "binary"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuthorization": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/file/{hash}": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Retrieve a file",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "hash",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"explode": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "File content",
|
||||||
|
"content": {
|
||||||
|
"application/octet-stream": {
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "binary"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"etag": {
|
||||||
|
"description": "File hash",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"last-modified": {
|
||||||
|
"description": "Date when the file was last modified",
|
||||||
|
"required": true,
|
||||||
|
"deprecated": false,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/info": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Get information about your server",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/json; charset=utf-8": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Info"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"schemas": {
|
||||||
|
"Info": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Server information",
|
||||||
|
"required": [
|
||||||
|
"stats",
|
||||||
|
"version",
|
||||||
|
"uptime"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"stats": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Stats"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Stats about your instance"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/VersionInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Version information"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"uptime": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"description": "Current uptime of the server in seconds"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SourceIcon": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"link",
|
||||||
|
"git",
|
||||||
|
"github",
|
||||||
|
"gitlab",
|
||||||
|
"gitea",
|
||||||
|
"bitbucket"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Stats": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Stats about your Talon instance",
|
||||||
|
"required": [
|
||||||
|
"n_websites",
|
||||||
|
"n_files",
|
||||||
|
"storage_used"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"n_websites": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"description": "Number of websites"
|
||||||
|
},
|
||||||
|
"n_files": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"description": "Number of unique files"
|
||||||
|
},
|
||||||
|
"storage_used": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint64",
|
||||||
|
"description": "Amount of used storage space (in bytes)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Version": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Website version",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"created_at",
|
||||||
|
"data"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint32",
|
||||||
|
"description": "Version ID"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "Version creation date"
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Associated version data\n\nThis is an arbitrary string map that can hold build information and other stuff\nand will be displayed in the site info dialog.",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"VersionFile": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Website file",
|
||||||
|
"required": [
|
||||||
|
"path",
|
||||||
|
"hash"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "File path"
|
||||||
|
},
|
||||||
|
"hash": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "File hash"
|
||||||
|
},
|
||||||
|
"mime": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "MIME file type"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"VersionInfo": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Information about a Talon version",
|
||||||
|
"required": [
|
||||||
|
"version",
|
||||||
|
"commit",
|
||||||
|
"commit_date",
|
||||||
|
"rust_version",
|
||||||
|
"build_target",
|
||||||
|
"build_mode"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"version": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Talon version"
|
||||||
|
},
|
||||||
|
"commit": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Commit hash"
|
||||||
|
},
|
||||||
|
"commit_date": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "Commit date"
|
||||||
|
},
|
||||||
|
"rust_version": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Rust version"
|
||||||
|
},
|
||||||
|
"build_target": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Build target (OS and architecture)"
|
||||||
|
},
|
||||||
|
"build_mode": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Rust build mode (`debug` / `release`)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Visibility": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"featured",
|
||||||
|
"searchable",
|
||||||
|
"hidden"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Website": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Website",
|
||||||
|
"required": [
|
||||||
|
"subdomain",
|
||||||
|
"name",
|
||||||
|
"created_at",
|
||||||
|
"visibility"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"subdomain": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Website subdomain"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Website name"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "Website creation date"
|
||||||
|
},
|
||||||
|
"latest_version": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint32",
|
||||||
|
"description": "Latest version ID"
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Color of the page icon\n\nFormat: `#7935df`"
|
||||||
|
},
|
||||||
|
"visibility": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Visibility"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Visibility of the page in the sidebar menu"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"source_url": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Link to the source of the page"
|
||||||
|
},
|
||||||
|
"source_icon": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/SourceIcon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Icon for the source link"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"WebsiteNew": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Create a new website",
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Website name"
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Color of the page icon"
|
||||||
|
},
|
||||||
|
"visibility": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Visibility"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Visibility of the page in the sidebar menu",
|
||||||
|
"default": "hidden"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"source_url": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Link to the source of the page"
|
||||||
|
},
|
||||||
|
"source_icon": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/SourceIcon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Icon for the source link"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"WebsiteUpdate": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Update a website with the contained values\n\nValues set to `None` remain unchanged.",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Website name"
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Color of the page icon"
|
||||||
|
},
|
||||||
|
"visibility": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Visibility"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Visibility of the page in the sidebar menu"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"source_url": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Link to the source of the page"
|
||||||
|
},
|
||||||
|
"source_icon": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/SourceIcon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Icon for the source link"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"securitySchemes": {
|
||||||
|
"ApiKeyAuthorization": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "X-API-Key",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
openapitools.json
Normal file
7
openapitools.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
|
||||||
|
"spaces": 2,
|
||||||
|
"generator-cli": {
|
||||||
|
"version": "6.4.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ use poem_openapi::{
|
||||||
auth::ApiKey,
|
auth::ApiKey,
|
||||||
param::{Path, Query},
|
param::{Path, Query},
|
||||||
payload::{Binary, Html, Json, Response},
|
payload::{Binary, Html, Json, Response},
|
||||||
OpenApi, SecurityScheme,
|
LicenseObject, OpenApi, OpenApiService, SecurityScheme,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -388,3 +388,9 @@ impl TalonApi {
|
||||||
Ok(Json(talon.info()?))
|
Ok(Json(talon.info()?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn api_service() -> OpenApiService<TalonApi, ()> {
|
||||||
|
OpenApiService::new(TalonApi, "Talon", crate::API_VERSION)
|
||||||
|
.description("API for the Talon static site management system")
|
||||||
|
.license(LicenseObject::new("MIT License"))
|
||||||
|
}
|
||||||
|
|
69
src/assets.rs
Normal file
69
src/assets.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::{storage::CompressionAlg, util};
|
||||||
|
use poem::{
|
||||||
|
handler,
|
||||||
|
http::{header, Method, StatusCode},
|
||||||
|
web::Path,
|
||||||
|
Request, Response, Result,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(rust_embed::RustEmbed)]
|
||||||
|
#[folder = "ui/menu/dist/"]
|
||||||
|
struct MenuAsset;
|
||||||
|
|
||||||
|
#[handler]
|
||||||
|
pub fn menu_assets(request: &Request, path: Path<String>) -> Result<Response> {
|
||||||
|
assets(request, path, PhantomData::<MenuAsset>)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assets<A: rust_embed::RustEmbed + Sync + Send>(
|
||||||
|
request: &Request,
|
||||||
|
path: Path<String>,
|
||||||
|
_: PhantomData<A>,
|
||||||
|
) -> Result<Response> {
|
||||||
|
if request.method() != Method::GET {
|
||||||
|
return Ok(StatusCode::METHOD_NOT_ALLOWED.into());
|
||||||
|
}
|
||||||
|
let path = path.0;
|
||||||
|
|
||||||
|
match A::get(&path) {
|
||||||
|
Some(content) => {
|
||||||
|
let hash = hex::encode(content.metadata.sha256_hash());
|
||||||
|
|
||||||
|
// if etag is matched, return 304
|
||||||
|
if request
|
||||||
|
.headers()
|
||||||
|
.get(header::IF_NONE_MATCH)
|
||||||
|
.map(|etag| etag.to_str().unwrap_or("000000").eq(&hash))
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
return Ok(StatusCode::NOT_MODIFIED.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let alg = util::parse_accept_encoding(request.headers(), &[CompressionAlg::Brotli]);
|
||||||
|
let (body, body_alg) = if let Some(CompressionAlg::Brotli) = alg {
|
||||||
|
let path_compressed = format!("{path}.br");
|
||||||
|
if let Some(compressed_content) = MenuAsset::get(&path_compressed) {
|
||||||
|
(compressed_content.data, CompressionAlg::Brotli)
|
||||||
|
} else {
|
||||||
|
(content.data, CompressionAlg::None)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(content.data, CompressionAlg::None)
|
||||||
|
};
|
||||||
|
|
||||||
|
// otherwise, return 200 with etag hash
|
||||||
|
let mime = mime_guess::from_path(path).first_or_octet_stream();
|
||||||
|
let mut builder = Response::builder()
|
||||||
|
.header(header::CONTENT_TYPE, mime.as_ref())
|
||||||
|
.header(header::ETAG, hash);
|
||||||
|
if let Some(encoding) = body_alg.encoding() {
|
||||||
|
builder = builder.header(header::CONTENT_ENCODING, encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(builder.body(body.to_vec()))
|
||||||
|
}
|
||||||
|
None => Ok(Response::builder().status(StatusCode::NOT_FOUND).finish()),
|
||||||
|
}
|
||||||
|
}
|
8
src/bin/openapi.rs
Normal file
8
src/bin/openapi.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
use std::{fs::File, io::Error, io::Write};
|
||||||
|
|
||||||
|
/// Generate Talon's OpenAPI documentation
|
||||||
|
fn main() -> Result<(), Error> {
|
||||||
|
let api = talon::api::api_service();
|
||||||
|
let mut file = File::create("openapi.json")?;
|
||||||
|
file.write_all(api.spec().as_bytes())
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
#![warn(clippy::todo, clippy::dbg_macro)]
|
#![warn(clippy::todo, clippy::dbg_macro)]
|
||||||
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
|
pub mod assets;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
@ -21,6 +22,8 @@ use time::OffsetDateTime;
|
||||||
|
|
||||||
shadow_rs::shadow!(build);
|
shadow_rs::shadow!(build);
|
||||||
|
|
||||||
|
pub const API_VERSION: &str = "0.1.0";
|
||||||
|
|
||||||
pub static LAST_COMMIT_DATE: Lazy<SystemTime> = Lazy::new(|| {
|
pub static LAST_COMMIT_DATE: Lazy<SystemTime> = Lazy::new(|| {
|
||||||
OffsetDateTime::parse(
|
OffsetDateTime::parse(
|
||||||
build::COMMIT_DATE_3339,
|
build::COMMIT_DATE_3339,
|
||||||
|
|
|
@ -131,6 +131,14 @@ pub struct Stats {
|
||||||
pub storage_used: u64,
|
pub storage_used: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Embedded site config
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct TalonConfig<'a> {
|
||||||
|
pub api: &'a str,
|
||||||
|
pub version: &'a str,
|
||||||
|
pub root_domain: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Enum, Serialize, Deserialize,
|
Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Enum, Serialize, Deserialize,
|
||||||
)]
|
)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{ops::Deref, path::Path, sync::Arc};
|
use std::{ops::Deref, path::Path, sync::Arc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
api::TalonApi,
|
assets,
|
||||||
config::Config,
|
config::Config,
|
||||||
db::Db,
|
db::Db,
|
||||||
model::{Info, VersionInfo},
|
model::{Info, VersionInfo},
|
||||||
|
@ -14,7 +14,6 @@ use poem::{
|
||||||
http::header, listener::TcpListener, middleware, Endpoint, EndpointExt, Route, RouteDomain,
|
http::header, listener::TcpListener, middleware, Endpoint, EndpointExt, Route, RouteDomain,
|
||||||
Server,
|
Server,
|
||||||
};
|
};
|
||||||
use poem_openapi::OpenApiService;
|
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -74,8 +73,8 @@ impl Talon {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn endpoint(&self) -> impl Endpoint {
|
pub fn endpoint(&self) -> impl Endpoint {
|
||||||
let api_service = OpenApiService::new(TalonApi, "Talon", "0.1.0")
|
let api_service =
|
||||||
.server(format!("{}/api", self.i.cfg.server.internal_url));
|
crate::api::api_service().server(format!("{}/api", self.i.cfg.server.internal_url));
|
||||||
let swagger_ui = api_service.swagger_ui();
|
let swagger_ui = api_service.swagger_ui();
|
||||||
let spec = api_service.spec();
|
let spec = api_service.spec();
|
||||||
|
|
||||||
|
@ -84,14 +83,18 @@ impl Talon {
|
||||||
"/",
|
"/",
|
||||||
poem::endpoint::make_sync(|_| "Hello World, I am Talon"),
|
poem::endpoint::make_sync(|_| "Hello World, I am Talon"),
|
||||||
)
|
)
|
||||||
.nest("/api", api_service)
|
.nest(
|
||||||
|
"/api",
|
||||||
|
api_service
|
||||||
|
.with(middleware::Cors::new())
|
||||||
|
.with(crate::middleware::LastModified),
|
||||||
|
)
|
||||||
.nest("/api/swagger", swagger_ui)
|
.nest("/api/swagger", swagger_ui)
|
||||||
.at(
|
.at(
|
||||||
"/api/spec",
|
"/api/spec",
|
||||||
poem::endpoint::make_sync(move |_| spec.clone()),
|
poem::endpoint::make_sync(move |_| spec.clone()),
|
||||||
)
|
)
|
||||||
.with(middleware::Cors::new())
|
.at("/assets/menu/*path", assets::menu_assets);
|
||||||
.with(crate::middleware::LastModified);
|
|
||||||
|
|
||||||
let internal_domain = format!(
|
let internal_domain = format!(
|
||||||
"{}.{}",
|
"{}.{}",
|
||||||
|
|
|
@ -24,7 +24,7 @@ use zip::ZipArchive;
|
||||||
use crate::{
|
use crate::{
|
||||||
config::Config,
|
config::Config,
|
||||||
db::{Db, DbError},
|
db::{Db, DbError},
|
||||||
model::Stats,
|
model::{Stats, TalonConfig},
|
||||||
util,
|
util,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ pub struct Storage {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
db: Db,
|
db: Db,
|
||||||
cfg: Config,
|
cfg: Config,
|
||||||
|
to_inject: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -44,7 +45,7 @@ pub enum CompressionAlg {
|
||||||
|
|
||||||
impl CompressionAlg {
|
impl CompressionAlg {
|
||||||
/// Get value of the http encoding header
|
/// Get value of the http encoding header
|
||||||
fn encoding(&self) -> Option<&'static str> {
|
pub fn encoding(&self) -> Option<&'static str> {
|
||||||
match self {
|
match self {
|
||||||
CompressionAlg::None => None,
|
CompressionAlg::None => None,
|
||||||
CompressionAlg::Gzip => Some("gzip"),
|
CompressionAlg::Gzip => Some("gzip"),
|
||||||
|
@ -117,10 +118,28 @@ const TMPDIR_PREFIX: &str = "talon";
|
||||||
impl Storage {
|
impl Storage {
|
||||||
/// Create a new file storage using the root folder and the database
|
/// Create a new file storage using the root folder and the database
|
||||||
pub fn new<P: Into<PathBuf>>(path: P, db: Db, cfg: Config) -> Self {
|
pub fn new<P: Into<PathBuf>>(path: P, db: Db, cfg: Config) -> Self {
|
||||||
|
// Build the string to inject into html pages
|
||||||
|
let talon_cfg = TalonConfig {
|
||||||
|
api: &format!("{}/api", cfg.server.internal_url),
|
||||||
|
version: crate::build::PKG_VERSION,
|
||||||
|
root_domain: &cfg.server.root_domain,
|
||||||
|
};
|
||||||
|
|
||||||
|
let to_inject = format!(
|
||||||
|
r#"<!-- INJECTED BY TALON -->
|
||||||
|
<script id="talon-config" type="application/json">{}</script>
|
||||||
|
<script src="{}/assets/menu/talon.js"></script>
|
||||||
|
<!-- INJECTED BY TALON -->
|
||||||
|
"#,
|
||||||
|
serde_json::to_string(&talon_cfg).unwrap_or_default(),
|
||||||
|
cfg.server.internal_url
|
||||||
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
path: path.into(),
|
path: path.into(),
|
||||||
db,
|
db,
|
||||||
cfg,
|
cfg,
|
||||||
|
to_inject,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,15 +491,13 @@ impl Storage {
|
||||||
// HTML files are not precompressed and need to have UI code injected
|
// HTML files are not precompressed and need to have UI code injected
|
||||||
if is_html {
|
if is_html {
|
||||||
// Inject UI code into HTML
|
// Inject UI code into HTML
|
||||||
let to_inject = "<!-- Hello World -->\n";
|
|
||||||
|
|
||||||
let mut html = String::with_capacity(metadata.len() as usize);
|
let mut html = String::with_capacity(metadata.len() as usize);
|
||||||
tokio::fs::File::from_std(file)
|
tokio::fs::File::from_std(file)
|
||||||
.read_to_string(&mut html)
|
.read_to_string(&mut html)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(ctag_pos) = html.rfind("</html>") {
|
if let Some(ctag_pos) = html.rfind("</html>") {
|
||||||
html.insert_str(ctag_pos, to_inject);
|
html.insert_str(ctag_pos, &self.to_inject);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compress response if possible
|
// Compress response if possible
|
||||||
|
|
|
@ -426,7 +426,7 @@ mod storage {
|
||||||
let resp = tokio_test::block_on(tln.storage.file_to_response(gf, &HeaderMap::new(), true))
|
let resp = tokio_test::block_on(tln.storage.file_to_response(gf, &HeaderMap::new(), true))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let body = tokio_test::block_on(resp.into_body().into_string()).unwrap();
|
let body = tokio_test::block_on(resp.into_body().into_string()).unwrap();
|
||||||
assert!(body.contains("<!-- Hello World -->\n"));
|
assert!(body.contains("<!-- INJECTED BY TALON -->\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
|
|
|
@ -32,5 +32,10 @@
|
||||||
* Use globals.d.ts instead of compilerOptions.types
|
* Use globals.d.ts instead of compilerOptions.types
|
||||||
* to avoid limiting type declarations.
|
* to avoid limiting type declarations.
|
||||||
*/
|
*/
|
||||||
"include": ["globals.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"]
|
"include": [
|
||||||
|
"ui/*/globals.d.ts",
|
||||||
|
"ui/*/src/**/*.ts",
|
||||||
|
"ui/*/src/**/*.js",
|
||||||
|
"ui/*/src/**/*.svelte"
|
||||||
|
]
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
extends: ["eslint:recommended"],
|
extends: ["eslint:recommended"],
|
||||||
env: {browser: true, es6: true, node: true},
|
env: { browser: true, es6: true, node: true },
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
sourceType: "module",
|
sourceType: "module",
|
||||||
},
|
},
|
||||||
|
@ -37,4 +37,4 @@ module.exports = {
|
||||||
],
|
],
|
||||||
rules: {},
|
rules: {},
|
||||||
ignorePatterns: [".rollup/**", "public/**", "dist/**"],
|
ignorePatterns: [".rollup/**", "public/**", "dist/**"],
|
||||||
}
|
};
|
||||||
|
|
52
ui/menu/package-lock.json
generated
52
ui/menu/package-lock.json
generated
|
@ -9,7 +9,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||||
"minify-html-stream": "^0.3.1"
|
"minify-html-stream": "^0.3.1",
|
||||||
|
"talon-client": "file:../talon-client"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.15.5",
|
"@babel/core": "^7.15.5",
|
||||||
|
@ -17,7 +18,7 @@
|
||||||
"@babel/preset-typescript": "^7.15.0",
|
"@babel/preset-typescript": "^7.15.0",
|
||||||
"@rollup/plugin-babel": "^5.3.0",
|
"@rollup/plugin-babel": "^5.3.0",
|
||||||
"@rollup/plugin-commonjs": "^20.0.0",
|
"@rollup/plugin-commonjs": "^20.0.0",
|
||||||
"@rollup/plugin-node-resolve": "^13.0.5",
|
"@rollup/plugin-node-resolve": "^13.3.0",
|
||||||
"@rollup/plugin-replace": "^3.0.0",
|
"@rollup/plugin-replace": "^3.0.0",
|
||||||
"@rollup/plugin-typescript": "^8.2.5",
|
"@rollup/plugin-typescript": "^8.2.5",
|
||||||
"@rollup/pluginutils": "^4.1.1",
|
"@rollup/pluginutils": "^4.1.1",
|
||||||
|
@ -29,6 +30,7 @@
|
||||||
"prettier": "^2.2.1",
|
"prettier": "^2.2.1",
|
||||||
"prettier-plugin-svelte": "^1.2.0",
|
"prettier-plugin-svelte": "^1.2.0",
|
||||||
"rollup": "^2.57.0",
|
"rollup": "^2.57.0",
|
||||||
|
"rollup-plugin-brotli": "^3.1.0",
|
||||||
"rollup-plugin-copy": "^3.4.0",
|
"rollup-plugin-copy": "^3.4.0",
|
||||||
"rollup-plugin-html-minifier": "^2.0.0",
|
"rollup-plugin-html-minifier": "^2.0.0",
|
||||||
"rollup-plugin-livereload": "^2.0.5",
|
"rollup-plugin-livereload": "^2.0.5",
|
||||||
|
@ -41,7 +43,8 @@
|
||||||
"svelte-keydown": "^0.3.1",
|
"svelte-keydown": "^0.3.1",
|
||||||
"svelte-modals": "^1.0.4",
|
"svelte-modals": "^1.0.4",
|
||||||
"svelte-preprocess": "^4.9.5",
|
"svelte-preprocess": "^4.9.5",
|
||||||
"typescript": "^4.4.3"
|
"tslib": "^2.5.0",
|
||||||
|
"typescript": "^4.9.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
|
@ -2758,9 +2761,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001460",
|
"version": "1.0.30001462",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001460.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001462.tgz",
|
||||||
"integrity": "sha512-Bud7abqjvEjipUkpLs4D7gR0l8hBYBHoa+tGtKJHvT2AYzLp1z7EmVkUT4ERpVUfca8S2HGIVs883D8pUH1ZzQ==",
|
"integrity": "sha512-PDd20WuOBPiasZ7KbFnmQRyuLE7cFXW2PVd7dmALzbkUXEP46upAuCDm9eY9vho8fgNMGmbAX92QBZHzcnWIqw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -2973,9 +2976,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.320",
|
"version": "1.4.325",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.320.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.325.tgz",
|
||||||
"integrity": "sha512-h70iRscrNluMZPVICXYl5SSB+rBKo22XfuIS1ER0OQxQZpKTnFpuS6coj7wY9M/3trv7OR88rRMOlKmRvDty7Q==",
|
"integrity": "sha512-K1C03NT4I7BuzsRdCU5RWkgZxtswnKDYM6/eMhkEXqKu4e5T+ck610x3FPzu1y7HVFSiQKZqP16gnJzPpji1TQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/emoji-regex": {
|
"node_modules/emoji-regex": {
|
||||||
|
@ -4489,9 +4492,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/resolve.exports": {
|
"node_modules/resolve.exports": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.1.tgz",
|
||||||
"integrity": "sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg==",
|
"integrity": "sha512-OEJWVeimw8mgQuj3HfkNl4KqRevH7lzeQNaWRPfx0PPse7Jk6ozcsG4FKVgtzDsC1KUF+YlTHh17NcgHOPykLw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
|
@ -4537,6 +4540,15 @@
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rollup-plugin-brotli": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/rollup-plugin-brotli/-/rollup-plugin-brotli-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-vXRPVd9B1x+aaXeBdmLKNNsai9AH3o0Qikf4u0m1icKqgi3qVA4UhOfwGaPYoAHML1GLMUnR//PDhiMHXN/M6g==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=11.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/rollup-plugin-copy": {
|
"node_modules/rollup-plugin-copy": {
|
||||||
"version": "3.4.0",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz",
|
||||||
|
@ -5150,6 +5162,10 @@
|
||||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/talon-client": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "file:../talon-client"
|
||||||
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.16.5",
|
"version": "5.16.5",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.16.5.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.16.5.tgz",
|
||||||
|
@ -5226,9 +5242,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "1.14.1",
|
"version": "2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
|
||||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/tsutils": {
|
"node_modules/tsutils": {
|
||||||
|
@ -5246,6 +5262,12 @@
|
||||||
"typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
|
"typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tsutils/node_modules/tslib": {
|
||||||
|
"version": "1.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||||
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/type-check": {
|
"node_modules/type-check": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
"start": "sirv public --single",
|
"start": "sirv public --single",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"fix": "eslint . --fix",
|
"fix": "eslint . --fix",
|
||||||
"check": "svelte-check --tsconfig tsconfig.json",
|
"check": "svelte-check --tsconfig ../../tsconfig.json",
|
||||||
"format": "prettier --plugin=./node_modules/prettier-plugin-svelte --write .",
|
"format": "prettier --plugin=./node_modules/prettier-plugin-svelte --write .",
|
||||||
"pc": "npm run fix & npm run check & npm run format",
|
"pc": "npm run fix & npm run check & npm run format",
|
||||||
"ci": "npm run lint & npm run check & prettier --plugin=./node_modules/prettier-plugin-svelte --check ."
|
"ci": "npm run lint & npm run check & prettier --plugin=./node_modules/prettier-plugin-svelte --check ."
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
"@babel/preset-typescript": "^7.15.0",
|
"@babel/preset-typescript": "^7.15.0",
|
||||||
"@rollup/plugin-babel": "^5.3.0",
|
"@rollup/plugin-babel": "^5.3.0",
|
||||||
"@rollup/plugin-commonjs": "^20.0.0",
|
"@rollup/plugin-commonjs": "^20.0.0",
|
||||||
"@rollup/plugin-node-resolve": "^13.0.5",
|
"@rollup/plugin-node-resolve": "^13.3.0",
|
||||||
"@rollup/plugin-replace": "^3.0.0",
|
"@rollup/plugin-replace": "^3.0.0",
|
||||||
"@rollup/plugin-typescript": "^8.2.5",
|
"@rollup/plugin-typescript": "^8.2.5",
|
||||||
"@rollup/pluginutils": "^4.1.1",
|
"@rollup/pluginutils": "^4.1.1",
|
||||||
|
@ -32,6 +32,7 @@
|
||||||
"prettier": "^2.2.1",
|
"prettier": "^2.2.1",
|
||||||
"prettier-plugin-svelte": "^1.2.0",
|
"prettier-plugin-svelte": "^1.2.0",
|
||||||
"rollup": "^2.57.0",
|
"rollup": "^2.57.0",
|
||||||
|
"rollup-plugin-brotli": "^3.1.0",
|
||||||
"rollup-plugin-copy": "^3.4.0",
|
"rollup-plugin-copy": "^3.4.0",
|
||||||
"rollup-plugin-html-minifier": "^2.0.0",
|
"rollup-plugin-html-minifier": "^2.0.0",
|
||||||
"rollup-plugin-livereload": "^2.0.5",
|
"rollup-plugin-livereload": "^2.0.5",
|
||||||
|
@ -44,11 +45,13 @@
|
||||||
"svelte-keydown": "^0.3.1",
|
"svelte-keydown": "^0.3.1",
|
||||||
"svelte-modals": "^1.0.4",
|
"svelte-modals": "^1.0.4",
|
||||||
"svelte-preprocess": "^4.9.5",
|
"svelte-preprocess": "^4.9.5",
|
||||||
"typescript": "^4.4.3"
|
"tslib": "^2.5.0",
|
||||||
|
"typescript": "^4.9.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||||
"minify-html-stream": "^0.3.1"
|
"minify-html-stream": "^0.3.1",
|
||||||
|
"talon-client": "file:../talon-client"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,11 +72,7 @@
|
||||||
fill="#000000"
|
fill="#000000"
|
||||||
font-family="sans-serif"
|
font-family="sans-serif"
|
||||||
font-size="40px"
|
font-size="40px"
|
||||||
style="
|
style="line-height: 1.25; shape-inside: url(#rect3620); white-space: pre"
|
||||||
line-height: 1.25;
|
|
||||||
shape-inside: url(#rect3620);
|
|
||||||
white-space: pre;
|
|
||||||
"
|
|
||||||
xml:space="preserve"
|
xml:space="preserve"
|
||||||
/>
|
/>
|
||||||
<g
|
<g
|
||||||
|
@ -106,191 +102,98 @@
|
||||||
</div>
|
</div>
|
||||||
<h1>development</h1>
|
<h1>development</h1>
|
||||||
<p>
|
<p>
|
||||||
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar
|
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar plum
|
||||||
plum pudding halvah chocolate. Cotton candy tart cake bonbon tart.
|
pudding halvah chocolate. Cotton candy tart cake bonbon tart. Shortbread jelly
|
||||||
Shortbread jelly fruitcake icing pastry. Dragée dessert cupcake cake
|
fruitcake icing pastry. Dragée dessert cupcake cake sesame snaps toffee pie.
|
||||||
sesame snaps toffee pie. Sweet roll sweet roll chupa chups jelly-o
|
Sweet roll sweet roll chupa chups jelly-o gummies tootsie roll sweet halvah oat
|
||||||
gummies tootsie roll sweet halvah oat cake. Carrot cake carrot cake
|
cake. Carrot cake carrot cake muffin bonbon sesame snaps brownie. Bonbon candy
|
||||||
muffin bonbon sesame snaps brownie. Bonbon candy macaroon fruitcake
|
macaroon fruitcake candy canes. Cake pudding danish liquorice cupcake jelly-o
|
||||||
candy canes. Cake pudding danish liquorice cupcake jelly-o ice cream.
|
ice cream. Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
||||||
Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
candy canes donut lemon drops apple pie danish bear claw. Caramels cake jelly
|
||||||
candy canes donut lemon drops apple pie danish bear claw. Caramels cake
|
jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop pudding
|
||||||
jelly jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop
|
marshmallow candy canes tootsie roll danish.
|
||||||
pudding marshmallow candy canes tootsie roll danish.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar
|
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar plum
|
||||||
plum pudding halvah chocolate. Cotton candy tart cake bonbon tart.
|
pudding halvah chocolate. Cotton candy tart cake bonbon tart. Shortbread jelly
|
||||||
Shortbread jelly fruitcake icing pastry. Dragée dessert cupcake cake
|
fruitcake icing pastry. Dragée dessert cupcake cake sesame snaps toffee pie.
|
||||||
sesame snaps toffee pie. Sweet roll sweet roll chupa chups jelly-o
|
Sweet roll sweet roll chupa chups jelly-o gummies tootsie roll sweet halvah oat
|
||||||
gummies tootsie roll sweet halvah oat cake. Carrot cake carrot cake
|
cake. Carrot cake carrot cake muffin bonbon sesame snaps brownie. Bonbon candy
|
||||||
muffin bonbon sesame snaps brownie. Bonbon candy macaroon fruitcake
|
macaroon fruitcake candy canes. Cake pudding danish liquorice cupcake jelly-o
|
||||||
candy canes. Cake pudding danish liquorice cupcake jelly-o ice cream.
|
ice cream. Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
||||||
Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
candy canes donut lemon drops apple pie danish bear claw. Caramels cake jelly
|
||||||
candy canes donut lemon drops apple pie danish bear claw. Caramels cake
|
jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop pudding
|
||||||
jelly jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop
|
marshmallow candy canes tootsie roll danish.
|
||||||
pudding marshmallow candy canes tootsie roll danish.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar
|
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar plum
|
||||||
plum pudding halvah chocolate. Cotton candy tart cake bonbon tart.
|
pudding halvah chocolate. Cotton candy tart cake bonbon tart. Shortbread jelly
|
||||||
Shortbread jelly fruitcake icing pastry. Dragée dessert cupcake cake
|
fruitcake icing pastry. Dragée dessert cupcake cake sesame snaps toffee pie.
|
||||||
sesame snaps toffee pie. Sweet roll sweet roll chupa chups jelly-o
|
Sweet roll sweet roll chupa chups jelly-o gummies tootsie roll sweet halvah oat
|
||||||
gummies tootsie roll sweet halvah oat cake. Carrot cake carrot cake
|
cake. Carrot cake carrot cake muffin bonbon sesame snaps brownie. Bonbon candy
|
||||||
muffin bonbon sesame snaps brownie. Bonbon candy macaroon fruitcake
|
macaroon fruitcake candy canes. Cake pudding danish liquorice cupcake jelly-o
|
||||||
candy canes. Cake pudding danish liquorice cupcake jelly-o ice cream.
|
ice cream. Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
||||||
Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
candy canes donut lemon drops apple pie danish bear claw. Caramels cake jelly
|
||||||
candy canes donut lemon drops apple pie danish bear claw. Caramels cake
|
jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop pudding
|
||||||
jelly jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop
|
marshmallow candy canes tootsie roll danish.
|
||||||
pudding marshmallow candy canes tootsie roll danish.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar
|
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar plum
|
||||||
plum pudding halvah chocolate. Cotton candy tart cake bonbon tart.
|
pudding halvah chocolate. Cotton candy tart cake bonbon tart. Shortbread jelly
|
||||||
Shortbread jelly fruitcake icing pastry. Dragée dessert cupcake cake
|
fruitcake icing pastry. Dragée dessert cupcake cake sesame snaps toffee pie.
|
||||||
sesame snaps toffee pie. Sweet roll sweet roll chupa chups jelly-o
|
Sweet roll sweet roll chupa chups jelly-o gummies tootsie roll sweet halvah oat
|
||||||
gummies tootsie roll sweet halvah oat cake. Carrot cake carrot cake
|
cake. Carrot cake carrot cake muffin bonbon sesame snaps brownie. Bonbon candy
|
||||||
muffin bonbon sesame snaps brownie. Bonbon candy macaroon fruitcake
|
macaroon fruitcake candy canes. Cake pudding danish liquorice cupcake jelly-o
|
||||||
candy canes. Cake pudding danish liquorice cupcake jelly-o ice cream.
|
ice cream. Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
||||||
Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
candy canes donut lemon drops apple pie danish bear claw. Caramels cake jelly
|
||||||
candy canes donut lemon drops apple pie danish bear claw. Caramels cake
|
jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop pudding
|
||||||
jelly jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop
|
marshmallow candy canes tootsie roll danish.
|
||||||
pudding marshmallow candy canes tootsie roll danish.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar
|
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar plum
|
||||||
plum pudding halvah chocolate. Cotton candy tart cake bonbon tart.
|
pudding halvah chocolate. Cotton candy tart cake bonbon tart. Shortbread jelly
|
||||||
Shortbread jelly fruitcake icing pastry. Dragée dessert cupcake cake
|
fruitcake icing pastry. Dragée dessert cupcake cake sesame snaps toffee pie.
|
||||||
sesame snaps toffee pie. Sweet roll sweet roll chupa chups jelly-o
|
Sweet roll sweet roll chupa chups jelly-o gummies tootsie roll sweet halvah oat
|
||||||
gummies tootsie roll sweet halvah oat cake. Carrot cake carrot cake
|
cake. Carrot cake carrot cake muffin bonbon sesame snaps brownie. Bonbon candy
|
||||||
muffin bonbon sesame snaps brownie. Bonbon candy macaroon fruitcake
|
macaroon fruitcake candy canes. Cake pudding danish liquorice cupcake jelly-o
|
||||||
candy canes. Cake pudding danish liquorice cupcake jelly-o ice cream.
|
ice cream. Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
||||||
Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
candy canes donut lemon drops apple pie danish bear claw. Caramels cake jelly
|
||||||
candy canes donut lemon drops apple pie danish bear claw. Caramels cake
|
jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop pudding
|
||||||
jelly jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop
|
marshmallow candy canes tootsie roll danish.
|
||||||
pudding marshmallow candy canes tootsie roll danish.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar
|
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar plum
|
||||||
plum pudding halvah chocolate. Cotton candy tart cake bonbon tart.
|
pudding halvah chocolate. Cotton candy tart cake bonbon tart. Shortbread jelly
|
||||||
Shortbread jelly fruitcake icing pastry. Dragée dessert cupcake cake
|
fruitcake icing pastry. Dragée dessert cupcake cake sesame snaps toffee pie.
|
||||||
sesame snaps toffee pie. Sweet roll sweet roll chupa chups jelly-o
|
Sweet roll sweet roll chupa chups jelly-o gummies tootsie roll sweet halvah oat
|
||||||
gummies tootsie roll sweet halvah oat cake. Carrot cake carrot cake
|
cake. Carrot cake carrot cake muffin bonbon sesame snaps brownie. Bonbon candy
|
||||||
muffin bonbon sesame snaps brownie. Bonbon candy macaroon fruitcake
|
macaroon fruitcake candy canes. Cake pudding danish liquorice cupcake jelly-o
|
||||||
candy canes. Cake pudding danish liquorice cupcake jelly-o ice cream.
|
ice cream. Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
||||||
Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
candy canes donut lemon drops apple pie danish bear claw. Caramels cake jelly
|
||||||
candy canes donut lemon drops apple pie danish bear claw. Caramels cake
|
jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop pudding
|
||||||
jelly jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop
|
marshmallow candy canes tootsie roll danish.
|
||||||
pudding marshmallow candy canes tootsie roll danish.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar
|
Carrot cake biscuit icing pudding danish topping powder. Croissant sugar plum
|
||||||
plum pudding halvah chocolate. Cotton candy tart cake bonbon tart.
|
pudding halvah chocolate. Cotton candy tart cake bonbon tart. Shortbread jelly
|
||||||
Shortbread jelly fruitcake icing pastry. Dragée dessert cupcake cake
|
fruitcake icing pastry. Dragée dessert cupcake cake sesame snaps toffee pie.
|
||||||
sesame snaps toffee pie. Sweet roll sweet roll chupa chups jelly-o
|
Sweet roll sweet roll chupa chups jelly-o gummies tootsie roll sweet halvah oat
|
||||||
gummies tootsie roll sweet halvah oat cake. Carrot cake carrot cake
|
cake. Carrot cake carrot cake muffin bonbon sesame snaps brownie. Bonbon candy
|
||||||
muffin bonbon sesame snaps brownie. Bonbon candy macaroon fruitcake
|
macaroon fruitcake candy canes. Cake pudding danish liquorice cupcake jelly-o
|
||||||
candy canes. Cake pudding danish liquorice cupcake jelly-o ice cream.
|
ice cream. Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
||||||
Liquorice lollipop danish tootsie roll toffee. Gingerbread chocolate
|
candy canes donut lemon drops apple pie danish bear claw. Caramels cake jelly
|
||||||
candy canes donut lemon drops apple pie danish bear claw. Caramels cake
|
jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop pudding
|
||||||
jelly jelly sweet chocolate bar gingerbread icing. Cake soufflé lollipop
|
marshmallow candy canes tootsie roll danish.
|
||||||
pudding marshmallow candy canes tootsie roll danish.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
<script id="talon-data" type="application/json">
|
<script id="talon-config" type="application/json">
|
||||||
{
|
{
|
||||||
"root_path": "/",
|
"api": "http://talon.localhost:3000/api",
|
||||||
"current_page": "2",
|
"version": "0.1.0",
|
||||||
"current_version": "6",
|
"root_domain": "localhost:3000"
|
||||||
"versions": {
|
|
||||||
"3": {
|
|
||||||
"date": "2021-06-15T11:12:21+00:00",
|
|
||||||
"name": "0.1.0",
|
|
||||||
"user": "ThetaDev",
|
|
||||||
"tags": {
|
|
||||||
"commit": "ec55eba5ae45640c3d225c2471920fd3c9a36489"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"date": "2021-06-20T16:48:21+00:00",
|
|
||||||
"name": "0.1.1",
|
|
||||||
"user": "ThetaDev",
|
|
||||||
"tags": {
|
|
||||||
"commit": "ec55eba5ae45640c3d225c2471920fd3c9a36489"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"date": "2021-06-22T12:08:21+00:00",
|
|
||||||
"name": "0.1.2",
|
|
||||||
"user": "ThetaDev",
|
|
||||||
"tags": {
|
|
||||||
"commit": "ec55eba5ae45640c3d225c2471920fd3c9a36489"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"date": "2021-07-02T16:12:40+00:00",
|
|
||||||
"name": "0.1.3",
|
|
||||||
"user": "ThetaDev",
|
|
||||||
"tags": {
|
|
||||||
"commit": "bbc7342580b48433481857bfe95e58784a508275"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pages": {
|
|
||||||
"1": {
|
|
||||||
"name": "ThetaDev",
|
|
||||||
"path": "",
|
|
||||||
"color": "#1f91ee",
|
|
||||||
"visibility": "featured",
|
|
||||||
"source": {
|
|
||||||
"url": "https://github.com/Theta-Dev",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"name": "Talon",
|
|
||||||
"path": "Talon",
|
|
||||||
"color": "#4b228a",
|
|
||||||
"visibility": "featured",
|
|
||||||
"source": {
|
|
||||||
"url": "https://github.com/Theta-Dev/Talon",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"name": "Spotify-Gender-Ex",
|
|
||||||
"path": "Spotify-Gender-Ex",
|
|
||||||
"color": "#1DB954",
|
|
||||||
"image": "https://raw.githubusercontent.com/Theta-Dev/Spotify-Gender-Ex/master/assets/logo_square.svg",
|
|
||||||
"visibility": "featured",
|
|
||||||
"source": {
|
|
||||||
"url": "https://github.com/Theta-Dev/Spotify-Gender-Ex",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "A1",
|
|
||||||
"path": "tests/a1",
|
|
||||||
"color": "#ff0000",
|
|
||||||
"visibility": "searchable"
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"name": "B1",
|
|
||||||
"path": "tests/b1",
|
|
||||||
"color": "#00ff00",
|
|
||||||
"visibility": "searchable"
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"name": "C1",
|
|
||||||
"path": "tests/c1",
|
|
||||||
"color": "#0000ff",
|
|
||||||
"visibility": "searchable"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src="./talon.js"></script>
|
<script src="./talon.js"></script>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -13,6 +13,7 @@ import sveltePreprocess from "svelte-preprocess"
|
||||||
import typescript from "@rollup/plugin-typescript"
|
import typescript from "@rollup/plugin-typescript"
|
||||||
import replace from "@rollup/plugin-replace"
|
import replace from "@rollup/plugin-replace"
|
||||||
import babel from "@rollup/plugin-babel"
|
import babel from "@rollup/plugin-babel"
|
||||||
|
import brotli from "rollup-plugin-brotli"
|
||||||
|
|
||||||
import css from ".rollup/css-only"
|
import css from ".rollup/css-only"
|
||||||
import {serve} from ".rollup/serve"
|
import {serve} from ".rollup/serve"
|
||||||
|
@ -148,6 +149,8 @@ export default {
|
||||||
],
|
],
|
||||||
babelHelpers: "bundled",
|
babelHelpers: "bundled",
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
brotli(),
|
||||||
],
|
],
|
||||||
watch: {
|
watch: {
|
||||||
chokidar: true,
|
chokidar: true,
|
||||||
|
|
|
@ -1,16 +1,32 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {closeModal, Modals} from "svelte-modals"
|
import { onMount } from "svelte";
|
||||||
|
import { closeModal, Modals } from "svelte-modals";
|
||||||
|
import type { Website } from "ui/talon-client/src";
|
||||||
|
|
||||||
import Menu from "./components/Menu.svelte"
|
import Menu from "./components/Menu.svelte";
|
||||||
import {currentPage, isPresent} from "./util/talonData"
|
import { currentWebsiteStore, fetchWebsites } from "./util/api";
|
||||||
|
|
||||||
|
let currentWebsite: Website;
|
||||||
|
|
||||||
|
currentWebsiteStore.subscribe((ws) => {
|
||||||
|
console.log("current ws changed", ws);
|
||||||
|
currentWebsite = ws;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMount(fetchWebsites);
|
||||||
|
|
||||||
|
let color: String;
|
||||||
|
$: {
|
||||||
|
if (currentWebsite && currentWebsite.color) {
|
||||||
|
color = currentWebsite.color;
|
||||||
|
} else {
|
||||||
|
color = "#7935df";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
// Default theme
|
|
||||||
.wrapper
|
|
||||||
--talon-color: #7935df
|
|
||||||
|
|
||||||
.backdrop
|
.backdrop
|
||||||
position: fixed
|
position: fixed
|
||||||
top: 0
|
top: 0
|
||||||
|
@ -20,12 +36,13 @@
|
||||||
background: rgba(0, 0, 0, 0.6)
|
background: rgba(0, 0, 0, 0.6)
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="wrapper" style={`--talon-color: ${currentPage.color}`}>
|
<div class="wrapper" style={`--talon-color: ${color}`}>
|
||||||
{#if isPresent}
|
{#if currentWebsite}
|
||||||
<Menu />
|
<Menu />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<Modals>
|
<Modals>
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<div class="backdrop" slot="backdrop" on:click={closeModal} />
|
<div class="backdrop" slot="backdrop" on:click={closeModal} />
|
||||||
</Modals>
|
</Modals>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let imageSrc: string
|
export let imageSrc: string;
|
||||||
export let size = 32
|
export let size = 32;
|
||||||
export let scale = 1
|
export let scale = 1;
|
||||||
export let alt = "??"
|
export let alt = "??";
|
||||||
export let color = "#4b228a"
|
export let color = "#4b228a";
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,63 +1,38 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {fly} from "svelte/transition"
|
import { fly } from "svelte/transition";
|
||||||
import {closeModal} from "svelte-modals"
|
import { closeModal } from "svelte-modals";
|
||||||
import Keydown from "svelte-keydown"
|
import Keydown from "svelte-keydown";
|
||||||
|
|
||||||
import type {TalonVersion} from "../util/types"
|
import PageIcon from "./PageIcon.svelte";
|
||||||
import PageIcon from "./PageIcon.svelte"
|
import Icon from "./Icon.svelte";
|
||||||
import Icon from "./Icon.svelte"
|
import { formatDate, getWebsiteVersionUrl } from "../util/functions";
|
||||||
import {formatDate} from "../util/functions"
|
import InlineIcon from "./InlineIcon.svelte";
|
||||||
import InlineIcon from "./InlineIcon.svelte"
|
import Tag from "./Tag.svelte";
|
||||||
import Tag from "./Tag.svelte"
|
import type { Version, Website } from "talon-client";
|
||||||
import {
|
import { client, currentWebsiteStore } from "../util/api";
|
||||||
currentPage,
|
import { talonConfig } from "../util/talonData";
|
||||||
currentVersion,
|
|
||||||
currentVersionId,
|
|
||||||
rootPath,
|
|
||||||
versions,
|
|
||||||
} from "../util/talonData"
|
|
||||||
|
|
||||||
export let isOpen: boolean
|
let currentWebsite: Website;
|
||||||
|
currentWebsiteStore.subscribe((ws) => {
|
||||||
|
currentWebsite = ws;
|
||||||
|
});
|
||||||
|
|
||||||
function getVersionName(versionId: string, version: TalonVersion): string {
|
export let isOpen: boolean;
|
||||||
return version.name ? version.name : "#" + versionId
|
$: {
|
||||||
|
if (isOpen && currentWebsite) {
|
||||||
|
client
|
||||||
|
.websiteSubdomainVersionsGet({ subdomain: currentWebsite.subdomain })
|
||||||
|
.then((v) => {
|
||||||
|
versions = v;
|
||||||
|
if (v && v.length > 0) {
|
||||||
|
currentVersion = v[v.length - 1];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVersionUrl(versionId: string, version: TalonVersion): string {
|
let versions: Version[] = [];
|
||||||
return (
|
let currentVersion: Version = null;
|
||||||
rootPath +
|
|
||||||
(currentPage && version.name
|
|
||||||
? currentPage.path + "@" + version.name
|
|
||||||
: "&v/" + versionId)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let versionName: string
|
|
||||||
$: versionName = getVersionName(currentVersionId, currentVersion)
|
|
||||||
|
|
||||||
let versionUrl: string
|
|
||||||
$: versionUrl = getVersionUrl(currentVersionId, currentVersion)
|
|
||||||
|
|
||||||
let uploadDate: string
|
|
||||||
$: uploadDate = formatDate(currentVersion.date)
|
|
||||||
|
|
||||||
let pageTags: [string, string][]
|
|
||||||
$: pageTags = currentVersion.tags
|
|
||||||
? Object.entries(currentVersion.tags).map(([key, val]) => [
|
|
||||||
key.replace(/^\w/, (c) => c.toUpperCase()),
|
|
||||||
val,
|
|
||||||
])
|
|
||||||
: []
|
|
||||||
|
|
||||||
let history: [string, string, string][]
|
|
||||||
$: history = Object.entries(versions)
|
|
||||||
.filter((e) => e[0] !== currentVersionId)
|
|
||||||
.map(([key, version]) => [
|
|
||||||
formatDate(version.date),
|
|
||||||
getVersionName(key, version),
|
|
||||||
getVersionUrl(key, version),
|
|
||||||
])
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
|
@ -143,62 +118,55 @@
|
||||||
|
|
||||||
<Keydown paused={!isOpen} on:Escape={closeModal} />
|
<Keydown paused={!isOpen} on:Escape={closeModal} />
|
||||||
|
|
||||||
{#if isOpen}
|
{#if isOpen && currentWebsite}
|
||||||
<div class="modal" role="dialog" transition:fly={{y: 50}} on:introstart on:outroend>
|
<div class="modal" role="dialog" transition:fly={{ y: 50 }} on:introstart on:outroend>
|
||||||
<div>
|
<div>
|
||||||
<div class="tag">
|
<div class="tag">
|
||||||
<PageIcon page={currentPage} size={60} scale={0.8} />
|
<PageIcon website={currentWebsite} size={60} scale={0.8} />
|
||||||
<span>{currentPage ? currentPage.name : 'v' + currentVersionId}</span>
|
<span>{currentWebsite.name}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if !currentPage}
|
{#if currentVersion}
|
||||||
<p>
|
|
||||||
This is a dangling version, i.e. it does not belong to a page.
|
|
||||||
Assign it to a page or it will be purged within 24 hours.
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<p class="dhead">
|
<p class="dhead">
|
||||||
<InlineIcon iconName="question" />
|
<InlineIcon iconName="question" />
|
||||||
Current version
|
Current version #{currentVersion.id}
|
||||||
</p>
|
</p>
|
||||||
|
<Tag key="Upload date" value={formatDate(currentVersion.createdAt)} />
|
||||||
|
<!--<Tag key="Uploaded by" value={currentVersion.user} />-->
|
||||||
|
|
||||||
<Tag key="Version" value={versionName} href={versionUrl} />
|
{#each Object.entries(currentVersion.data) as [key, value]}
|
||||||
<Tag key="Upload date" value={uploadDate} />
|
|
||||||
<Tag key="Uploaded by" value={currentVersion.user} />
|
|
||||||
|
|
||||||
{#each pageTags as [key, value]}
|
|
||||||
<Tag {key} {value} />
|
<Tag {key} {value} />
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#if history.length}
|
{#if versions && versions.length}
|
||||||
<p class="dhead">
|
<p class="dhead">
|
||||||
<InlineIcon iconName="history" />
|
<InlineIcon iconName="history" />
|
||||||
History
|
History
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{#each history as [date, name, url]}
|
{#each versions as version}
|
||||||
<p class="smalltag">
|
<p class="smalltag">
|
||||||
<a href={url}> <span>{name}</span> <span>{date}</span> </a>
|
<a href={getWebsiteVersionUrl(currentWebsite.subdomain, version.id)}>
|
||||||
|
<span>#{version.id}</span>
|
||||||
|
<span>{formatDate(version.createdAt)}</span>
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
<p class="dhead" />
|
<p class="dhead" />
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
This site is powered by
|
Powered by
|
||||||
<a
|
<a
|
||||||
href="https://github.com/Theta-Dev/Talon/tree/__VERSION__"
|
href="https://code.thetadev.de/ThetaDev/Talon/src/tag/{talonConfig.version}"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
referrerpolicy="no-referrer">Talon __VERSION__</a>, a static site
|
rel="noreferrer"
|
||||||
management system created by
|
referrerpolicy="no-referrer">Talon
|
||||||
<a
|
{talonConfig.version}</a>
|
||||||
href="https://thetadev.de"
|
|
||||||
target="_blank"
|
|
||||||
referrerpolicy="no-referrer">ThetaDev</a>
|
|
||||||
</div>
|
</div>
|
||||||
<p><a href={rootPath + '&credits'} target="_blank">View licenses</a></p>
|
<!--<p><a href="" target="_blank">View licenses</a></p>-->
|
||||||
<button on:click={closeModal}>
|
<button on:click={closeModal}>
|
||||||
<Icon iconName="close" size={40} scale={0.6} transparent={true} />
|
<Icon iconName="close" size={40} scale={0.6} transparent={true} />
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -1,87 +1,97 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {openModal} from "svelte-modals"
|
import { openModal } from "svelte-modals";
|
||||||
|
|
||||||
import Icon from "./Icon.svelte"
|
import Icon from "./Icon.svelte";
|
||||||
import MenuItem from "./MenuItem.svelte"
|
import MenuItem from "./MenuItem.svelte";
|
||||||
import MenuItemPage from "./MenuItemPage.svelte"
|
import MenuItemPage from "./MenuItemPage.svelte";
|
||||||
import InfoModal from "./InfoModal.svelte"
|
import InfoModal from "./InfoModal.svelte";
|
||||||
import FloatingButton from "./FloatingButton.svelte"
|
import FloatingButton from "./FloatingButton.svelte";
|
||||||
|
|
||||||
import type {Focusable, TalonPage} from "../util/types"
|
import type { Focusable } from "../util/types";
|
||||||
import {TalonVisibility} from "../util/types"
|
import PageIcon from "./PageIcon.svelte";
|
||||||
import PageIcon from "./PageIcon.svelte"
|
import MenuItemInput from "./MenuItemInput.svelte";
|
||||||
import MenuItemInput from "./MenuItemInput.svelte"
|
import { currentWebsiteStore, websitesStore } from "../util/api";
|
||||||
import {currentPage, currentPageId, pages, rootPath} from "../util/talonData"
|
import { Visibility, Website } from "talon-client";
|
||||||
|
import { getWebsiteUrl } from "../util/functions";
|
||||||
|
|
||||||
|
let currentWebsite: Website;
|
||||||
|
let websites: Website[];
|
||||||
|
|
||||||
|
currentWebsiteStore.subscribe((ws) => {
|
||||||
|
currentWebsite = ws;
|
||||||
|
});
|
||||||
|
websitesStore.subscribe((ws) => {
|
||||||
|
websites = ws;
|
||||||
|
});
|
||||||
|
|
||||||
function showSidebar(): void {
|
function showSidebar(): void {
|
||||||
sidebarShown = true
|
sidebarShown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideSidebar(): void {
|
function hideSidebar(): void {
|
||||||
sidebarShown = false
|
sidebarShown = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMobile(): boolean {
|
function isMobile(): boolean {
|
||||||
return window.innerWidth < 768
|
return window.innerWidth < 768;
|
||||||
}
|
}
|
||||||
|
|
||||||
function openSearch(): void {
|
function openSearch(): void {
|
||||||
searchOpen = true
|
searchOpen = true;
|
||||||
searchInput.focus()
|
searchInput.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeSearch() {
|
function closeSearch() {
|
||||||
searchOpen = false
|
searchOpen = false;
|
||||||
searchInput.blur()
|
searchInput.blur();
|
||||||
|
|
||||||
if (displayedPages.length === 0) searchText = ""
|
if (displayedWebsites.length === 0) searchText = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearSearch() {
|
function clearSearch() {
|
||||||
searchText = ""
|
searchText = "";
|
||||||
closeSearch()
|
closeSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchKeypress(e: KeyboardEvent) {
|
function searchKeypress(e: KeyboardEvent) {
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case "Enter":
|
case "Enter":
|
||||||
if (!searchText) {
|
if (!searchText) {
|
||||||
closeSearch()
|
closeSearch();
|
||||||
} else if (displayedPages.length) {
|
} else if (displayedWebsites.length) {
|
||||||
window.location.href = rootPath + displayedPages[0].path
|
window.location.href = getWebsiteUrl(displayedWebsites[0].subdomain);
|
||||||
} else {
|
} else {
|
||||||
closeSearch()
|
closeSearch();
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
case "Escape":
|
case "Escape":
|
||||||
clearSearch()
|
clearSearch();
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openInfo() {
|
function openInfo() {
|
||||||
openModal(InfoModal)
|
openModal(InfoModal);
|
||||||
}
|
}
|
||||||
|
|
||||||
let sidebarShown = !isMobile()
|
let sidebarShown = !isMobile();
|
||||||
let searchInput: Focusable
|
let searchInput: Focusable;
|
||||||
let searchOpen = false
|
let searchOpen = false;
|
||||||
let searchText = ""
|
let searchText = "";
|
||||||
|
|
||||||
let displayedPages: TalonPage[]
|
let displayedWebsites: Website[];
|
||||||
$: displayedPages = Object.entries(pages)
|
|
||||||
.filter(([id, page]) => {
|
$: displayedWebsites = websites.filter((ws) => {
|
||||||
if (id === currentPageId) return false
|
if (ws.subdomain == currentWebsite.subdomain) return false;
|
||||||
|
|
||||||
if (searchText) {
|
if (searchText) {
|
||||||
return (
|
return (
|
||||||
page.visibility !== TalonVisibility.HIDDEN &&
|
ws.visibility !== Visibility.Hidden &&
|
||||||
page.name.toLowerCase().includes(searchText.toLowerCase())
|
ws.name.toLowerCase().includes(searchText.toLowerCase())
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
return page.visibility === TalonVisibility.FEATURED
|
return ws.visibility === Visibility.Featured;
|
||||||
})
|
});
|
||||||
.map(([, page]) => page)
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -128,25 +138,22 @@
|
||||||
bind:text={searchText} />
|
bind:text={searchText} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{#each displayedPages as page, i}
|
{#each displayedWebsites as website, i}
|
||||||
<MenuItemPage
|
<MenuItemPage {website} active={searchOpen && searchText && i === 0} />
|
||||||
{page}
|
|
||||||
{rootPath}
|
|
||||||
active={searchOpen && searchText && i === 0} />
|
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{#if currentPage && currentPage.source}
|
{#if currentWebsite && currentWebsite.sourceUrl}
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text="View source"
|
text="View source"
|
||||||
link={currentPage.source.url}
|
link={currentWebsite.sourceUrl}
|
||||||
newTab={true}
|
newTab={true}
|
||||||
privacy={true}>
|
privacy={true}>
|
||||||
<Icon iconName={currentPage.source.type} size={40} scale={0.6} />
|
<Icon iconName={currentWebsite.sourceIcon} size={40} scale={0.6} />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{/if}
|
{/if}
|
||||||
<MenuItem text="Info" on:click={openInfo}>
|
<MenuItem text="Info" on:click={openInfo}>
|
||||||
<PageIcon page={currentPage} />
|
<PageIcon website={currentWebsite} />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem text="Hide sidebar" on:click={hideSidebar}>
|
<MenuItem text="Hide sidebar" on:click={hideSidebar}>
|
||||||
<Icon iconName="arrowRight" size={40} scale={0.6} />
|
<Icon iconName="arrowRight" size={40} scale={0.6} />
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {TalonPage} from "../util/types"
|
import PageIcon from "./PageIcon.svelte";
|
||||||
import PageIcon from "./PageIcon.svelte"
|
import MenuItem from "./MenuItem.svelte";
|
||||||
import MenuItem from "./MenuItem.svelte"
|
import type { Website } from "talon-client";
|
||||||
|
import { getWebsiteUrl } from "../util/functions";
|
||||||
|
|
||||||
export let page: TalonPage
|
export let website: Website;
|
||||||
export let rootPath = "/"
|
export let active = false;
|
||||||
export let active = false
|
|
||||||
|
|
||||||
const MAX_TEXT_LEN = 20
|
const MAX_TEXT_LEN = 20;
|
||||||
|
|
||||||
let text: string
|
let text: string;
|
||||||
$: text =
|
$: text =
|
||||||
page.name.length > MAX_TEXT_LEN
|
website.name.length > MAX_TEXT_LEN
|
||||||
? page.name.substr(0, 20).trim() + "..."
|
? website.name.substring(0, 20).trim() + "..."
|
||||||
: page.name
|
: website.name;
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<MenuItem {active} {text} link={rootPath + page.path}>
|
<MenuItem {active} {text} link={getWebsiteUrl(website.subdomain)}>
|
||||||
<PageIcon {page} />
|
<PageIcon {website} />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ImageIcon from "./ImageIcon.svelte"
|
import ImageIcon from "./ImageIcon.svelte"
|
||||||
import Icon from "./Icon.svelte"
|
import Icon from "./Icon.svelte"
|
||||||
import type {TalonPage} from "../util/types"
|
import type { Website } from "ui/apiclient";
|
||||||
|
|
||||||
export let page: TalonPage
|
export let website: Website
|
||||||
export let size = 40
|
export let size = 40
|
||||||
export let scale = 0.8
|
export let scale = 0.8
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if page}
|
{#if website}
|
||||||
<ImageIcon
|
<ImageIcon
|
||||||
imageSrc={page.image}
|
imageSrc=""
|
||||||
color={page.color}
|
color={website.color}
|
||||||
alt={page.name.substr(0, 2)}
|
alt={website.name.substring(0, 2)}
|
||||||
{size}
|
{size}
|
||||||
{scale} />
|
{scale} />
|
||||||
{:else}
|
{:else}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const sidebar = document.createElement("talon-sidebar")
|
const sidebar = document.createElement("talon-sidebar");
|
||||||
document.body.append(sidebar)
|
document.body.append(sidebar);
|
||||||
|
|
||||||
export {default as default} from "./App.svelte"
|
export { default as default } from "./App.svelte";
|
||||||
|
|
18
ui/menu/src/util/api.ts
Normal file
18
ui/menu/src/util/api.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import {Writable, writable} from "svelte/store"
|
||||||
|
|
||||||
|
import {Configuration, DefaultApi, Website} from "talon-client"
|
||||||
|
import {getSubdomain} from "./functions"
|
||||||
|
import { talonConfig } from "./talonData"
|
||||||
|
|
||||||
|
export const websitesStore: Writable<Website[]> = writable([])
|
||||||
|
export const currentWebsiteStore: Writable<Website> = writable(null)
|
||||||
|
|
||||||
|
export const client = new DefaultApi(new Configuration({basePath: talonConfig.api}));
|
||||||
|
|
||||||
|
export function fetchWebsites(): void {
|
||||||
|
client.websitesGet().then((ws) => {
|
||||||
|
websitesStore.set(ws)
|
||||||
|
const subdomain = getSubdomain()
|
||||||
|
currentWebsiteStore.set(ws.find((w) => w.subdomain == subdomain))
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,5 +1,41 @@
|
||||||
function formatDate(dateString: string): string {
|
import {talonConfig} from "./talonData"
|
||||||
return new Date(dateString).toLocaleString(navigator.language)
|
|
||||||
|
export function formatDate(date: Date): string {
|
||||||
|
return date.toLocaleString(navigator.language)
|
||||||
}
|
}
|
||||||
|
|
||||||
export {formatDate}
|
export function getSubdomain(): string {
|
||||||
|
const hn = window.location.hostname
|
||||||
|
const rd_noport = talonConfig.root_domain.split(":", 1)[0]
|
||||||
|
|
||||||
|
if (hn.endsWith("." + rd_noport)) {
|
||||||
|
const subdomain = hn.substring(0, hn.length - rd_noport.length - 1).split("--", 1)[0]
|
||||||
|
if (subdomain === "x") {
|
||||||
|
return "-"
|
||||||
|
} else {
|
||||||
|
return subdomain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "-"
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getWebsiteUrl(subdomain: string): string {
|
||||||
|
const proto = window.location.protocol
|
||||||
|
|
||||||
|
if (subdomain === "-") {
|
||||||
|
return `${proto}//${talonConfig.root_domain}`
|
||||||
|
} else {
|
||||||
|
return `${proto}//${subdomain}.${talonConfig.root_domain}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getWebsiteVersionUrl(subdomain: string, version: number): string {
|
||||||
|
const proto = window.location.protocol
|
||||||
|
const v = `--v${version}`
|
||||||
|
|
||||||
|
if (subdomain === "-") {
|
||||||
|
return `${proto}//x${v}.${talonConfig.root_domain}`
|
||||||
|
} else {
|
||||||
|
return `${proto}//${subdomain}${v}.${talonConfig.root_domain}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,54 +1,33 @@
|
||||||
import type {TalonData, TalonPage, TalonVersion} from "./types"
|
import type {TalonConfig} from "./types"
|
||||||
import {TalonVisibility} from "./types"
|
|
||||||
|
|
||||||
const talonData: TalonData = JSON.parse(
|
export const talonConfig: TalonConfig = JSON.parse(
|
||||||
document.getElementById("talon-data").textContent
|
document.getElementById("talon-config").textContent
|
||||||
) as TalonData
|
) as TalonConfig
|
||||||
|
|
||||||
const isTalonData = (obj: TalonData) =>
|
// const rootPath = talonData.root_path
|
||||||
"root_path" in obj &&
|
|
||||||
"current_page" in obj &&
|
|
||||||
"current_version" in obj &&
|
|
||||||
"versions" in obj &&
|
|
||||||
"pages" in obj
|
|
||||||
|
|
||||||
const isTalonVersion = (obj: TalonVersion) => "date" in obj && "user" in obj
|
// const currentVersion = talonData.versions[talonData.current_version]
|
||||||
|
// const currentVersionId = talonData.current_version
|
||||||
|
|
||||||
const rootPath = talonData.root_path
|
// const getCurrentPage = () => {
|
||||||
|
// if (talonData.current_page) {
|
||||||
|
// return talonData.pages[talonData.current_page]
|
||||||
|
// } else {
|
||||||
|
// return {
|
||||||
|
// name: "#" + talonData.current_version,
|
||||||
|
// path: "&v/" + talonData.current_version,
|
||||||
|
// color: "#7935df",
|
||||||
|
// visibility: TalonVisibility.HIDDEN,
|
||||||
|
// image: undefined,
|
||||||
|
// source: undefined,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
const currentVersion = talonData.versions[talonData.current_version]
|
// const currentPage: TalonPage = getCurrentPage()
|
||||||
const currentVersionId = talonData.current_version
|
// const currentPageId = talonData.current_page
|
||||||
|
|
||||||
const getCurrentPage = () => {
|
// const isPresent = isTalonData(talonData) && isTalonVersion(currentVersion)
|
||||||
if (talonData.current_page) {
|
|
||||||
return talonData.pages[talonData.current_page]
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
name: "#" + talonData.current_version,
|
|
||||||
path: "&v/" + talonData.current_version,
|
|
||||||
color: "#7935df",
|
|
||||||
visibility: TalonVisibility.HIDDEN,
|
|
||||||
image: undefined,
|
|
||||||
source: undefined,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentPage: TalonPage = getCurrentPage()
|
// const versions = talonData.versions
|
||||||
const currentPageId = talonData.current_page
|
// const pages = talonData.pages
|
||||||
|
|
||||||
const isPresent = isTalonData(talonData) && isTalonVersion(currentVersion)
|
|
||||||
|
|
||||||
const versions = talonData.versions
|
|
||||||
const pages = talonData.pages
|
|
||||||
|
|
||||||
export {
|
|
||||||
rootPath,
|
|
||||||
isPresent,
|
|
||||||
currentVersion,
|
|
||||||
currentVersionId,
|
|
||||||
currentPage,
|
|
||||||
currentPageId,
|
|
||||||
versions,
|
|
||||||
pages,
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,54 +1,15 @@
|
||||||
export interface TalonData {
|
export interface TalonConfig {
|
||||||
root_path: string
|
api: string;
|
||||||
current_page: string | null
|
version: string;
|
||||||
current_version: string
|
root_domain: string;
|
||||||
versions: {[key: string]: TalonVersion}
|
|
||||||
pages: {[key: string]: TalonPage}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TalonPage {
|
|
||||||
name: string
|
|
||||||
path: string
|
|
||||||
color: string
|
|
||||||
visibility: TalonVisibility
|
|
||||||
image: string | undefined
|
|
||||||
source: TalonLink | undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum TalonVisibility {
|
|
||||||
FEATURED = "featured",
|
|
||||||
SEARCHABLE = "searchable",
|
|
||||||
HIDDEN = "hidden",
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TalonLink {
|
|
||||||
url: string
|
|
||||||
type: TalonLinkType
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum TalonLinkType {
|
|
||||||
LINK = "link",
|
|
||||||
GIT = "git",
|
|
||||||
GITHUB = "github",
|
|
||||||
GITLAB = "gitlab",
|
|
||||||
GITEA = "gitea",
|
|
||||||
BITBUCKET = "bitbucket",
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TalonVersion {
|
|
||||||
date: string
|
|
||||||
name: string | undefined
|
|
||||||
user: string
|
|
||||||
tags: {[key: string]: string} | undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Focusable {
|
export interface Focusable {
|
||||||
focus(): void
|
focus(): void;
|
||||||
blur(): void
|
blur(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SvelteActionRes {
|
export interface SvelteActionRes {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
update?: (parameters: any) => void
|
update?: (parameters: any) => void;
|
||||||
destroy?: () => void
|
destroy?: () => void;
|
||||||
}
|
}
|
||||||
|
|
90
ui/menu/testdata/test.json
vendored
90
ui/menu/testdata/test.json
vendored
|
@ -1,90 +0,0 @@
|
||||||
{
|
|
||||||
"root_path": "/",
|
|
||||||
"current_page": null,
|
|
||||||
"current_version": "6",
|
|
||||||
"versions": {
|
|
||||||
"3": {
|
|
||||||
"date": "2021-06-15T11:12:21+00:00",
|
|
||||||
"name": "0.1.0",
|
|
||||||
"user": "ThetaDev",
|
|
||||||
"tags": {
|
|
||||||
"commit": "ec55eba5ae45640c3d225c2471920fd3c9a36489"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"date": "2021-06-20T16:48:21+00:00",
|
|
||||||
"name": "0.1.1",
|
|
||||||
"user": "ThetaDev",
|
|
||||||
"tags": {
|
|
||||||
"commit": "ec55eba5ae45640c3d225c2471920fd3c9a36489"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"date": "2021-06-22T12:08:21+00:00",
|
|
||||||
"name": "0.1.2",
|
|
||||||
"user": "ThetaDev",
|
|
||||||
"tags": {
|
|
||||||
"commit": "ec55eba5ae45640c3d225c2471920fd3c9a36489"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"date": "2021-07-02T16:12:40+00:00",
|
|
||||||
"name": "0.1.3",
|
|
||||||
"user": "ThetaDev",
|
|
||||||
"tags": {
|
|
||||||
"commit": "bbc7342580b48433481857bfe95e58784a508275"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pages": {
|
|
||||||
"1": {
|
|
||||||
"name": "ThetaDev",
|
|
||||||
"path": "",
|
|
||||||
"color": "#1f91ee",
|
|
||||||
"visibility": "featured",
|
|
||||||
"source": {
|
|
||||||
"url": "https://github.com/Theta-Dev",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"name": "Talon",
|
|
||||||
"path": "Talon",
|
|
||||||
"color": "#4b228a",
|
|
||||||
"visibility": "featured",
|
|
||||||
"source": {
|
|
||||||
"url": "https://github.com/Theta-Dev/Talon",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"name": "Spotify-Gender-Ex",
|
|
||||||
"path": "Spotify-Gender-Ex",
|
|
||||||
"color": "#1DB954",
|
|
||||||
"image": "https://raw.githubusercontent.com/Theta-Dev/Spotify-Gender-Ex/master/assets/logo_square.svg",
|
|
||||||
"visibility": "featured",
|
|
||||||
"source": {
|
|
||||||
"url": "https://github.com/Theta-Dev/Spotify-Gender-Ex",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"4": {
|
|
||||||
"name": "A1",
|
|
||||||
"path": "tests/a1",
|
|
||||||
"color": "#ff0000",
|
|
||||||
"visibility": "searchable"
|
|
||||||
},
|
|
||||||
"5": {
|
|
||||||
"name": "B1",
|
|
||||||
"path": "tests/b1",
|
|
||||||
"color": "#00ff00",
|
|
||||||
"visibility": "searchable"
|
|
||||||
},
|
|
||||||
"6": {
|
|
||||||
"name": "C1",
|
|
||||||
"path": "tests/c1",
|
|
||||||
"color": "#0000ff",
|
|
||||||
"visibility": "searchable"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
99
ui/menu/testdata/testSchema.json
vendored
99
ui/menu/testdata/testSchema.json
vendored
|
@ -1,99 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
||||||
"title": "Talon menu data",
|
|
||||||
"definitions": {
|
|
||||||
"Version": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"date": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "date-time"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"user": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"tags": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["date", "user"]
|
|
||||||
},
|
|
||||||
"Link": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"url": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["link", "git", "github", "gitlab", "gitea", "bitbucket"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["url", "type"]
|
|
||||||
},
|
|
||||||
"Page": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 100
|
|
||||||
},
|
|
||||||
"path": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"color": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "regex",
|
|
||||||
"pattern": "^#[A-z\\d]{6}$"
|
|
||||||
},
|
|
||||||
"image": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "uri"
|
|
||||||
},
|
|
||||||
"visibility": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["featured", "searchable", "hidden"]
|
|
||||||
},
|
|
||||||
"source": {
|
|
||||||
"$ref": "#/definitions/Link"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["name", "path", "color", "visibility"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"oneOf": [
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"root_path": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"current_page": {
|
|
||||||
"type": ["string", "null"]
|
|
||||||
},
|
|
||||||
"current_version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"versions": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"$ref": "#/definitions/Version"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pages": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"$ref": "#/definitions/Page"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["root_path", "current_page", "current_version", "versions", "pages"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
4
ui/talon-client/.gitignore
vendored
Normal file
4
ui/talon-client/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
wwwroot/*.js
|
||||||
|
node_modules
|
||||||
|
typings
|
||||||
|
dist
|
1
ui/talon-client/.npmignore
Normal file
1
ui/talon-client/.npmignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
README.md
|
23
ui/talon-client/.openapi-generator-ignore
Normal file
23
ui/talon-client/.openapi-generator-ignore
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# OpenAPI Generator Ignore
|
||||||
|
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||||
|
|
||||||
|
# Use this file to prevent files from being overwritten by the generator.
|
||||||
|
# The patterns follow closely to .gitignore or .dockerignore.
|
||||||
|
|
||||||
|
# As an example, the C# client generator defines ApiClient.cs.
|
||||||
|
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||||
|
#ApiClient.cs
|
||||||
|
|
||||||
|
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||||
|
#foo/*/qux
|
||||||
|
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||||
|
|
||||||
|
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||||
|
#foo/**/qux
|
||||||
|
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||||
|
|
||||||
|
# You can also negate patterns with an exclamation (!).
|
||||||
|
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||||
|
#docs/*.md
|
||||||
|
# Then explicitly reverse the ignore rule for a single file:
|
||||||
|
#!docs/README.md
|
23
ui/talon-client/.openapi-generator/FILES
Normal file
23
ui/talon-client/.openapi-generator/FILES
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
.gitignore
|
||||||
|
.npmignore
|
||||||
|
.openapi-generator-ignore
|
||||||
|
README.md
|
||||||
|
package.json
|
||||||
|
src/apis/DefaultApi.ts
|
||||||
|
src/apis/index.ts
|
||||||
|
src/index.ts
|
||||||
|
src/models/Info.ts
|
||||||
|
src/models/InfoStats.ts
|
||||||
|
src/models/InfoVersion.ts
|
||||||
|
src/models/SourceIcon.ts
|
||||||
|
src/models/Stats.ts
|
||||||
|
src/models/Version.ts
|
||||||
|
src/models/VersionFile.ts
|
||||||
|
src/models/VersionInfo.ts
|
||||||
|
src/models/Visibility.ts
|
||||||
|
src/models/Website.ts
|
||||||
|
src/models/WebsiteNew.ts
|
||||||
|
src/models/WebsiteUpdate.ts
|
||||||
|
src/models/index.ts
|
||||||
|
src/runtime.ts
|
||||||
|
tsconfig.json
|
1
ui/talon-client/.openapi-generator/VERSION
Normal file
1
ui/talon-client/.openapi-generator/VERSION
Normal file
|
@ -0,0 +1 @@
|
||||||
|
6.4.0
|
45
ui/talon-client/README.md
Normal file
45
ui/talon-client/README.md
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
## talon-client@0.1.0
|
||||||
|
|
||||||
|
This generator creates TypeScript/JavaScript client that utilizes [Fetch API](https://fetch.spec.whatwg.org/). The generated Node module can be used in the following environments:
|
||||||
|
|
||||||
|
Environment
|
||||||
|
* Node.js
|
||||||
|
* Webpack
|
||||||
|
* Browserify
|
||||||
|
|
||||||
|
Language level
|
||||||
|
* ES5 - you must have a Promises/A+ library installed
|
||||||
|
* ES6
|
||||||
|
|
||||||
|
Module system
|
||||||
|
* CommonJS
|
||||||
|
* ES6 module system
|
||||||
|
|
||||||
|
It can be used in both TypeScript and JavaScript. In TypeScript, the definition should be automatically resolved via `package.json`. ([Reference](http://www.typescriptlang.org/docs/handbook/typings-for-npm-packages.html))
|
||||||
|
|
||||||
|
### Building
|
||||||
|
|
||||||
|
To build and compile the typescript sources to javascript use:
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Publishing
|
||||||
|
|
||||||
|
First build the package then run ```npm publish```
|
||||||
|
|
||||||
|
### Consuming
|
||||||
|
|
||||||
|
navigate to the folder of your consuming project and run one of the following commands.
|
||||||
|
|
||||||
|
_published:_
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install talon-client@0.1.0 --save
|
||||||
|
```
|
||||||
|
|
||||||
|
_unPublished (not recommended):_
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install PATH_TO_GENERATED_PACKAGE --save
|
28
ui/talon-client/package-lock.json
generated
Normal file
28
ui/talon-client/package-lock.json
generated
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"name": "talon-client",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "talon-client",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"version": "4.9.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||||
|
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
ui/talon-client/package.json
Normal file
19
ui/talon-client/package.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "talon-client",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "OpenAPI client for talon-client",
|
||||||
|
"author": "OpenAPI-Generator",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/GIT_USER_ID/GIT_REPO_ID.git"
|
||||||
|
},
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"typings": "./dist/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"prepare": "npm run build"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^4.0"
|
||||||
|
}
|
||||||
|
}
|
559
ui/talon-client/src/apis/DefaultApi.ts
Normal file
559
ui/talon-client/src/apis/DefaultApi.ts
Normal file
|
@ -0,0 +1,559 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import * as runtime from '../runtime';
|
||||||
|
import type {
|
||||||
|
Info,
|
||||||
|
Version,
|
||||||
|
VersionFile,
|
||||||
|
Visibility,
|
||||||
|
Website,
|
||||||
|
WebsiteNew,
|
||||||
|
WebsiteUpdate,
|
||||||
|
} from '../models';
|
||||||
|
import {
|
||||||
|
InfoFromJSON,
|
||||||
|
InfoToJSON,
|
||||||
|
VersionFromJSON,
|
||||||
|
VersionToJSON,
|
||||||
|
VersionFileFromJSON,
|
||||||
|
VersionFileToJSON,
|
||||||
|
VisibilityFromJSON,
|
||||||
|
VisibilityToJSON,
|
||||||
|
WebsiteFromJSON,
|
||||||
|
WebsiteToJSON,
|
||||||
|
WebsiteNewFromJSON,
|
||||||
|
WebsiteNewToJSON,
|
||||||
|
WebsiteUpdateFromJSON,
|
||||||
|
WebsiteUpdateToJSON,
|
||||||
|
} from '../models';
|
||||||
|
|
||||||
|
export interface FileHashGetRequest {
|
||||||
|
hash: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebsiteSubdomainDeleteRequest {
|
||||||
|
subdomain: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebsiteSubdomainGetRequest {
|
||||||
|
subdomain: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebsiteSubdomainPatchRequest {
|
||||||
|
subdomain: string;
|
||||||
|
websiteUpdate: WebsiteUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebsiteSubdomainPutRequest {
|
||||||
|
subdomain: string;
|
||||||
|
websiteNew: WebsiteNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebsiteSubdomainUploadPostRequest {
|
||||||
|
subdomain: string;
|
||||||
|
body: Blob;
|
||||||
|
fallback?: string;
|
||||||
|
spa?: boolean;
|
||||||
|
versionData?: { [key: string]: string; };
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebsiteSubdomainVersionVersionDeleteRequest {
|
||||||
|
subdomain: string;
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebsiteSubdomainVersionVersionFilesGetRequest {
|
||||||
|
subdomain: string;
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebsiteSubdomainVersionVersionGetRequest {
|
||||||
|
subdomain: string;
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebsiteSubdomainVersionsGetRequest {
|
||||||
|
subdomain: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebsitesAllGetRequest {
|
||||||
|
visibility?: Visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebsitesGetRequest {
|
||||||
|
visibility?: Visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export class DefaultApi extends runtime.BaseAPI {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a file
|
||||||
|
*/
|
||||||
|
async fileHashGetRaw(requestParameters: FileHashGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Blob>> {
|
||||||
|
if (requestParameters.hash === null || requestParameters.hash === undefined) {
|
||||||
|
throw new runtime.RequiredError('hash','Required parameter requestParameters.hash was null or undefined when calling fileHashGet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: `/file/{hash}`.replace(`{${"hash"}}`, encodeURIComponent(String(requestParameters.hash))),
|
||||||
|
method: 'GET',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
return new runtime.BlobApiResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a file
|
||||||
|
*/
|
||||||
|
async fileHashGet(requestParameters: FileHashGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Blob> {
|
||||||
|
const response = await this.fileHashGetRaw(requestParameters, initOverrides);
|
||||||
|
return await response.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get information about your server
|
||||||
|
*/
|
||||||
|
async infoGetRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Info>> {
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: `/info`,
|
||||||
|
method: 'GET',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
return new runtime.JSONApiResponse(response, (jsonValue) => InfoFromJSON(jsonValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get information about your server
|
||||||
|
*/
|
||||||
|
async infoGet(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Info> {
|
||||||
|
const response = await this.infoGetRaw(initOverrides);
|
||||||
|
return await response.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete website
|
||||||
|
*/
|
||||||
|
async websiteSubdomainDeleteRaw(requestParameters: WebsiteSubdomainDeleteRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<void>> {
|
||||||
|
if (requestParameters.subdomain === null || requestParameters.subdomain === undefined) {
|
||||||
|
throw new runtime.RequiredError('subdomain','Required parameter requestParameters.subdomain was null or undefined when calling websiteSubdomainDelete.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
if (this.configuration && this.configuration.apiKey) {
|
||||||
|
headerParameters["X-API-Key"] = this.configuration.apiKey("X-API-Key"); // ApiKeyAuthorization authentication
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: `/website/{subdomain}`.replace(`{${"subdomain"}}`, encodeURIComponent(String(requestParameters.subdomain))),
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
return new runtime.VoidApiResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete website
|
||||||
|
*/
|
||||||
|
async websiteSubdomainDelete(requestParameters: WebsiteSubdomainDeleteRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<void> {
|
||||||
|
await this.websiteSubdomainDeleteRaw(requestParameters, initOverrides);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a website
|
||||||
|
*/
|
||||||
|
async websiteSubdomainGetRaw(requestParameters: WebsiteSubdomainGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Website>> {
|
||||||
|
if (requestParameters.subdomain === null || requestParameters.subdomain === undefined) {
|
||||||
|
throw new runtime.RequiredError('subdomain','Required parameter requestParameters.subdomain was null or undefined when calling websiteSubdomainGet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: `/website/{subdomain}`.replace(`{${"subdomain"}}`, encodeURIComponent(String(requestParameters.subdomain))),
|
||||||
|
method: 'GET',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
return new runtime.JSONApiResponse(response, (jsonValue) => WebsiteFromJSON(jsonValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a website
|
||||||
|
*/
|
||||||
|
async websiteSubdomainGet(requestParameters: WebsiteSubdomainGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Website> {
|
||||||
|
const response = await this.websiteSubdomainGetRaw(requestParameters, initOverrides);
|
||||||
|
return await response.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update website
|
||||||
|
*/
|
||||||
|
async websiteSubdomainPatchRaw(requestParameters: WebsiteSubdomainPatchRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<void>> {
|
||||||
|
if (requestParameters.subdomain === null || requestParameters.subdomain === undefined) {
|
||||||
|
throw new runtime.RequiredError('subdomain','Required parameter requestParameters.subdomain was null or undefined when calling websiteSubdomainPatch.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestParameters.websiteUpdate === null || requestParameters.websiteUpdate === undefined) {
|
||||||
|
throw new runtime.RequiredError('websiteUpdate','Required parameter requestParameters.websiteUpdate was null or undefined when calling websiteSubdomainPatch.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
headerParameters['Content-Type'] = 'application/json; charset=utf-8';
|
||||||
|
|
||||||
|
if (this.configuration && this.configuration.apiKey) {
|
||||||
|
headerParameters["X-API-Key"] = this.configuration.apiKey("X-API-Key"); // ApiKeyAuthorization authentication
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: `/website/{subdomain}`.replace(`{${"subdomain"}}`, encodeURIComponent(String(requestParameters.subdomain))),
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
body: WebsiteUpdateToJSON(requestParameters.websiteUpdate),
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
return new runtime.VoidApiResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update website
|
||||||
|
*/
|
||||||
|
async websiteSubdomainPatch(requestParameters: WebsiteSubdomainPatchRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<void> {
|
||||||
|
await this.websiteSubdomainPatchRaw(requestParameters, initOverrides);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new website
|
||||||
|
*/
|
||||||
|
async websiteSubdomainPutRaw(requestParameters: WebsiteSubdomainPutRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<void>> {
|
||||||
|
if (requestParameters.subdomain === null || requestParameters.subdomain === undefined) {
|
||||||
|
throw new runtime.RequiredError('subdomain','Required parameter requestParameters.subdomain was null or undefined when calling websiteSubdomainPut.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestParameters.websiteNew === null || requestParameters.websiteNew === undefined) {
|
||||||
|
throw new runtime.RequiredError('websiteNew','Required parameter requestParameters.websiteNew was null or undefined when calling websiteSubdomainPut.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
headerParameters['Content-Type'] = 'application/json; charset=utf-8';
|
||||||
|
|
||||||
|
if (this.configuration && this.configuration.apiKey) {
|
||||||
|
headerParameters["X-API-Key"] = this.configuration.apiKey("X-API-Key"); // ApiKeyAuthorization authentication
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: `/website/{subdomain}`.replace(`{${"subdomain"}}`, encodeURIComponent(String(requestParameters.subdomain))),
|
||||||
|
method: 'PUT',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
body: WebsiteNewToJSON(requestParameters.websiteNew),
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
return new runtime.VoidApiResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new website
|
||||||
|
*/
|
||||||
|
async websiteSubdomainPut(requestParameters: WebsiteSubdomainPutRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<void> {
|
||||||
|
await this.websiteSubdomainPutRaw(requestParameters, initOverrides);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload a new version
|
||||||
|
*/
|
||||||
|
async websiteSubdomainUploadPostRaw(requestParameters: WebsiteSubdomainUploadPostRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<void>> {
|
||||||
|
if (requestParameters.subdomain === null || requestParameters.subdomain === undefined) {
|
||||||
|
throw new runtime.RequiredError('subdomain','Required parameter requestParameters.subdomain was null or undefined when calling websiteSubdomainUploadPost.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestParameters.body === null || requestParameters.body === undefined) {
|
||||||
|
throw new runtime.RequiredError('body','Required parameter requestParameters.body was null or undefined when calling websiteSubdomainUploadPost.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
if (requestParameters.fallback !== undefined) {
|
||||||
|
queryParameters['fallback'] = requestParameters.fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestParameters.spa !== undefined) {
|
||||||
|
queryParameters['spa'] = requestParameters.spa;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestParameters.versionData !== undefined) {
|
||||||
|
queryParameters['version_data'] = requestParameters.versionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
headerParameters['Content-Type'] = 'application/octet-stream';
|
||||||
|
|
||||||
|
if (this.configuration && this.configuration.apiKey) {
|
||||||
|
headerParameters["X-API-Key"] = this.configuration.apiKey("X-API-Key"); // ApiKeyAuthorization authentication
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: `/website/{subdomain}/upload`.replace(`{${"subdomain"}}`, encodeURIComponent(String(requestParameters.subdomain))),
|
||||||
|
method: 'POST',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
body: requestParameters.body as any,
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
return new runtime.VoidApiResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload a new version
|
||||||
|
*/
|
||||||
|
async websiteSubdomainUploadPost(requestParameters: WebsiteSubdomainUploadPostRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<void> {
|
||||||
|
await this.websiteSubdomainUploadPostRaw(requestParameters, initOverrides);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete version
|
||||||
|
*/
|
||||||
|
async websiteSubdomainVersionVersionDeleteRaw(requestParameters: WebsiteSubdomainVersionVersionDeleteRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<void>> {
|
||||||
|
if (requestParameters.subdomain === null || requestParameters.subdomain === undefined) {
|
||||||
|
throw new runtime.RequiredError('subdomain','Required parameter requestParameters.subdomain was null or undefined when calling websiteSubdomainVersionVersionDelete.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestParameters.version === null || requestParameters.version === undefined) {
|
||||||
|
throw new runtime.RequiredError('version','Required parameter requestParameters.version was null or undefined when calling websiteSubdomainVersionVersionDelete.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
if (this.configuration && this.configuration.apiKey) {
|
||||||
|
headerParameters["X-API-Key"] = this.configuration.apiKey("X-API-Key"); // ApiKeyAuthorization authentication
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: `/website/{subdomain}/version/{version}`.replace(`{${"subdomain"}}`, encodeURIComponent(String(requestParameters.subdomain))).replace(`{${"version"}}`, encodeURIComponent(String(requestParameters.version))),
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
return new runtime.VoidApiResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete version
|
||||||
|
*/
|
||||||
|
async websiteSubdomainVersionVersionDelete(requestParameters: WebsiteSubdomainVersionVersionDeleteRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<void> {
|
||||||
|
await this.websiteSubdomainVersionVersionDeleteRaw(requestParameters, initOverrides);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get version files
|
||||||
|
*/
|
||||||
|
async websiteSubdomainVersionVersionFilesGetRaw(requestParameters: WebsiteSubdomainVersionVersionFilesGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Array<VersionFile>>> {
|
||||||
|
if (requestParameters.subdomain === null || requestParameters.subdomain === undefined) {
|
||||||
|
throw new runtime.RequiredError('subdomain','Required parameter requestParameters.subdomain was null or undefined when calling websiteSubdomainVersionVersionFilesGet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestParameters.version === null || requestParameters.version === undefined) {
|
||||||
|
throw new runtime.RequiredError('version','Required parameter requestParameters.version was null or undefined when calling websiteSubdomainVersionVersionFilesGet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: `/website/{subdomain}/version/{version}/files`.replace(`{${"subdomain"}}`, encodeURIComponent(String(requestParameters.subdomain))).replace(`{${"version"}}`, encodeURIComponent(String(requestParameters.version))),
|
||||||
|
method: 'GET',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(VersionFileFromJSON));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get version files
|
||||||
|
*/
|
||||||
|
async websiteSubdomainVersionVersionFilesGet(requestParameters: WebsiteSubdomainVersionVersionFilesGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Array<VersionFile>> {
|
||||||
|
const response = await this.websiteSubdomainVersionVersionFilesGetRaw(requestParameters, initOverrides);
|
||||||
|
return await response.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get version
|
||||||
|
*/
|
||||||
|
async websiteSubdomainVersionVersionGetRaw(requestParameters: WebsiteSubdomainVersionVersionGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Version>> {
|
||||||
|
if (requestParameters.subdomain === null || requestParameters.subdomain === undefined) {
|
||||||
|
throw new runtime.RequiredError('subdomain','Required parameter requestParameters.subdomain was null or undefined when calling websiteSubdomainVersionVersionGet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestParameters.version === null || requestParameters.version === undefined) {
|
||||||
|
throw new runtime.RequiredError('version','Required parameter requestParameters.version was null or undefined when calling websiteSubdomainVersionVersionGet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: `/website/{subdomain}/version/{version}`.replace(`{${"subdomain"}}`, encodeURIComponent(String(requestParameters.subdomain))).replace(`{${"version"}}`, encodeURIComponent(String(requestParameters.version))),
|
||||||
|
method: 'GET',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
return new runtime.JSONApiResponse(response, (jsonValue) => VersionFromJSON(jsonValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get version
|
||||||
|
*/
|
||||||
|
async websiteSubdomainVersionVersionGet(requestParameters: WebsiteSubdomainVersionVersionGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Version> {
|
||||||
|
const response = await this.websiteSubdomainVersionVersionGetRaw(requestParameters, initOverrides);
|
||||||
|
return await response.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get website versions
|
||||||
|
*/
|
||||||
|
async websiteSubdomainVersionsGetRaw(requestParameters: WebsiteSubdomainVersionsGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Array<Version>>> {
|
||||||
|
if (requestParameters.subdomain === null || requestParameters.subdomain === undefined) {
|
||||||
|
throw new runtime.RequiredError('subdomain','Required parameter requestParameters.subdomain was null or undefined when calling websiteSubdomainVersionsGet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: `/website/{subdomain}/versions`.replace(`{${"subdomain"}}`, encodeURIComponent(String(requestParameters.subdomain))),
|
||||||
|
method: 'GET',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(VersionFromJSON));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get website versions
|
||||||
|
*/
|
||||||
|
async websiteSubdomainVersionsGet(requestParameters: WebsiteSubdomainVersionsGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Array<Version>> {
|
||||||
|
const response = await this.websiteSubdomainVersionsGetRaw(requestParameters, initOverrides);
|
||||||
|
return await response.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all websites from Talon\'s database (including hidden ones, if the current user has access to them). This endpoint requires authentication (use the `/websites` endpoint for unauthenticated users).
|
||||||
|
* Get all websites
|
||||||
|
*/
|
||||||
|
async websitesAllGetRaw(requestParameters: WebsitesAllGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Array<Website>>> {
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
if (requestParameters.visibility !== undefined) {
|
||||||
|
queryParameters['visibility'] = requestParameters.visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
if (this.configuration && this.configuration.apiKey) {
|
||||||
|
headerParameters["X-API-Key"] = this.configuration.apiKey("X-API-Key"); // ApiKeyAuthorization authentication
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: `/websitesAll`,
|
||||||
|
method: 'GET',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(WebsiteFromJSON));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all websites from Talon\'s database (including hidden ones, if the current user has access to them). This endpoint requires authentication (use the `/websites` endpoint for unauthenticated users).
|
||||||
|
* Get all websites
|
||||||
|
*/
|
||||||
|
async websitesAllGet(requestParameters: WebsitesAllGetRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Array<Website>> {
|
||||||
|
const response = await this.websitesAllGetRaw(requestParameters, initOverrides);
|
||||||
|
return await response.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all publicly listed websites (visibility != `hidden`)
|
||||||
|
* Get all publicly listed websites
|
||||||
|
*/
|
||||||
|
async websitesGetRaw(requestParameters: WebsitesGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Array<Website>>> {
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
if (requestParameters.visibility !== undefined) {
|
||||||
|
queryParameters['visibility'] = requestParameters.visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: `/websites`,
|
||||||
|
method: 'GET',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(WebsiteFromJSON));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all publicly listed websites (visibility != `hidden`)
|
||||||
|
* Get all publicly listed websites
|
||||||
|
*/
|
||||||
|
async websitesGet(requestParameters: WebsitesGetRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Array<Website>> {
|
||||||
|
const response = await this.websitesGetRaw(requestParameters, initOverrides);
|
||||||
|
return await response.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
3
ui/talon-client/src/apis/index.ts
Normal file
3
ui/talon-client/src/apis/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export * from './DefaultApi';
|
5
ui/talon-client/src/index.ts
Normal file
5
ui/talon-client/src/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export * from './runtime';
|
||||||
|
export * from './apis';
|
||||||
|
export * from './models';
|
96
ui/talon-client/src/models/Info.ts
Normal file
96
ui/talon-client/src/models/Info.ts
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { exists, mapValues } from '../runtime';
|
||||||
|
import type { InfoStats } from './InfoStats';
|
||||||
|
import {
|
||||||
|
InfoStatsFromJSON,
|
||||||
|
InfoStatsFromJSONTyped,
|
||||||
|
InfoStatsToJSON,
|
||||||
|
} from './InfoStats';
|
||||||
|
import type { InfoVersion } from './InfoVersion';
|
||||||
|
import {
|
||||||
|
InfoVersionFromJSON,
|
||||||
|
InfoVersionFromJSONTyped,
|
||||||
|
InfoVersionToJSON,
|
||||||
|
} from './InfoVersion';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server information
|
||||||
|
* @export
|
||||||
|
* @interface Info
|
||||||
|
*/
|
||||||
|
export interface Info {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {InfoStats}
|
||||||
|
* @memberof Info
|
||||||
|
*/
|
||||||
|
stats: InfoStats;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {InfoVersion}
|
||||||
|
* @memberof Info
|
||||||
|
*/
|
||||||
|
version: InfoVersion;
|
||||||
|
/**
|
||||||
|
* Current uptime of the server in seconds
|
||||||
|
* @type {number}
|
||||||
|
* @memberof Info
|
||||||
|
*/
|
||||||
|
uptime: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the Info interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfInfo(value: object): boolean {
|
||||||
|
let isInstance = true;
|
||||||
|
isInstance = isInstance && "stats" in value;
|
||||||
|
isInstance = isInstance && "version" in value;
|
||||||
|
isInstance = isInstance && "uptime" in value;
|
||||||
|
|
||||||
|
return isInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InfoFromJSON(json: any): Info {
|
||||||
|
return InfoFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InfoFromJSONTyped(json: any, ignoreDiscriminator: boolean): Info {
|
||||||
|
if ((json === undefined) || (json === null)) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'stats': InfoStatsFromJSON(json['stats']),
|
||||||
|
'version': InfoVersionFromJSON(json['version']),
|
||||||
|
'uptime': json['uptime'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InfoToJSON(value?: Info | null): any {
|
||||||
|
if (value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'stats': InfoStatsToJSON(value.stats),
|
||||||
|
'version': InfoVersionToJSON(value.version),
|
||||||
|
'uptime': value.uptime,
|
||||||
|
};
|
||||||
|
}
|
83
ui/talon-client/src/models/InfoStats.ts
Normal file
83
ui/talon-client/src/models/InfoStats.ts
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { exists, mapValues } from '../runtime';
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface InfoStats
|
||||||
|
*/
|
||||||
|
export interface InfoStats {
|
||||||
|
/**
|
||||||
|
* Number of websites
|
||||||
|
* @type {number}
|
||||||
|
* @memberof InfoStats
|
||||||
|
*/
|
||||||
|
nWebsites: number;
|
||||||
|
/**
|
||||||
|
* Number of unique files
|
||||||
|
* @type {number}
|
||||||
|
* @memberof InfoStats
|
||||||
|
*/
|
||||||
|
nFiles: number;
|
||||||
|
/**
|
||||||
|
* Amount of used storage space (in bytes)
|
||||||
|
* @type {number}
|
||||||
|
* @memberof InfoStats
|
||||||
|
*/
|
||||||
|
storageUsed: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the InfoStats interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfInfoStats(value: object): boolean {
|
||||||
|
let isInstance = true;
|
||||||
|
isInstance = isInstance && "nWebsites" in value;
|
||||||
|
isInstance = isInstance && "nFiles" in value;
|
||||||
|
isInstance = isInstance && "storageUsed" in value;
|
||||||
|
|
||||||
|
return isInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InfoStatsFromJSON(json: any): InfoStats {
|
||||||
|
return InfoStatsFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InfoStatsFromJSONTyped(json: any, ignoreDiscriminator: boolean): InfoStats {
|
||||||
|
if ((json === undefined) || (json === null)) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'nWebsites': json['n_websites'],
|
||||||
|
'nFiles': json['n_files'],
|
||||||
|
'storageUsed': json['storage_used'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InfoStatsToJSON(value?: InfoStats | null): any {
|
||||||
|
if (value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'n_websites': value.nWebsites,
|
||||||
|
'n_files': value.nFiles,
|
||||||
|
'storage_used': value.storageUsed,
|
||||||
|
};
|
||||||
|
}
|
110
ui/talon-client/src/models/InfoVersion.ts
Normal file
110
ui/talon-client/src/models/InfoVersion.ts
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { exists, mapValues } from '../runtime';
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface InfoVersion
|
||||||
|
*/
|
||||||
|
export interface InfoVersion {
|
||||||
|
/**
|
||||||
|
* Talon version
|
||||||
|
* @type {string}
|
||||||
|
* @memberof InfoVersion
|
||||||
|
*/
|
||||||
|
version: string;
|
||||||
|
/**
|
||||||
|
* Commit hash
|
||||||
|
* @type {string}
|
||||||
|
* @memberof InfoVersion
|
||||||
|
*/
|
||||||
|
commit: string;
|
||||||
|
/**
|
||||||
|
* Commit date
|
||||||
|
* @type {Date}
|
||||||
|
* @memberof InfoVersion
|
||||||
|
*/
|
||||||
|
commitDate: Date;
|
||||||
|
/**
|
||||||
|
* Rust version
|
||||||
|
* @type {string}
|
||||||
|
* @memberof InfoVersion
|
||||||
|
*/
|
||||||
|
rustVersion: string;
|
||||||
|
/**
|
||||||
|
* Build target (OS and architecture)
|
||||||
|
* @type {string}
|
||||||
|
* @memberof InfoVersion
|
||||||
|
*/
|
||||||
|
buildTarget: string;
|
||||||
|
/**
|
||||||
|
* Rust build mode (`debug` / `release`)
|
||||||
|
* @type {string}
|
||||||
|
* @memberof InfoVersion
|
||||||
|
*/
|
||||||
|
buildMode: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the InfoVersion interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfInfoVersion(value: object): boolean {
|
||||||
|
let isInstance = true;
|
||||||
|
isInstance = isInstance && "version" in value;
|
||||||
|
isInstance = isInstance && "commit" in value;
|
||||||
|
isInstance = isInstance && "commitDate" in value;
|
||||||
|
isInstance = isInstance && "rustVersion" in value;
|
||||||
|
isInstance = isInstance && "buildTarget" in value;
|
||||||
|
isInstance = isInstance && "buildMode" in value;
|
||||||
|
|
||||||
|
return isInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InfoVersionFromJSON(json: any): InfoVersion {
|
||||||
|
return InfoVersionFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InfoVersionFromJSONTyped(json: any, ignoreDiscriminator: boolean): InfoVersion {
|
||||||
|
if ((json === undefined) || (json === null)) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'version': json['version'],
|
||||||
|
'commit': json['commit'],
|
||||||
|
'commitDate': (new Date(json['commit_date'])),
|
||||||
|
'rustVersion': json['rust_version'],
|
||||||
|
'buildTarget': json['build_target'],
|
||||||
|
'buildMode': json['build_mode'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InfoVersionToJSON(value?: InfoVersion | null): any {
|
||||||
|
if (value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'version': value.version,
|
||||||
|
'commit': value.commit,
|
||||||
|
'commit_date': (value.commitDate.toISOString()),
|
||||||
|
'rust_version': value.rustVersion,
|
||||||
|
'build_target': value.buildTarget,
|
||||||
|
'build_mode': value.buildMode,
|
||||||
|
};
|
||||||
|
}
|
41
ui/talon-client/src/models/SourceIcon.ts
Normal file
41
ui/talon-client/src/models/SourceIcon.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const SourceIcon = {
|
||||||
|
Link: 'link',
|
||||||
|
Git: 'git',
|
||||||
|
Github: 'github',
|
||||||
|
Gitlab: 'gitlab',
|
||||||
|
Gitea: 'gitea',
|
||||||
|
Bitbucket: 'bitbucket'
|
||||||
|
} as const;
|
||||||
|
export type SourceIcon = typeof SourceIcon[keyof typeof SourceIcon];
|
||||||
|
|
||||||
|
|
||||||
|
export function SourceIconFromJSON(json: any): SourceIcon {
|
||||||
|
return SourceIconFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SourceIconFromJSONTyped(json: any, ignoreDiscriminator: boolean): SourceIcon {
|
||||||
|
return json as SourceIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SourceIconToJSON(value?: SourceIcon | null): any {
|
||||||
|
return value as any;
|
||||||
|
}
|
83
ui/talon-client/src/models/Stats.ts
Normal file
83
ui/talon-client/src/models/Stats.ts
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { exists, mapValues } from '../runtime';
|
||||||
|
/**
|
||||||
|
* Stats about your Talon instance
|
||||||
|
* @export
|
||||||
|
* @interface Stats
|
||||||
|
*/
|
||||||
|
export interface Stats {
|
||||||
|
/**
|
||||||
|
* Number of websites
|
||||||
|
* @type {number}
|
||||||
|
* @memberof Stats
|
||||||
|
*/
|
||||||
|
nWebsites: number;
|
||||||
|
/**
|
||||||
|
* Number of unique files
|
||||||
|
* @type {number}
|
||||||
|
* @memberof Stats
|
||||||
|
*/
|
||||||
|
nFiles: number;
|
||||||
|
/**
|
||||||
|
* Amount of used storage space (in bytes)
|
||||||
|
* @type {number}
|
||||||
|
* @memberof Stats
|
||||||
|
*/
|
||||||
|
storageUsed: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the Stats interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfStats(value: object): boolean {
|
||||||
|
let isInstance = true;
|
||||||
|
isInstance = isInstance && "nWebsites" in value;
|
||||||
|
isInstance = isInstance && "nFiles" in value;
|
||||||
|
isInstance = isInstance && "storageUsed" in value;
|
||||||
|
|
||||||
|
return isInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StatsFromJSON(json: any): Stats {
|
||||||
|
return StatsFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StatsFromJSONTyped(json: any, ignoreDiscriminator: boolean): Stats {
|
||||||
|
if ((json === undefined) || (json === null)) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'nWebsites': json['n_websites'],
|
||||||
|
'nFiles': json['n_files'],
|
||||||
|
'storageUsed': json['storage_used'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StatsToJSON(value?: Stats | null): any {
|
||||||
|
if (value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'n_websites': value.nWebsites,
|
||||||
|
'n_files': value.nFiles,
|
||||||
|
'storage_used': value.storageUsed,
|
||||||
|
};
|
||||||
|
}
|
86
ui/talon-client/src/models/Version.ts
Normal file
86
ui/talon-client/src/models/Version.ts
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { exists, mapValues } from '../runtime';
|
||||||
|
/**
|
||||||
|
* Website version
|
||||||
|
* @export
|
||||||
|
* @interface Version
|
||||||
|
*/
|
||||||
|
export interface Version {
|
||||||
|
/**
|
||||||
|
* Version ID
|
||||||
|
* @type {number}
|
||||||
|
* @memberof Version
|
||||||
|
*/
|
||||||
|
id: number;
|
||||||
|
/**
|
||||||
|
* Version creation date
|
||||||
|
* @type {Date}
|
||||||
|
* @memberof Version
|
||||||
|
*/
|
||||||
|
createdAt: Date;
|
||||||
|
/**
|
||||||
|
* Associated version data
|
||||||
|
*
|
||||||
|
* This is an arbitrary string map that can hold build information and other stuff
|
||||||
|
* and will be displayed in the site info dialog.
|
||||||
|
* @type {{ [key: string]: string; }}
|
||||||
|
* @memberof Version
|
||||||
|
*/
|
||||||
|
data: { [key: string]: string; };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the Version interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfVersion(value: object): boolean {
|
||||||
|
let isInstance = true;
|
||||||
|
isInstance = isInstance && "id" in value;
|
||||||
|
isInstance = isInstance && "createdAt" in value;
|
||||||
|
isInstance = isInstance && "data" in value;
|
||||||
|
|
||||||
|
return isInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VersionFromJSON(json: any): Version {
|
||||||
|
return VersionFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VersionFromJSONTyped(json: any, ignoreDiscriminator: boolean): Version {
|
||||||
|
if ((json === undefined) || (json === null)) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'id': json['id'],
|
||||||
|
'createdAt': (new Date(json['created_at'])),
|
||||||
|
'data': json['data'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VersionToJSON(value?: Version | null): any {
|
||||||
|
if (value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'id': value.id,
|
||||||
|
'created_at': (value.createdAt.toISOString()),
|
||||||
|
'data': value.data,
|
||||||
|
};
|
||||||
|
}
|
82
ui/talon-client/src/models/VersionFile.ts
Normal file
82
ui/talon-client/src/models/VersionFile.ts
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { exists, mapValues } from '../runtime';
|
||||||
|
/**
|
||||||
|
* Website file
|
||||||
|
* @export
|
||||||
|
* @interface VersionFile
|
||||||
|
*/
|
||||||
|
export interface VersionFile {
|
||||||
|
/**
|
||||||
|
* File path
|
||||||
|
* @type {string}
|
||||||
|
* @memberof VersionFile
|
||||||
|
*/
|
||||||
|
path: string;
|
||||||
|
/**
|
||||||
|
* File hash
|
||||||
|
* @type {string}
|
||||||
|
* @memberof VersionFile
|
||||||
|
*/
|
||||||
|
hash: string;
|
||||||
|
/**
|
||||||
|
* MIME file type
|
||||||
|
* @type {string}
|
||||||
|
* @memberof VersionFile
|
||||||
|
*/
|
||||||
|
mime?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the VersionFile interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfVersionFile(value: object): boolean {
|
||||||
|
let isInstance = true;
|
||||||
|
isInstance = isInstance && "path" in value;
|
||||||
|
isInstance = isInstance && "hash" in value;
|
||||||
|
|
||||||
|
return isInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VersionFileFromJSON(json: any): VersionFile {
|
||||||
|
return VersionFileFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VersionFileFromJSONTyped(json: any, ignoreDiscriminator: boolean): VersionFile {
|
||||||
|
if ((json === undefined) || (json === null)) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'path': json['path'],
|
||||||
|
'hash': json['hash'],
|
||||||
|
'mime': !exists(json, 'mime') ? undefined : json['mime'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VersionFileToJSON(value?: VersionFile | null): any {
|
||||||
|
if (value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'path': value.path,
|
||||||
|
'hash': value.hash,
|
||||||
|
'mime': value.mime,
|
||||||
|
};
|
||||||
|
}
|
110
ui/talon-client/src/models/VersionInfo.ts
Normal file
110
ui/talon-client/src/models/VersionInfo.ts
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { exists, mapValues } from '../runtime';
|
||||||
|
/**
|
||||||
|
* Information about a Talon version
|
||||||
|
* @export
|
||||||
|
* @interface VersionInfo
|
||||||
|
*/
|
||||||
|
export interface VersionInfo {
|
||||||
|
/**
|
||||||
|
* Talon version
|
||||||
|
* @type {string}
|
||||||
|
* @memberof VersionInfo
|
||||||
|
*/
|
||||||
|
version: string;
|
||||||
|
/**
|
||||||
|
* Commit hash
|
||||||
|
* @type {string}
|
||||||
|
* @memberof VersionInfo
|
||||||
|
*/
|
||||||
|
commit: string;
|
||||||
|
/**
|
||||||
|
* Commit date
|
||||||
|
* @type {Date}
|
||||||
|
* @memberof VersionInfo
|
||||||
|
*/
|
||||||
|
commitDate: Date;
|
||||||
|
/**
|
||||||
|
* Rust version
|
||||||
|
* @type {string}
|
||||||
|
* @memberof VersionInfo
|
||||||
|
*/
|
||||||
|
rustVersion: string;
|
||||||
|
/**
|
||||||
|
* Build target (OS and architecture)
|
||||||
|
* @type {string}
|
||||||
|
* @memberof VersionInfo
|
||||||
|
*/
|
||||||
|
buildTarget: string;
|
||||||
|
/**
|
||||||
|
* Rust build mode (`debug` / `release`)
|
||||||
|
* @type {string}
|
||||||
|
* @memberof VersionInfo
|
||||||
|
*/
|
||||||
|
buildMode: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the VersionInfo interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfVersionInfo(value: object): boolean {
|
||||||
|
let isInstance = true;
|
||||||
|
isInstance = isInstance && "version" in value;
|
||||||
|
isInstance = isInstance && "commit" in value;
|
||||||
|
isInstance = isInstance && "commitDate" in value;
|
||||||
|
isInstance = isInstance && "rustVersion" in value;
|
||||||
|
isInstance = isInstance && "buildTarget" in value;
|
||||||
|
isInstance = isInstance && "buildMode" in value;
|
||||||
|
|
||||||
|
return isInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VersionInfoFromJSON(json: any): VersionInfo {
|
||||||
|
return VersionInfoFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VersionInfoFromJSONTyped(json: any, ignoreDiscriminator: boolean): VersionInfo {
|
||||||
|
if ((json === undefined) || (json === null)) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'version': json['version'],
|
||||||
|
'commit': json['commit'],
|
||||||
|
'commitDate': (new Date(json['commit_date'])),
|
||||||
|
'rustVersion': json['rust_version'],
|
||||||
|
'buildTarget': json['build_target'],
|
||||||
|
'buildMode': json['build_mode'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VersionInfoToJSON(value?: VersionInfo | null): any {
|
||||||
|
if (value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'version': value.version,
|
||||||
|
'commit': value.commit,
|
||||||
|
'commit_date': (value.commitDate.toISOString()),
|
||||||
|
'rust_version': value.rustVersion,
|
||||||
|
'build_target': value.buildTarget,
|
||||||
|
'build_mode': value.buildMode,
|
||||||
|
};
|
||||||
|
}
|
38
ui/talon-client/src/models/Visibility.ts
Normal file
38
ui/talon-client/src/models/Visibility.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const Visibility = {
|
||||||
|
Featured: 'featured',
|
||||||
|
Searchable: 'searchable',
|
||||||
|
Hidden: 'hidden'
|
||||||
|
} as const;
|
||||||
|
export type Visibility = typeof Visibility[keyof typeof Visibility];
|
||||||
|
|
||||||
|
|
||||||
|
export function VisibilityFromJSON(json: any): Visibility {
|
||||||
|
return VisibilityFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VisibilityFromJSONTyped(json: any, ignoreDiscriminator: boolean): Visibility {
|
||||||
|
return json as Visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VisibilityToJSON(value?: Visibility | null): any {
|
||||||
|
return value as any;
|
||||||
|
}
|
139
ui/talon-client/src/models/Website.ts
Normal file
139
ui/talon-client/src/models/Website.ts
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { exists, mapValues } from '../runtime';
|
||||||
|
import type { SourceIcon } from './SourceIcon';
|
||||||
|
import {
|
||||||
|
SourceIconFromJSON,
|
||||||
|
SourceIconFromJSONTyped,
|
||||||
|
SourceIconToJSON,
|
||||||
|
} from './SourceIcon';
|
||||||
|
import type { Visibility } from './Visibility';
|
||||||
|
import {
|
||||||
|
VisibilityFromJSON,
|
||||||
|
VisibilityFromJSONTyped,
|
||||||
|
VisibilityToJSON,
|
||||||
|
} from './Visibility';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Website
|
||||||
|
* @export
|
||||||
|
* @interface Website
|
||||||
|
*/
|
||||||
|
export interface Website {
|
||||||
|
/**
|
||||||
|
* Website subdomain
|
||||||
|
* @type {string}
|
||||||
|
* @memberof Website
|
||||||
|
*/
|
||||||
|
subdomain: string;
|
||||||
|
/**
|
||||||
|
* Website name
|
||||||
|
* @type {string}
|
||||||
|
* @memberof Website
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
* Website creation date
|
||||||
|
* @type {Date}
|
||||||
|
* @memberof Website
|
||||||
|
*/
|
||||||
|
createdAt: Date;
|
||||||
|
/**
|
||||||
|
* Latest version ID
|
||||||
|
* @type {number}
|
||||||
|
* @memberof Website
|
||||||
|
*/
|
||||||
|
latestVersion?: number;
|
||||||
|
/**
|
||||||
|
* Color of the page icon
|
||||||
|
*
|
||||||
|
* Format: `#7935df`
|
||||||
|
* @type {string}
|
||||||
|
* @memberof Website
|
||||||
|
*/
|
||||||
|
color?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {Visibility}
|
||||||
|
* @memberof Website
|
||||||
|
*/
|
||||||
|
visibility: Visibility;
|
||||||
|
/**
|
||||||
|
* Link to the source of the page
|
||||||
|
* @type {string}
|
||||||
|
* @memberof Website
|
||||||
|
*/
|
||||||
|
sourceUrl?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {SourceIcon}
|
||||||
|
* @memberof Website
|
||||||
|
*/
|
||||||
|
sourceIcon?: SourceIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the Website interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfWebsite(value: object): boolean {
|
||||||
|
let isInstance = true;
|
||||||
|
isInstance = isInstance && "subdomain" in value;
|
||||||
|
isInstance = isInstance && "name" in value;
|
||||||
|
isInstance = isInstance && "createdAt" in value;
|
||||||
|
isInstance = isInstance && "visibility" in value;
|
||||||
|
|
||||||
|
return isInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WebsiteFromJSON(json: any): Website {
|
||||||
|
return WebsiteFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WebsiteFromJSONTyped(json: any, ignoreDiscriminator: boolean): Website {
|
||||||
|
if ((json === undefined) || (json === null)) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'subdomain': json['subdomain'],
|
||||||
|
'name': json['name'],
|
||||||
|
'createdAt': (new Date(json['created_at'])),
|
||||||
|
'latestVersion': !exists(json, 'latest_version') ? undefined : json['latest_version'],
|
||||||
|
'color': !exists(json, 'color') ? undefined : json['color'],
|
||||||
|
'visibility': VisibilityFromJSON(json['visibility']),
|
||||||
|
'sourceUrl': !exists(json, 'source_url') ? undefined : json['source_url'],
|
||||||
|
'sourceIcon': !exists(json, 'source_icon') ? undefined : SourceIconFromJSON(json['source_icon']),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WebsiteToJSON(value?: Website | null): any {
|
||||||
|
if (value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'subdomain': value.subdomain,
|
||||||
|
'name': value.name,
|
||||||
|
'created_at': (value.createdAt.toISOString()),
|
||||||
|
'latest_version': value.latestVersion,
|
||||||
|
'color': value.color,
|
||||||
|
'visibility': VisibilityToJSON(value.visibility),
|
||||||
|
'source_url': value.sourceUrl,
|
||||||
|
'source_icon': SourceIconToJSON(value.sourceIcon),
|
||||||
|
};
|
||||||
|
}
|
110
ui/talon-client/src/models/WebsiteNew.ts
Normal file
110
ui/talon-client/src/models/WebsiteNew.ts
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { exists, mapValues } from '../runtime';
|
||||||
|
import type { SourceIcon } from './SourceIcon';
|
||||||
|
import {
|
||||||
|
SourceIconFromJSON,
|
||||||
|
SourceIconFromJSONTyped,
|
||||||
|
SourceIconToJSON,
|
||||||
|
} from './SourceIcon';
|
||||||
|
import type { Visibility } from './Visibility';
|
||||||
|
import {
|
||||||
|
VisibilityFromJSON,
|
||||||
|
VisibilityFromJSONTyped,
|
||||||
|
VisibilityToJSON,
|
||||||
|
} from './Visibility';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new website
|
||||||
|
* @export
|
||||||
|
* @interface WebsiteNew
|
||||||
|
*/
|
||||||
|
export interface WebsiteNew {
|
||||||
|
/**
|
||||||
|
* Website name
|
||||||
|
* @type {string}
|
||||||
|
* @memberof WebsiteNew
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
* Color of the page icon
|
||||||
|
* @type {string}
|
||||||
|
* @memberof WebsiteNew
|
||||||
|
*/
|
||||||
|
color?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {Visibility}
|
||||||
|
* @memberof WebsiteNew
|
||||||
|
*/
|
||||||
|
visibility?: Visibility;
|
||||||
|
/**
|
||||||
|
* Link to the source of the page
|
||||||
|
* @type {string}
|
||||||
|
* @memberof WebsiteNew
|
||||||
|
*/
|
||||||
|
sourceUrl?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {SourceIcon}
|
||||||
|
* @memberof WebsiteNew
|
||||||
|
*/
|
||||||
|
sourceIcon?: SourceIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the WebsiteNew interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfWebsiteNew(value: object): boolean {
|
||||||
|
let isInstance = true;
|
||||||
|
isInstance = isInstance && "name" in value;
|
||||||
|
|
||||||
|
return isInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WebsiteNewFromJSON(json: any): WebsiteNew {
|
||||||
|
return WebsiteNewFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WebsiteNewFromJSONTyped(json: any, ignoreDiscriminator: boolean): WebsiteNew {
|
||||||
|
if ((json === undefined) || (json === null)) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'name': json['name'],
|
||||||
|
'color': !exists(json, 'color') ? undefined : json['color'],
|
||||||
|
'visibility': !exists(json, 'visibility') ? undefined : VisibilityFromJSON(json['visibility']),
|
||||||
|
'sourceUrl': !exists(json, 'source_url') ? undefined : json['source_url'],
|
||||||
|
'sourceIcon': !exists(json, 'source_icon') ? undefined : SourceIconFromJSON(json['source_icon']),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WebsiteNewToJSON(value?: WebsiteNew | null): any {
|
||||||
|
if (value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'name': value.name,
|
||||||
|
'color': value.color,
|
||||||
|
'visibility': VisibilityToJSON(value.visibility),
|
||||||
|
'source_url': value.sourceUrl,
|
||||||
|
'source_icon': SourceIconToJSON(value.sourceIcon),
|
||||||
|
};
|
||||||
|
}
|
111
ui/talon-client/src/models/WebsiteUpdate.ts
Normal file
111
ui/talon-client/src/models/WebsiteUpdate.ts
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { exists, mapValues } from '../runtime';
|
||||||
|
import type { SourceIcon } from './SourceIcon';
|
||||||
|
import {
|
||||||
|
SourceIconFromJSON,
|
||||||
|
SourceIconFromJSONTyped,
|
||||||
|
SourceIconToJSON,
|
||||||
|
} from './SourceIcon';
|
||||||
|
import type { Visibility } from './Visibility';
|
||||||
|
import {
|
||||||
|
VisibilityFromJSON,
|
||||||
|
VisibilityFromJSONTyped,
|
||||||
|
VisibilityToJSON,
|
||||||
|
} from './Visibility';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a website with the contained values
|
||||||
|
*
|
||||||
|
* Values set to `None` remain unchanged.
|
||||||
|
* @export
|
||||||
|
* @interface WebsiteUpdate
|
||||||
|
*/
|
||||||
|
export interface WebsiteUpdate {
|
||||||
|
/**
|
||||||
|
* Website name
|
||||||
|
* @type {string}
|
||||||
|
* @memberof WebsiteUpdate
|
||||||
|
*/
|
||||||
|
name?: string;
|
||||||
|
/**
|
||||||
|
* Color of the page icon
|
||||||
|
* @type {string}
|
||||||
|
* @memberof WebsiteUpdate
|
||||||
|
*/
|
||||||
|
color?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {Visibility}
|
||||||
|
* @memberof WebsiteUpdate
|
||||||
|
*/
|
||||||
|
visibility?: Visibility;
|
||||||
|
/**
|
||||||
|
* Link to the source of the page
|
||||||
|
* @type {string}
|
||||||
|
* @memberof WebsiteUpdate
|
||||||
|
*/
|
||||||
|
sourceUrl?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {SourceIcon}
|
||||||
|
* @memberof WebsiteUpdate
|
||||||
|
*/
|
||||||
|
sourceIcon?: SourceIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the WebsiteUpdate interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfWebsiteUpdate(value: object): boolean {
|
||||||
|
let isInstance = true;
|
||||||
|
|
||||||
|
return isInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WebsiteUpdateFromJSON(json: any): WebsiteUpdate {
|
||||||
|
return WebsiteUpdateFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WebsiteUpdateFromJSONTyped(json: any, ignoreDiscriminator: boolean): WebsiteUpdate {
|
||||||
|
if ((json === undefined) || (json === null)) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'name': !exists(json, 'name') ? undefined : json['name'],
|
||||||
|
'color': !exists(json, 'color') ? undefined : json['color'],
|
||||||
|
'visibility': !exists(json, 'visibility') ? undefined : VisibilityFromJSON(json['visibility']),
|
||||||
|
'sourceUrl': !exists(json, 'source_url') ? undefined : json['source_url'],
|
||||||
|
'sourceIcon': !exists(json, 'source_icon') ? undefined : SourceIconFromJSON(json['source_icon']),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WebsiteUpdateToJSON(value?: WebsiteUpdate | null): any {
|
||||||
|
if (value === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'name': value.name,
|
||||||
|
'color': value.color,
|
||||||
|
'visibility': VisibilityToJSON(value.visibility),
|
||||||
|
'source_url': value.sourceUrl,
|
||||||
|
'source_icon': SourceIconToJSON(value.sourceIcon),
|
||||||
|
};
|
||||||
|
}
|
14
ui/talon-client/src/models/index.ts
Normal file
14
ui/talon-client/src/models/index.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export * from './Info';
|
||||||
|
export * from './InfoStats';
|
||||||
|
export * from './InfoVersion';
|
||||||
|
export * from './SourceIcon';
|
||||||
|
export * from './Stats';
|
||||||
|
export * from './Version';
|
||||||
|
export * from './VersionFile';
|
||||||
|
export * from './VersionInfo';
|
||||||
|
export * from './Visibility';
|
||||||
|
export * from './Website';
|
||||||
|
export * from './WebsiteNew';
|
||||||
|
export * from './WebsiteUpdate';
|
407
ui/talon-client/src/runtime.ts
Normal file
407
ui/talon-client/src/runtime.ts
Normal file
|
@ -0,0 +1,407 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Talon
|
||||||
|
* API for the Talon static site management system
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 0.1.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
export const BASE_PATH = "http://localhost".replace(/\/+$/, "");
|
||||||
|
|
||||||
|
export interface ConfigurationParameters {
|
||||||
|
basePath?: string; // override base path
|
||||||
|
fetchApi?: FetchAPI; // override for fetch implementation
|
||||||
|
middleware?: Middleware[]; // middleware to apply before/after fetch requests
|
||||||
|
queryParamsStringify?: (params: HTTPQuery) => string; // stringify function for query strings
|
||||||
|
username?: string; // parameter for basic security
|
||||||
|
password?: string; // parameter for basic security
|
||||||
|
apiKey?: string | ((name: string) => string); // parameter for apiKey security
|
||||||
|
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string | Promise<string>); // parameter for oauth2 security
|
||||||
|
headers?: HTTPHeaders; //header params we want to use on every request
|
||||||
|
credentials?: RequestCredentials; //value for the credentials param we want to use on each request
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Configuration {
|
||||||
|
constructor(private configuration: ConfigurationParameters = {}) {}
|
||||||
|
|
||||||
|
set config(configuration: Configuration) {
|
||||||
|
this.configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
get basePath(): string {
|
||||||
|
return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
get fetchApi(): FetchAPI | undefined {
|
||||||
|
return this.configuration.fetchApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
get middleware(): Middleware[] {
|
||||||
|
return this.configuration.middleware || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
get queryParamsStringify(): (params: HTTPQuery) => string {
|
||||||
|
return this.configuration.queryParamsStringify || querystring;
|
||||||
|
}
|
||||||
|
|
||||||
|
get username(): string | undefined {
|
||||||
|
return this.configuration.username;
|
||||||
|
}
|
||||||
|
|
||||||
|
get password(): string | undefined {
|
||||||
|
return this.configuration.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
get apiKey(): ((name: string) => string) | undefined {
|
||||||
|
const apiKey = this.configuration.apiKey;
|
||||||
|
if (apiKey) {
|
||||||
|
return typeof apiKey === 'function' ? apiKey : () => apiKey;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
get accessToken(): ((name?: string, scopes?: string[]) => string | Promise<string>) | undefined {
|
||||||
|
const accessToken = this.configuration.accessToken;
|
||||||
|
if (accessToken) {
|
||||||
|
return typeof accessToken === 'function' ? accessToken : async () => accessToken;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
get headers(): HTTPHeaders | undefined {
|
||||||
|
return this.configuration.headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
get credentials(): RequestCredentials | undefined {
|
||||||
|
return this.configuration.credentials;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DefaultConfig = new Configuration();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the base class for all generated API classes.
|
||||||
|
*/
|
||||||
|
export class BaseAPI {
|
||||||
|
|
||||||
|
private middleware: Middleware[];
|
||||||
|
|
||||||
|
constructor(protected configuration = DefaultConfig) {
|
||||||
|
this.middleware = configuration.middleware;
|
||||||
|
}
|
||||||
|
|
||||||
|
withMiddleware<T extends BaseAPI>(this: T, ...middlewares: Middleware[]) {
|
||||||
|
const next = this.clone<T>();
|
||||||
|
next.middleware = next.middleware.concat(...middlewares);
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
withPreMiddleware<T extends BaseAPI>(this: T, ...preMiddlewares: Array<Middleware['pre']>) {
|
||||||
|
const middlewares = preMiddlewares.map((pre) => ({ pre }));
|
||||||
|
return this.withMiddleware<T>(...middlewares);
|
||||||
|
}
|
||||||
|
|
||||||
|
withPostMiddleware<T extends BaseAPI>(this: T, ...postMiddlewares: Array<Middleware['post']>) {
|
||||||
|
const middlewares = postMiddlewares.map((post) => ({ post }));
|
||||||
|
return this.withMiddleware<T>(...middlewares);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise<Response> {
|
||||||
|
const { url, init } = await this.createFetchParams(context, initOverrides);
|
||||||
|
const response = await this.fetchApi(url, init);
|
||||||
|
if (response && (response.status >= 200 && response.status < 300)) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
throw new ResponseError(response, 'Response returned an error code');
|
||||||
|
}
|
||||||
|
|
||||||
|
private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) {
|
||||||
|
let url = this.configuration.basePath + context.path;
|
||||||
|
if (context.query !== undefined && Object.keys(context.query).length !== 0) {
|
||||||
|
// only add the querystring to the URL if there are query parameters.
|
||||||
|
// this is done to avoid urls ending with a "?" character which buggy webservers
|
||||||
|
// do not handle correctly sometimes.
|
||||||
|
url += '?' + this.configuration.queryParamsStringify(context.query);
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = Object.assign({}, this.configuration.headers, context.headers);
|
||||||
|
Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {});
|
||||||
|
|
||||||
|
const initOverrideFn =
|
||||||
|
typeof initOverrides === "function"
|
||||||
|
? initOverrides
|
||||||
|
: async () => initOverrides;
|
||||||
|
|
||||||
|
const initParams = {
|
||||||
|
method: context.method,
|
||||||
|
headers,
|
||||||
|
body: context.body,
|
||||||
|
credentials: this.configuration.credentials,
|
||||||
|
};
|
||||||
|
|
||||||
|
const overriddenInit: RequestInit = {
|
||||||
|
...initParams,
|
||||||
|
...(await initOverrideFn({
|
||||||
|
init: initParams,
|
||||||
|
context,
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
const init: RequestInit = {
|
||||||
|
...overriddenInit,
|
||||||
|
body:
|
||||||
|
isFormData(overriddenInit.body) ||
|
||||||
|
overriddenInit.body instanceof URLSearchParams ||
|
||||||
|
isBlob(overriddenInit.body)
|
||||||
|
? overriddenInit.body
|
||||||
|
: JSON.stringify(overriddenInit.body),
|
||||||
|
};
|
||||||
|
|
||||||
|
return { url, init };
|
||||||
|
}
|
||||||
|
|
||||||
|
private fetchApi = async (url: string, init: RequestInit) => {
|
||||||
|
let fetchParams = { url, init };
|
||||||
|
for (const middleware of this.middleware) {
|
||||||
|
if (middleware.pre) {
|
||||||
|
fetchParams = await middleware.pre({
|
||||||
|
fetch: this.fetchApi,
|
||||||
|
...fetchParams,
|
||||||
|
}) || fetchParams;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let response: Response | undefined = undefined;
|
||||||
|
try {
|
||||||
|
response = await (this.configuration.fetchApi || fetch)(fetchParams.url, fetchParams.init);
|
||||||
|
} catch (e) {
|
||||||
|
for (const middleware of this.middleware) {
|
||||||
|
if (middleware.onError) {
|
||||||
|
response = await middleware.onError({
|
||||||
|
fetch: this.fetchApi,
|
||||||
|
url: fetchParams.url,
|
||||||
|
init: fetchParams.init,
|
||||||
|
error: e,
|
||||||
|
response: response ? response.clone() : undefined,
|
||||||
|
}) || response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (response === undefined) {
|
||||||
|
if (e instanceof Error) {
|
||||||
|
throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response');
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const middleware of this.middleware) {
|
||||||
|
if (middleware.post) {
|
||||||
|
response = await middleware.post({
|
||||||
|
fetch: this.fetchApi,
|
||||||
|
url: fetchParams.url,
|
||||||
|
init: fetchParams.init,
|
||||||
|
response: response.clone(),
|
||||||
|
}) || response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a shallow clone of `this` by constructing a new instance
|
||||||
|
* and then shallow cloning data members.
|
||||||
|
*/
|
||||||
|
private clone<T extends BaseAPI>(this: T): T {
|
||||||
|
const constructor = this.constructor as any;
|
||||||
|
const next = new constructor(this.configuration);
|
||||||
|
next.middleware = this.middleware.slice();
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function isBlob(value: any): value is Blob {
|
||||||
|
return typeof Blob !== 'undefined' && value instanceof Blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFormData(value: any): value is FormData {
|
||||||
|
return typeof FormData !== "undefined" && value instanceof FormData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ResponseError extends Error {
|
||||||
|
override name: "ResponseError" = "ResponseError";
|
||||||
|
constructor(public response: Response, msg?: string) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FetchError extends Error {
|
||||||
|
override name: "FetchError" = "FetchError";
|
||||||
|
constructor(public cause: Error, msg?: string) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RequiredError extends Error {
|
||||||
|
override name: "RequiredError" = "RequiredError";
|
||||||
|
constructor(public field: string, msg?: string) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const COLLECTION_FORMATS = {
|
||||||
|
csv: ",",
|
||||||
|
ssv: " ",
|
||||||
|
tsv: "\t",
|
||||||
|
pipes: "|",
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FetchAPI = WindowOrWorkerGlobalScope['fetch'];
|
||||||
|
|
||||||
|
export type Json = any;
|
||||||
|
export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
|
||||||
|
export type HTTPHeaders = { [key: string]: string };
|
||||||
|
export type HTTPQuery = { [key: string]: string | number | null | boolean | Array<string | number | null | boolean> | Set<string | number | null | boolean> | HTTPQuery };
|
||||||
|
export type HTTPBody = Json | FormData | URLSearchParams;
|
||||||
|
export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody };
|
||||||
|
export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original';
|
||||||
|
|
||||||
|
export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise<RequestInit>
|
||||||
|
|
||||||
|
export interface FetchParams {
|
||||||
|
url: string;
|
||||||
|
init: RequestInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RequestOpts {
|
||||||
|
path: string;
|
||||||
|
method: HTTPMethod;
|
||||||
|
headers: HTTPHeaders;
|
||||||
|
query?: HTTPQuery;
|
||||||
|
body?: HTTPBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function exists(json: any, key: string) {
|
||||||
|
const value = json[key];
|
||||||
|
return value !== null && value !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function querystring(params: HTTPQuery, prefix: string = ''): string {
|
||||||
|
return Object.keys(params)
|
||||||
|
.map(key => querystringSingleKey(key, params[key], prefix))
|
||||||
|
.filter(part => part.length > 0)
|
||||||
|
.join('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array<string | number | null | boolean> | Set<string | number | null | boolean> | HTTPQuery, keyPrefix: string = ''): string {
|
||||||
|
const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key);
|
||||||
|
if (value instanceof Array) {
|
||||||
|
const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue)))
|
||||||
|
.join(`&${encodeURIComponent(fullKey)}=`);
|
||||||
|
return `${encodeURIComponent(fullKey)}=${multiValue}`;
|
||||||
|
}
|
||||||
|
if (value instanceof Set) {
|
||||||
|
const valueAsArray = Array.from(value);
|
||||||
|
return querystringSingleKey(key, valueAsArray, keyPrefix);
|
||||||
|
}
|
||||||
|
if (value instanceof Date) {
|
||||||
|
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`;
|
||||||
|
}
|
||||||
|
if (value instanceof Object) {
|
||||||
|
return querystring(value as HTTPQuery, fullKey);
|
||||||
|
}
|
||||||
|
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mapValues(data: any, fn: (item: any) => any) {
|
||||||
|
return Object.keys(data).reduce(
|
||||||
|
(acc, key) => ({ ...acc, [key]: fn(data[key]) }),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canConsumeForm(consumes: Consume[]): boolean {
|
||||||
|
for (const consume of consumes) {
|
||||||
|
if ('multipart/form-data' === consume.contentType) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Consume {
|
||||||
|
contentType: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RequestContext {
|
||||||
|
fetch: FetchAPI;
|
||||||
|
url: string;
|
||||||
|
init: RequestInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResponseContext {
|
||||||
|
fetch: FetchAPI;
|
||||||
|
url: string;
|
||||||
|
init: RequestInit;
|
||||||
|
response: Response;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ErrorContext {
|
||||||
|
fetch: FetchAPI;
|
||||||
|
url: string;
|
||||||
|
init: RequestInit;
|
||||||
|
error: unknown;
|
||||||
|
response?: Response;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Middleware {
|
||||||
|
pre?(context: RequestContext): Promise<FetchParams | void>;
|
||||||
|
post?(context: ResponseContext): Promise<Response | void>;
|
||||||
|
onError?(context: ErrorContext): Promise<Response | void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiResponse<T> {
|
||||||
|
raw: Response;
|
||||||
|
value(): Promise<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResponseTransformer<T> {
|
||||||
|
(json: any): T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class JSONApiResponse<T> {
|
||||||
|
constructor(public raw: Response, private transformer: ResponseTransformer<T> = (jsonValue: any) => jsonValue) {}
|
||||||
|
|
||||||
|
async value(): Promise<T> {
|
||||||
|
return this.transformer(await this.raw.json());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class VoidApiResponse {
|
||||||
|
constructor(public raw: Response) {}
|
||||||
|
|
||||||
|
async value(): Promise<void> {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BlobApiResponse {
|
||||||
|
constructor(public raw: Response) {}
|
||||||
|
|
||||||
|
async value(): Promise<Blob> {
|
||||||
|
return await this.raw.blob();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TextApiResponse {
|
||||||
|
constructor(public raw: Response) {}
|
||||||
|
|
||||||
|
async value(): Promise<string> {
|
||||||
|
return await this.raw.text();
|
||||||
|
};
|
||||||
|
}
|
20
ui/talon-client/tsconfig.json
Normal file
20
ui/talon-client/tsconfig.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"declaration": true,
|
||||||
|
"target": "es5",
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"outDir": "dist",
|
||||||
|
"lib": [
|
||||||
|
"es6",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
|
"typeRoots": [
|
||||||
|
"node_modules/@types"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in a new issue