Compare commits
13 commits
Author | SHA1 | Date | |
---|---|---|---|
f1ed826eee | |||
f1e5388db1 | |||
ba4086bac9 | |||
067dae1356 | |||
0c8d70d6e1 | |||
e8bb51d388 | |||
b38eabb27b | |||
1e7718865c | |||
44fc06cd4b | |||
f700b484be | |||
0cec19e682 | |||
3be7f2795f | |||
97a8e9a2ba |
13 changed files with 643 additions and 482 deletions
|
@ -18,4 +18,5 @@ repos:
|
||||||
name: ui/menu lint+fmt
|
name: ui/menu lint+fmt
|
||||||
language: system
|
language: system
|
||||||
files: ^ui/menu/
|
files: ^ui/menu/
|
||||||
entry: sh -c "npm run --prefix ui/menu pc"
|
pass_filenames: false
|
||||||
|
entry: npm run --prefix ui/menu pc
|
||||||
|
|
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -2,6 +2,31 @@
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [0.4.2] - 2023-07-22
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- Container entrypoint
|
||||||
|
- Website version ordering
|
||||||
|
|
||||||
|
### Miscellaneous Tasks
|
||||||
|
|
||||||
|
- Fix npm pre-commit hook
|
||||||
|
|
||||||
|
## [0.4.1] - 2023-04-05
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- Stop propagation of key events on menu search
|
||||||
|
- Use sh
|
||||||
|
- Remove version prefix from "latest" tag
|
||||||
|
- Detect CI commit SHA
|
||||||
|
- Use better abbreviations for page names
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Add upload script
|
||||||
|
|
||||||
## [0.4.0] - 2023-04-02
|
## [0.4.0] - 2023-04-02
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
962
Cargo.lock
generated
962
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "talon"
|
name = "talon"
|
||||||
version = "0.4.0"
|
version = "0.4.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["ThetaDev <t.testboy@gmail.com>"]
|
authors = ["ThetaDev <t.testboy@gmail.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
@ -48,7 +48,7 @@ commit_parsers = [
|
||||||
{ message = "^refactor", group = "Refactor"},
|
{ message = "^refactor", group = "Refactor"},
|
||||||
{ message = "^style", group = "Styling"},
|
{ message = "^style", group = "Styling"},
|
||||||
{ message = "^test", group = "Testing"},
|
{ message = "^test", group = "Testing"},
|
||||||
{ message = "^chore\\(release\\): (prepare for|bump)", skip = true},
|
{ message = "^chore\\(release\\):", skip = true},
|
||||||
{ message = "(^chore)|(^ci)", group = "Miscellaneous Tasks"},
|
{ message = "(^chore)|(^ci)", group = "Miscellaneous Tasks"},
|
||||||
{ body = ".*security", group = "Security"},
|
{ body = ".*security", group = "Security"},
|
||||||
]
|
]
|
||||||
|
|
|
@ -41,7 +41,8 @@ for arch in "${ARCHITECTURES[@]}"; do
|
||||||
|
|
||||||
# Finalize container
|
# Finalize container
|
||||||
buildah umount "$container"
|
buildah umount "$container"
|
||||||
buildah config --entrypoint "/talon" --cmd "run -d /data" --arch "$arch" --port 3000 --author "ThetaDev" "$container"
|
# entrypoint syntax: see issue https://github.com/containers/buildah/issues/1768
|
||||||
|
buildah config --entrypoint '["/talon"]' --cmd "run -d /data" --arch "$arch" --port 3000 --author "ThetaDev" "$container"
|
||||||
buildah commit "$container" "$IMAGE:$arch-$TAG"
|
buildah commit "$container" "$IMAGE:$arch-$TAG"
|
||||||
|
|
||||||
buildah manifest add "$REGISTRY/$IMAGE:$TAG" "$IMAGE:$arch-$TAG"
|
buildah manifest add "$REGISTRY/$IMAGE:$TAG" "$IMAGE:$arch-$TAG"
|
||||||
|
|
75
scripts/upload.sh
Executable file
75
scripts/upload.sh
Executable file
|
@ -0,0 +1,75 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Check for dependencies
|
||||||
|
which curl > /dev/null
|
||||||
|
which jq > /dev/null
|
||||||
|
|
||||||
|
# Assert required variables
|
||||||
|
if [ -z "$TALON_KEY" ]; then echo "TALON_KEY unset"; exit 1; fi
|
||||||
|
if [ -z "$TALON_URL" ]; then echo "TALON_URL unset"; exit 1; fi
|
||||||
|
if [ -z "$SUBDOMAIN" ]; then echo "SUBDOMAIN unset"; exit 1; fi
|
||||||
|
|
||||||
|
API_URL="$TALON_URL/api"
|
||||||
|
API_KEY_H="x-api-key: $TALON_KEY"
|
||||||
|
|
||||||
|
# Check if the website already exists
|
||||||
|
WEBSITE_STATUS=$(curl --head -o /dev/null -s -w "%{http_code}" "$API_URL/website/$SUBDOMAIN")
|
||||||
|
if [ "$WEBSITE_STATUS" = "200" ]; then
|
||||||
|
echo "Website '$SUBDOMAIN' found"
|
||||||
|
else
|
||||||
|
# Create the website if it does not exist
|
||||||
|
if [ -z "$WEBSITE_NAME" ]; then echo "WEBSITE_NAME unset"; exit 1; fi
|
||||||
|
|
||||||
|
CREATE_BODY=$(jq -c --null-input --arg name "$WEBSITE_NAME" --arg color "$WEBSITE_COLOR" \
|
||||||
|
--arg visibility "$WEBSITE_VISIBILITY" --arg source_url "$WEBSITE_SOURCE_URL" \
|
||||||
|
--arg source_icon "$WEBSITE_SOURCE_ICON" \
|
||||||
|
'{"name": $name, "color": $color, "visibility": $visibility, "source_url": $source_url, "source_icon": $source_icon} | delpaths([path(.[]| select(.==""))])')
|
||||||
|
echo "Creating website '$SUBDOMAIN': $CREATE_BODY"
|
||||||
|
|
||||||
|
curl -Ss --fail -X "PUT" -H "$API_KEY_H" -H "content-type: application/json" --data "$CREATE_BODY" "$API_URL/website/$SUBDOMAIN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check the upload directory
|
||||||
|
if [ ! -d "$1" ]; then echo "Upload directory does not exist"; exit 1; fi
|
||||||
|
if [ ! -f "$1/index.html" ]; then echo "Upload directory does not contain index.html"; exit 1; fi
|
||||||
|
|
||||||
|
# Validate fallback page param
|
||||||
|
if [ "$FALLBACK" ] && [ ! -f "$1/$FALLBACK" ]; then echo "fallback page $FALLBACK does not exist"; exit 1; fi
|
||||||
|
|
||||||
|
# Automatically detect fallback pages
|
||||||
|
if [ -z "$SPA" ] && [ -z "$FALLBACK" ]; then
|
||||||
|
if [ -f "$1/404.html" ]; then FALLBACK="404.html"; fi
|
||||||
|
if [ -f "$1/200.html" ]; then SPA=true; FALLBACK="200.html"; fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
push_arg() {
|
||||||
|
if [ "$UPLOAD_ARGS" ]; then UPLOAD_ARGS="$UPLOAD_ARGS&"; fi
|
||||||
|
UPLOAD_ARGS="$UPLOAD_ARGS$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$FALLBACK" ]; then push_arg "fallback=$FALLBACK"; fi
|
||||||
|
if [ "$SPA" = "true" ]; then push_arg "spa=true"; fi
|
||||||
|
|
||||||
|
if [ "$UPLOAD_ARGS" ]; then UPLOAD_ARGS="?$UPLOAD_ARGS"; fi
|
||||||
|
|
||||||
|
if [ "$CI_COMMIT_SHA" ]; then
|
||||||
|
echo "Git commit: $CI_COMMIT_SHA"
|
||||||
|
push_arg "commit=$CI_COMMIT_SHA"
|
||||||
|
elif GIT_COMMIT=$(git rev-parse HEAD 2> /dev/null); then
|
||||||
|
echo "Git commit: $GIT_COMMIT"
|
||||||
|
push_arg "commit=$GIT_COMMIT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compress website
|
||||||
|
ARCHIVE=$(mktemp)
|
||||||
|
tar -cz --directory "$1" --file "$ARCHIVE" .
|
||||||
|
|
||||||
|
# Upload website
|
||||||
|
echo "Version params: $UPLOAD_ARGS"
|
||||||
|
echo "Uploading..."
|
||||||
|
curl --fail -X "POST" -H "$API_KEY_H" -H "content-type: application/octet-stream" --data-binary "@$ARCHIVE" "$API_URL/website/$SUBDOMAIN/upload$UPLOAD_ARGS"
|
||||||
|
|
||||||
|
rm "$ARCHIVE"
|
||||||
|
|
||||||
|
echo "Website uploaded ;-)"
|
17
src/api.rs
17
src/api.rs
|
@ -300,18 +300,17 @@ impl TalonApi {
|
||||||
subdomain: Path<String>,
|
subdomain: Path<String>,
|
||||||
) -> Result<Response<Json<Vec<Version>>>> {
|
) -> Result<Response<Json<Vec<Version>>>> {
|
||||||
let website = talon.db.get_website(&subdomain)?;
|
let website = talon.db.get_website(&subdomain)?;
|
||||||
talon
|
let mut versions = talon
|
||||||
.db
|
.db
|
||||||
.get_website_versions(&subdomain)
|
.get_website_versions(&subdomain)
|
||||||
.map(|r| r.map(Version::from))
|
.map(|r| r.map(Version::from))
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
.map(|data| {
|
versions.sort_by_key(|v| v.id);
|
||||||
Response::new(Json(data)).header(
|
|
||||||
header::LAST_MODIFIED,
|
Ok(Response::new(Json(versions)).header(
|
||||||
httpdate::fmt_http_date(website.updated_at.into()),
|
header::LAST_MODIFIED,
|
||||||
)
|
httpdate::fmt_http_date(website.updated_at.into()),
|
||||||
})
|
))
|
||||||
.map_err(Error::from)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get version
|
/// Get version
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
closeSearch();
|
closeSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchKeypress(e: KeyboardEvent) {
|
function searchKeyup(e: KeyboardEvent) {
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case "Enter":
|
case "Enter":
|
||||||
if (!searchText) {
|
if (!searchText) {
|
||||||
|
@ -96,7 +96,7 @@
|
||||||
active={searchOpen || Boolean(searchText).valueOf()}
|
active={searchOpen || Boolean(searchText).valueOf()}
|
||||||
on:click={openSearch}
|
on:click={openSearch}
|
||||||
on:focusout={closeSearch}
|
on:focusout={closeSearch}
|
||||||
on:keyup={searchKeypress}
|
on:keyup={searchKeyup}
|
||||||
bind:input={searchInput}
|
bind:input={searchInput}
|
||||||
bind:text={searchText}
|
bind:text={searchText}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -26,7 +26,9 @@
|
||||||
bind:this={inputElm}
|
bind:this={inputElm}
|
||||||
bind:value={text}
|
bind:value={text}
|
||||||
on:focusout
|
on:focusout
|
||||||
on:keyup
|
on:keypress|stopPropagation
|
||||||
|
on:keydown|stopPropagation
|
||||||
|
on:keyup|stopPropagation
|
||||||
use:selectTextOnFocus
|
use:selectTextOnFocus
|
||||||
/>
|
/>
|
||||||
<Icon iconName="search" size={40} scale={0.6} />
|
<Icon iconName="search" size={40} scale={0.6} />
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import Icon from "./Icon.svelte";
|
import Icon from "./Icon.svelte";
|
||||||
import type { Website } from "talon-client";
|
import type { Website } from "talon-client";
|
||||||
import { talonConfig } from "../util/talonData";
|
import { talonConfig } from "../util/talonData";
|
||||||
|
import { getAbbreviation } from "../util/functions";
|
||||||
|
|
||||||
export let website: Website;
|
export let website: Website;
|
||||||
export let size = 40;
|
export let size = 40;
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
? `${talonConfig.internal}/icons/${website.subdomain}`
|
? `${talonConfig.internal}/icons/${website.subdomain}`
|
||||||
: null}
|
: null}
|
||||||
color={website.color}
|
color={website.color}
|
||||||
alt={website.name.substring(0, 2)}
|
alt={getAbbreviation(website.name)}
|
||||||
{size}
|
{size}
|
||||||
{scale}
|
{scale}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import {
|
import {
|
||||||
formatDate,
|
formatDate,
|
||||||
getSubdomainAndVersion,
|
getSubdomainAndVersion,
|
||||||
|
getWebsiteUrl,
|
||||||
getWebsiteVersionUrl,
|
getWebsiteVersionUrl,
|
||||||
isUrl,
|
isUrl,
|
||||||
trimCommit,
|
trimCommit,
|
||||||
|
@ -75,9 +76,7 @@
|
||||||
Current version #{currentVersion.id}
|
Current version #{currentVersion.id}
|
||||||
|
|
||||||
{#if latestVersion && latestVersion !== currentVersion}
|
{#if latestVersion && latestVersion !== currentVersion}
|
||||||
<a
|
<a class="latest-tag" href={getWebsiteUrl(currentWebsite.subdomain)}
|
||||||
class="latest-tag"
|
|
||||||
href={getWebsiteVersionUrl(currentWebsite.subdomain, latestVersion.id)}
|
|
||||||
>Latest: #{latestVersion.id}</a
|
>Latest: #{latestVersion.id}</a
|
||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -81,3 +81,23 @@ export function trimCommit(commit: string | undefined): string | undefined {
|
||||||
export function isMobile(): boolean {
|
export function isMobile(): boolean {
|
||||||
return window.innerWidth < 768;
|
return window.innerWidth < 768;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a 2-letter abbreviation of the website name.
|
||||||
|
*
|
||||||
|
* If the name consists of multiple words
|
||||||
|
* (separated by spaces, underscores or CamelCase), output
|
||||||
|
* the first letters of these words.
|
||||||
|
*
|
||||||
|
* Otherwise output the first letters of the name.
|
||||||
|
*/
|
||||||
|
export function getAbbreviation(name: string): string {
|
||||||
|
const split_sep = name
|
||||||
|
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
||||||
|
.split(/[ ,.;_-]/)
|
||||||
|
.filter((x) => x.length > 0);
|
||||||
|
if (split_sep.length >= 2) {
|
||||||
|
return split_sep[0].charAt(0) + split_sep[1].charAt(0);
|
||||||
|
}
|
||||||
|
return name.substring(0, 2);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue