Compare commits
105 Commits
Author | SHA1 | Date |
---|---|---|
Jef Roosens | d8b0d35c40 | |
Jef Roosens | 6c7df4b30e | |
Jef Roosens | 6ff4cef5d4 | |
Jef Roosens | a1a0f38f74 | |
Renovate Bot | 1d83ee4338 | |
Renovate Bot | 2f66ce4e22 | |
Renovate Bot | 9cbdfff62f | |
Renovate Bot | 7dfb3c0e20 | |
Jef Roosens | fe9c19f0e8 | |
Renovate Bot | f4aba0c16f | |
Jef Roosens | 7cebe510f7 | |
Renovate Bot | d4872e9c48 | |
Jef Roosens | a35b9a73f1 | |
Renovate Bot | af8660f99e | |
Jef Roosens | 8207e104ae | |
Renovate Bot | 4e24ad8988 | |
Jef Roosens | a826d4272a | |
Renovate Bot | f6faaf0db9 | |
Jef Roosens | 204f8f0a56 | |
Jef Roosens | cc9ff7635c | |
Jef Roosens | 6d95ffd372 | |
Jef Roosens | 237568d5e4 | |
Jef Roosens | be797de526 | |
Jef Roosens | 03020fe798 | |
Renovate Bot | 82bb4c6a6e | |
Jef Roosens | 4cf9152fc4 | |
Jef Roosens | 8baeda4cae | |
Jef Roosens | 2547434d95 | |
Jef Roosens | b9d0bb7aa5 | |
Jef Roosens | faa4f713c8 | |
Jef Roosens | c8bfc16af8 | |
Jef Roosens | 9dbb4c8804 | |
Jef Roosens | 728e72e47c | |
Jef Roosens | 01aa4bae80 | |
Jef Roosens | 2a14703097 | |
Jef Roosens | 81c0d5e00b | |
Jef Roosens | 63316314aa | |
Jef Roosens | 0ec5e33860 | |
Jef Roosens | 9d065c229e | |
Jef Roosens | b8f31aa337 | |
Jef Roosens | bd51b6ce14 | |
Jef Roosens | 4666790784 | |
Jef Roosens | 92c6e2c5cc | |
Jef Roosens | ff1631b525 | |
Jef Roosens | cd4075d294 | |
Jef Roosens | 785acd5c2e | |
Renovate Bot | 48802dbc3c | |
Jef Roosens | 487edf9ebd | |
Renovate Bot | d7ee53e62c | |
Jef Roosens | f9da125b4a | |
Jef Roosens | 135e74e6e3 | |
Renovate Bot | 5725b91c61 | |
Jef Roosens | 336ff25249 | |
Jef Roosens | 3bbc90ad60 | |
Jef Roosens | 472f890a98 | |
Jef Roosens | 3f5c0d038b | |
Jef Roosens | fd6b3ed134 | |
Jef Roosens | 92a08a17af | |
Jef Roosens | 9946aaf001 | |
Jef Roosens | 1da94c5211 | |
Jef Roosens | 6532fbebb1 | |
Jef Roosens | 0b86ed9254 | |
Jef Roosens | d2e6028104 | |
Renovate Bot | 9f31c69777 | |
Renovate Bot | 39ad811429 | |
Jef Roosens | bef7505631 | |
Jef Roosens | 5ce3f0bb39 | |
Jef Roosens | e67616baa1 | |
Jef Roosens | 36bd27c919 | |
Renovate Bot | 1cf009c212 | |
Jef Roosens | e179b1eadb | |
Renovate Bot | e5b872acdf | |
Jef Roosens | a738951961 | |
Renovate Bot | 8e3425749f | |
Jef Roosens | f27775910f | |
Jef Roosens | 4b3ae8a9a4 | |
Jef Roosens | d2ad0591f6 | |
Jef Roosens | 28bb959c12 | |
Jef Roosens | 5a95ee5270 | |
Jef Roosens | e0ac8ddd24 | |
Jef Roosens | 628a918682 | |
Jef Roosens | 0055667877 | |
Jef Roosens | 687632a704 | |
Jef Roosens | 659632eba5 | |
Jef Roosens | 77e04d5b6b | |
Jef Roosens | 2c75e29e1b | |
Jef Roosens | 683e48281f | |
Renovate Bot | caa92377f6 | |
Jef Roosens | 3bdf79e824 | |
Jef Roosens | 0abfaca967 | |
Jef Roosens | 62738354a0 | |
Jef Roosens | 2a4153d430 | |
Jef Roosens | 9e428b1882 | |
Renovate Bot | 0082076527 | |
Jef Roosens | 7ccfe6eebf | |
Jef Roosens | f1416aaa48 | |
Renovate Bot | 26ec8b4eba | |
Renovate Bot | b93d771372 | |
Jef Roosens | e5b9c285fa | |
Renovate Bot | bf8a0ae666 | |
Jef Roosens | ecec03134a | |
Jef Roosens | 5b0e595253 | |
Jef Roosens | 85611e2d59 | |
Jef Roosens | 0877cc590c | |
Jef Roosens | 91985a1710 |
|
@ -1,20 +1,42 @@
|
|||
*
|
||||
|
||||
# Source code
|
||||
# =====BACKEND=====
|
||||
## Source code
|
||||
!src/
|
||||
|
||||
# Cargo files
|
||||
## Cargo files
|
||||
!Cargo.toml
|
||||
!Cargo.lock
|
||||
|
||||
# Entrypoint for devop container
|
||||
## Entrypoint for devop container
|
||||
!docker/entrypoint_dev.sh
|
||||
!docker/entrypoint.sh
|
||||
|
||||
# Config file
|
||||
## Config file
|
||||
!Rocket.toml
|
||||
|
||||
# Database migrations
|
||||
## Database migrations
|
||||
!migrations/
|
||||
|
||||
## Crontab for release container
|
||||
!docker/crontab
|
||||
|
||||
|
||||
# =====FRONTEND=====
|
||||
## Source code
|
||||
!web/src/
|
||||
|
||||
## Public assets
|
||||
!web/public/
|
||||
!web/index.html
|
||||
|
||||
## Production env file
|
||||
!web/.env.production
|
||||
|
||||
## Package manager stuff
|
||||
!web/package.json
|
||||
!web/yarn.lock
|
||||
|
||||
## Project configs
|
||||
!web/tsconfig.json
|
||||
!web/vite.config.ts
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = false
|
||||
indent_style = space
|
||||
indent_size = 4
|
|
@ -0,0 +1,91 @@
|
|||
pipeline:
|
||||
# Download the cache from S3
|
||||
restore-cache:
|
||||
image: plugins/s3-cache
|
||||
pull: true
|
||||
|
||||
endpoint: https://s3.roosens.me
|
||||
root: build-cache/
|
||||
restore: true
|
||||
|
||||
secrets: [ cache_s3_access_key, cache_s3_secret_key ]
|
||||
|
||||
|
||||
# =====BUILDING=====
|
||||
build-frontend:
|
||||
image: node:15-alpine3.13
|
||||
pull: true
|
||||
group: build
|
||||
commands:
|
||||
- cd web
|
||||
- yarn install
|
||||
- yarn run build
|
||||
|
||||
build-backend:
|
||||
image: chewingbever/fej-builder:latest
|
||||
pull: true
|
||||
group: build
|
||||
environment:
|
||||
- CARGO_HOME=.cargo
|
||||
commands:
|
||||
- cargo build
|
||||
|
||||
|
||||
# =====TESTING=====
|
||||
test-backend:
|
||||
image: chewingbever/fej-builder:latest
|
||||
environment:
|
||||
- CARGO_HOME=.cargo
|
||||
commands:
|
||||
- cargo test
|
||||
|
||||
|
||||
# =====LINTING=====
|
||||
lint-frontend:
|
||||
image: node:15-alpine3.13
|
||||
group: lint
|
||||
commands:
|
||||
- cd web
|
||||
- yarn run lint
|
||||
|
||||
lint-backend:
|
||||
image: chewingbever/fej-builder:latest
|
||||
group: lint
|
||||
environment:
|
||||
- CARGO_HOME=.cargo
|
||||
commands:
|
||||
- cargo fmt -- --check
|
||||
# This is run here because it requires compilation
|
||||
- cargo clippy --all-targets -- -D warnings
|
||||
|
||||
|
||||
# =====REBUILD & FLUSH CACHE=====
|
||||
rebuild-cache:
|
||||
image: plugins/s3-cache
|
||||
|
||||
endpoint: https://s3.roosens.me
|
||||
root: build-cache/
|
||||
rebuild: true
|
||||
mount:
|
||||
- target
|
||||
- .cargo
|
||||
- web/node_modules
|
||||
|
||||
secrets: [ cache_s3_access_key, cache_s3_secret_key ]
|
||||
# Push the cache, even on failure
|
||||
when:
|
||||
status: [ success, failure ]
|
||||
|
||||
flush-cache:
|
||||
image: plugins/s3-cache
|
||||
|
||||
endpoint: https://s3.roosens.me
|
||||
root: build-cache/
|
||||
flush: true
|
||||
# Delete cache older than 30 days (might lower this)
|
||||
flush_age: 14
|
||||
|
||||
secrets: [ cache_s3_access_key, cache_s3_secret_key ]
|
||||
# Push the cache, even on failure
|
||||
when:
|
||||
status: [ success, failure ]
|
|
@ -58,9 +58,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.15"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -98,12 +98,6 @@ dependencies = [
|
|||
"safemem",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.0"
|
||||
|
@ -323,9 +317,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "diesel"
|
||||
version = "1.4.6"
|
||||
version = "1.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "047bfc4d5c3bd2ef6ca6f981941046113524b9a9f9a7cbdfdd7ff40f58e6f542"
|
||||
checksum = "b28135ecf6b7d446b43e27e225622a038cc4e2930a1022f51cdb97ada19b8e4d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
|
@ -861,9 +855,9 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
|||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.4"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
|
||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
||||
|
||||
[[package]]
|
||||
name = "migrations_internals"
|
||||
|
@ -1342,9 +1336,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.4.5"
|
||||
version = "1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -1353,9 +1347,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.23"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
|
@ -1406,12 +1400,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rocket"
|
||||
version = "0.4.7"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7febfdfd4d43facfc7daba20349ebe2c310c6735bd6a2a9255ea8bc425b4cb13"
|
||||
checksum = "4a7ab1dfdc75bb8bd2be381f37796b1b300c45a3c9145b34d86715e8dd90bf28"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"base64 0.12.3",
|
||||
"base64 0.13.0",
|
||||
"log 0.4.14",
|
||||
"memchr",
|
||||
"num_cpus",
|
||||
|
@ -1427,9 +1421,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rocket_codegen"
|
||||
version = "0.4.7"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ceac2c55b2c8b1cdc53add64332defa5fc227f64263b86b4114d1386286d42a3"
|
||||
checksum = "1729e687d6d2cf434d174da84fb948f7fef4fac22d20ce94ca61c28b72dbcf9f"
|
||||
dependencies = [
|
||||
"devise",
|
||||
"glob",
|
||||
|
@ -1442,9 +1436,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rocket_contrib"
|
||||
version = "0.4.7"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7954a707f9ca18aa74ca8c1f5d1f900f52a4dceb68e96e3112143f759cfd20e"
|
||||
checksum = "6b6303dccab46dce6c7ac26c9b9d8d8cde1b19614b027c3f913be6611bff6d9b"
|
||||
dependencies = [
|
||||
"diesel",
|
||||
"log 0.4.14",
|
||||
|
@ -1458,9 +1452,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rocket_contrib_codegen"
|
||||
version = "0.4.7"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30deb6dec53b91fac3538a2a3935cf13e0f462745f9f33bf27bedffbe7265b5d"
|
||||
checksum = "a0f2cbcb6c09b3ac0acdf77682ff8c9d1f317361498a773ee50b32be7fddfe2b"
|
||||
dependencies = [
|
||||
"devise",
|
||||
"quote 0.6.13",
|
||||
|
@ -1470,9 +1464,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rocket_http"
|
||||
version = "0.4.7"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce364100ed7a1bf39257b69ebd014c1d5b4979b0d365d8c9ab0aa9c79645493d"
|
||||
checksum = "6131e6e6d38a9817f4a494ff5da95971451c2eb56a53915579fc9c80f6ef0117"
|
||||
dependencies = [
|
||||
"cookie 0.11.4",
|
||||
"hyper 0.10.16",
|
||||
|
@ -1580,18 +1574,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.125"
|
||||
version = "1.0.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
|
||||
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.125"
|
||||
version = "1.0.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
||||
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.26",
|
||||
"quote 1.0.9",
|
||||
|
|
26
Cargo.toml
26
Cargo.toml
|
@ -4,6 +4,10 @@ version = "1.0.2"
|
|||
authors = ["Jef Roosens <roosensjef@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
# Enables hosting of the frontend
|
||||
frontend = []
|
||||
|
||||
[lib]
|
||||
name = "fej"
|
||||
path = "src/fej/lib.rs"
|
||||
|
@ -19,18 +23,26 @@ test = true
|
|||
bench = true
|
||||
doc = true
|
||||
doctest = true
|
||||
|
||||
[[bin]]
|
||||
name = "populate_ivago"
|
||||
path = "src/populate_ivago.rs"
|
||||
test = false
|
||||
bench = false
|
||||
doc = false
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
rocket = "0.4.7"
|
||||
serde = "1.0.124"
|
||||
rocket = "0.4.10"
|
||||
serde = "1.0.126"
|
||||
chrono = "0.4.19"
|
||||
chrono-tz = "0.5.3"
|
||||
regex = "1.4.5"
|
||||
reqwest = { version = "0.11.2", features = ["blocking", "json", "cookies"] }
|
||||
diesel = { version = "1.4.6", features = ["postgres"] }
|
||||
regex = "1.5.4"
|
||||
reqwest = { version = "0.11.3", features = ["blocking", "json", "cookies"] }
|
||||
diesel = { version = "1.4.8", features = ["postgres"] }
|
||||
diesel_migrations = "1.4.0"
|
||||
|
||||
[dependencies.rocket_contrib]
|
||||
version = "0.4.7"
|
||||
version = "0.4.10"
|
||||
default-features = false
|
||||
features = ["json", "diesel_postgres_pool"]
|
||||
features = ["json", "diesel_postgres_pool", "serve"]
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
# see diesel.rs/guides/configuring-diesel-cli
|
||||
|
||||
[print_schema]
|
||||
file = "src/schema.rs"
|
||||
file = "src/fej/schema.rs"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# vim: filetype=dockerfile
|
||||
# Our entire toolchain runs in alpine
|
||||
FROM alpine:latest AS builder
|
||||
FROM alpine:3.13.5 AS builder
|
||||
|
||||
ENV PATH "$PATH:/app/.cargo/bin"
|
||||
ENV PATH "$PATH:/root/.cargo/bin"
|
||||
# Needed for proper compiling of openssl-dev
|
||||
ENV RUSTFLAGS "-C target-feature=-crt-static"
|
||||
|
||||
|
@ -19,18 +19,7 @@ RUN addgroup -S builder && \
|
|||
openssl-dev \
|
||||
postgresql-dev
|
||||
|
||||
# Switch to the non-root user
|
||||
USER builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install rustup in the new user's home
|
||||
# Create mountpoints for volumes with correct permissions
|
||||
RUN { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly; } && \
|
||||
rustup target add x86_64-unknown-linux-musl --toolchain nightly && \
|
||||
mkdir -p .cargo/registry target
|
||||
|
||||
# Copy source code over to builder
|
||||
COPY --chown=builder:builder Cargo.toml Cargo.lock ./
|
||||
COPY --chown=builder:builder src/ ./src/
|
||||
COPY --chown=builder:builder migrations/ ./migrations/
|
||||
rustup target add x86_64-unknown-linux-musl --toolchain nightly
|
||||
|
|
|
@ -3,6 +3,10 @@ FROM chewingbever/fej-builder:latest
|
|||
|
||||
ENV RUST_BACKTRACE 1
|
||||
|
||||
# Copy source code over to builder
|
||||
COPY --chown=builder:builder Cargo.toml Cargo.lock ./
|
||||
COPY --chown=builder:builder src/ ./src/
|
||||
COPY --chown=builder:builder migrations/ ./migrations/
|
||||
COPY --chown=builder:builder ./docker/entrypoint_dev.sh /entrypoint.sh
|
||||
COPY --chown=builder:builder ./Rocket.toml /app/Rocket.toml
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
# vim: filetype=dockerfile
|
||||
FROM chewingbever/fej-builder:latest AS builder
|
||||
FROM chewingbever/fej-builder:latest AS backend-builder
|
||||
|
||||
COPY --chown=builder:builder Cargo.toml Cargo.lock ./
|
||||
COPY --chown=builder:builder src/ ./src/
|
||||
COPY --chown=builder:builder migrations/ ./migrations/
|
||||
|
||||
# And then finally, build the project
|
||||
# Thank the lords that this article exists
|
||||
|
@ -15,11 +19,22 @@ FROM chewingbever/fej-builder:latest AS builder
|
|||
RUN cargo install \
|
||||
--path . \
|
||||
--root /app/output \
|
||||
--target x86_64-unknown-linux-musl
|
||||
--target x86_64-unknown-linux-musl \
|
||||
--features frontend
|
||||
|
||||
|
||||
FROM node:17-alpine3.13 AS frontend-builder
|
||||
|
||||
COPY ./web /app
|
||||
WORKDIR /app
|
||||
|
||||
# Build the frontend
|
||||
RUN yarn install && \
|
||||
yarn run build
|
||||
|
||||
|
||||
# Now, we create the actual image
|
||||
FROM alpine:latest
|
||||
FROM alpine:3.13.5
|
||||
COPY ./docker/crontab /var/spool/cron/crontabs/fej
|
||||
|
||||
# Install some dynamic libraries needed for everything to work
|
||||
|
@ -37,8 +52,9 @@ RUN apk update && \
|
|||
# Switch to non-root user
|
||||
USER fej:fej
|
||||
|
||||
# Copy binary over to final image
|
||||
COPY --from=builder --chown=fej:fej /app/output/bin /app/bin
|
||||
# Copy binary & frontend over to final image
|
||||
COPY --from=backend-builder --chown=fej:fej /app/output/bin /app/bin
|
||||
COPY --from=frontend-builder --chown=fej:fej /app/dist /app/dist
|
||||
|
||||
# Embed config file inside container
|
||||
# The workdir is changed so that the config file is read properly
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
# This'll be filled up later
|
||||
# Runs the ivago scraper
|
||||
*/30 * * * * /app/bin/populate_ivago
|
||||
|
|
|
@ -13,7 +13,7 @@ services:
|
|||
- 'DATABASE_URL=postgres://fej:fej@db:5432/fej'
|
||||
|
||||
db:
|
||||
image: 'postgres:13-alpine'
|
||||
image: 'postgres:14-alpine'
|
||||
restart: 'always'
|
||||
|
||||
environment:
|
||||
|
|
26
fejctl
26
fejctl
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
image='chewingbever/fej'
|
||||
web_dir='web'
|
||||
|
||||
# Small wrapper around the docker-compose command
|
||||
#
|
||||
|
@ -18,16 +19,6 @@ function dc() {
|
|||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
if [[ "$build_builder" -eq 1 ]]; then
|
||||
# We always rebuild the builder before we run any compose command
|
||||
DOCKER_BUILDKIT=1 docker build \
|
||||
-f docker/Dockerfile.builder \
|
||||
-t "$image-builder:latest" . || {
|
||||
>&2 echo "Failed to build builder.";
|
||||
exit 1;
|
||||
}
|
||||
fi
|
||||
|
||||
if [[ "$release" -eq 1 ]]; then
|
||||
DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker-compose \
|
||||
--file docker/docker-compose.yml \
|
||||
|
@ -53,6 +44,18 @@ function dcr() {
|
|||
--detach
|
||||
}
|
||||
|
||||
# Publish the builder image
|
||||
function publish_builder() {
|
||||
DOCKER_BUILDKIT=1 docker build \
|
||||
-f docker/Dockerfile.builder \
|
||||
-t "$image-builder:latest" . || {
|
||||
>&2 echo "Failed to build builder.";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
docker push "$image-builder:latest"
|
||||
}
|
||||
|
||||
# Tags & pushes the release version to Docker Hub
|
||||
function publish() {
|
||||
local branch=`git rev-parse --abbrev-ref HEAD`
|
||||
|
@ -96,10 +99,12 @@ function main() {
|
|||
# Building
|
||||
b | build ) dcr build --bin "$bin" && dc -- logs -f app ;;
|
||||
br | build-release ) dc -br build ;;
|
||||
bf | build-frontend ) cd "$web_dir" && yarn run build ;;
|
||||
|
||||
# Running
|
||||
r | run ) dcr run --bin "$bin" && dc -- logs -f app ;;
|
||||
rr | run-release ) dc -br -- up --build --detach && dc -r -- logs -f app ;;
|
||||
rf | run-frontend ) dcr run --bin server && cd "$web_dir" && yarn run dev ;;
|
||||
s | stop ) dc down ;;
|
||||
sr | stop-release ) dc -r stop ;;
|
||||
|
||||
|
@ -113,6 +118,7 @@ function main() {
|
|||
l | logs ) dc -- logs -f app ;;
|
||||
lint ) cargo fmt -- --check ;;
|
||||
p | push | publish ) publish ;;
|
||||
pb ) publish_builder ;;
|
||||
t | test ) dcr -- test --no-fail-fast && dc -- logs -f app ;;
|
||||
* ) >&2 echo "Invalid command."; exit 1 ;;
|
||||
esac
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
-- This file should undo anything in `up.sql`
|
||||
DROP SCHEMA ivago CASCADE;
|
||||
DROP table ivago_streets;
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
-- Your SQL goes here
|
||||
CREATE SCHEMA ivago;
|
||||
|
||||
CREATE TABLE ivago.streets (
|
||||
CREATE TABLE ivago_streets (
|
||||
name TEXT NOT NULL,
|
||||
city TEXT NOT NULL,
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||
}
|
|
@ -8,6 +8,7 @@ use rocket::http::Status;
|
|||
pub enum FejError {
|
||||
InvalidArgument,
|
||||
FailedRequest,
|
||||
DatabaseError,
|
||||
}
|
||||
|
||||
// I'd love to move this over to the server binary, but right now, error E0117 is making that
|
||||
|
@ -17,6 +18,7 @@ impl From<FejError> for Status {
|
|||
match err {
|
||||
FejError::InvalidArgument => Status::BadRequest,
|
||||
FejError::FailedRequest => Status::InternalServerError,
|
||||
FejError::DatabaseError => Status::InternalServerError,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,3 +35,9 @@ impl From<chrono::ParseError> for FejError {
|
|||
FejError::InvalidArgument
|
||||
}
|
||||
}
|
||||
|
||||
impl From<diesel::result::Error> for FejError {
|
||||
fn from(_: diesel::result::Error) -> FejError {
|
||||
FejError::DatabaseError
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
use crate::errors::FejError;
|
||||
use chrono::{DateTime, NaiveDate, TimeZone};
|
||||
use chrono_tz::Europe::Brussels;
|
||||
use chrono_tz::Tz;
|
||||
use rocket::http::RawStr;
|
||||
use rocket::request::FromFormValue;
|
||||
use serde::ser::Serializer;
|
||||
use serde::Serialize;
|
||||
use chrono_tz::{Europe::Brussels, Tz};
|
||||
use rocket::{http::RawStr, request::FromFormValue};
|
||||
use serde::{ser::Serializer, Serialize};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
/// This class is a simple wrapper around chrono's DateTime. Its sole purpose
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
use super::Street;
|
||||
use crate::{errors::FejError, schema::ivago_streets::dsl::*};
|
||||
use {diesel::prelude::*, PgConnection};
|
||||
|
||||
pub fn search_streets(db_con: &PgConnection, search_term: &str) -> Result<Vec<Street>, FejError> {
|
||||
Ok(ivago_streets
|
||||
.filter(name.ilike(format!("%{}%", search_term)))
|
||||
.or_filter(city.ilike(format!("%{}%", search_term)))
|
||||
.load(db_con)?)
|
||||
}
|
|
@ -2,10 +2,13 @@ use crate::errors::FejError;
|
|||
use chrono::DateTime;
|
||||
use chrono_tz::Tz;
|
||||
use reqwest::blocking as reqwest;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::{From, TryFrom};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
convert::{From, TryFrom},
|
||||
};
|
||||
|
||||
mod basic_date;
|
||||
pub mod db;
|
||||
mod pickup_time;
|
||||
mod street;
|
||||
|
||||
|
|
|
@ -16,10 +16,7 @@ impl PickupTime {
|
|||
/// * `date` - Date of pickup time
|
||||
/// * `label` - Type of trash
|
||||
pub fn new(date: BasicDate, label: String) -> PickupTime {
|
||||
PickupTime {
|
||||
date: date,
|
||||
label: label,
|
||||
}
|
||||
PickupTime { date, label }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
use crate::schema::ivago_streets;
|
||||
use diesel::{Insertable, Queryable};
|
||||
use regex::Regex;
|
||||
use rocket::http::RawStr;
|
||||
use rocket::request::FromFormValue;
|
||||
use rocket::{http::RawStr, request::FromFormValue};
|
||||
use serde::ser::{Serialize, SerializeStruct, Serializer};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
/// Represents a street in a given city
|
||||
#[derive(Queryable, Insertable)]
|
||||
#[table_name = "ivago_streets"]
|
||||
pub struct Street {
|
||||
name: String,
|
||||
city: String,
|
||||
|
@ -14,10 +17,7 @@ impl Street {
|
|||
// This constructor just makes my life a bit easier during testing
|
||||
#[cfg(test)]
|
||||
fn new(name: String, city: String) -> Street {
|
||||
Street {
|
||||
name: name,
|
||||
city: city,
|
||||
}
|
||||
Street { name, city }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#![feature(proc_macro_hygiene, decl_macro)]
|
||||
#[macro_use]
|
||||
extern crate diesel;
|
||||
|
||||
// Route modules
|
||||
pub mod ivago;
|
||||
|
||||
// Helper modules
|
||||
pub mod errors;
|
||||
|
||||
pub mod schema;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
table! {
|
||||
ivago_streets (name, city) {
|
||||
name -> Text,
|
||||
city -> Text,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
use diesel::{insert_into, Connection, PgConnection, RunQueryDsl};
|
||||
use fej::{ivago::search_streets, schema::ivago_streets::dsl::*};
|
||||
|
||||
const ABC: &str = "abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
fn main() {
|
||||
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||
|
||||
let db_conn = PgConnection::establish(&database_url)
|
||||
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url));
|
||||
|
||||
// Doing this linearly is good enough I'd say
|
||||
for c in ABC.chars() {
|
||||
if let Ok(streets) = search_streets(&c.to_string()) {
|
||||
insert_into(ivago_streets)
|
||||
.values(streets)
|
||||
.execute(&db_conn)
|
||||
.expect("Failed to insert rows.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,15 +15,18 @@ mod routes;
|
|||
|
||||
// Very temporary solution for CORS
|
||||
// https://stackoverflow.com/questions/62412361/how-to-set-up-cors-or-options-for-rocket-rs
|
||||
use rocket::fairing::AdHoc;
|
||||
use rocket::fairing::{Fairing, Info, Kind};
|
||||
use rocket::http::Header;
|
||||
use rocket::{Request, Response, Rocket};
|
||||
use rocket::{
|
||||
fairing::{AdHoc, Fairing, Info, Kind},
|
||||
http::Header,
|
||||
Request, Response, Rocket,
|
||||
};
|
||||
use rocket_contrib::databases::diesel;
|
||||
#[cfg(feature = "frontend")]
|
||||
use rocket_contrib::serve::StaticFiles;
|
||||
|
||||
pub struct CORS;
|
||||
pub struct Cors;
|
||||
|
||||
impl Fairing for CORS {
|
||||
impl Fairing for Cors {
|
||||
fn info(&self) -> Info {
|
||||
Info {
|
||||
name: "Add CORS headers to responses",
|
||||
|
@ -47,7 +50,7 @@ embed_migrations!();
|
|||
|
||||
// This defines a connection to the database
|
||||
#[database("postgres_fej")]
|
||||
struct FejDbConn(diesel::PgConnection);
|
||||
pub struct FejDbConn(diesel::PgConnection);
|
||||
|
||||
// I'd like to thank Stackoverflow for helping me with this
|
||||
// https://stackoverflow.com/questions/61047355/how-to-run-diesel-migration-with-rocket-in-production
|
||||
|
@ -55,17 +58,27 @@ fn run_db_migrations(rocket: Rocket) -> Result<Rocket, Rocket> {
|
|||
let conn = FejDbConn::get_one(&rocket).expect("database connection");
|
||||
match embedded_migrations::run(&*conn) {
|
||||
Ok(()) => Ok(rocket),
|
||||
Err(e) => Err(rocket),
|
||||
Err(_) => Err(rocket),
|
||||
}
|
||||
}
|
||||
|
||||
fn rocket() -> rocket::Rocket {
|
||||
rocket::ignite()
|
||||
.attach(CORS)
|
||||
// This needs to be muted for the frontend feature
|
||||
#[allow(unused_mut)]
|
||||
let mut rocket = rocket::ignite()
|
||||
.attach(Cors)
|
||||
.attach(FejDbConn::fairing())
|
||||
.attach(AdHoc::on_attach("Database Migrations", run_db_migrations))
|
||||
.mount("/ivago", routes::ivago())
|
||||
.register(catchers![catchers::not_found])
|
||||
.mount("/api/ivago", routes::ivago()) // /api being hardcoded is temporary
|
||||
.register(catchers![catchers::not_found]);
|
||||
|
||||
// TODO make all of this not hard-coded
|
||||
#[cfg(feature = "frontend")]
|
||||
{
|
||||
rocket = rocket.mount("/", StaticFiles::from("/app/dist"));
|
||||
}
|
||||
|
||||
rocket
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use fej::ivago::{get_pickup_times, search_streets, BasicDate, PickupTime, Street};
|
||||
use crate::FejDbConn;
|
||||
use fej::ivago::{db::search_streets, get_pickup_times, BasicDate, PickupTime, Street};
|
||||
use rocket::http::Status;
|
||||
use rocket_contrib::json::Json;
|
||||
|
||||
|
@ -9,8 +10,8 @@ use rocket_contrib::json::Json;
|
|||
///
|
||||
/// * `search_term` - Search term to use to look for streets
|
||||
#[get("/search?<q>")]
|
||||
pub fn route_search_streets(q: String) -> Result<Json<Vec<Street>>, Status> {
|
||||
Ok(Json(search_streets(q.as_str())?))
|
||||
pub fn route_search_streets(db_conn: FejDbConn, q: String) -> Result<Json<Vec<Street>>, Status> {
|
||||
Ok(Json(search_streets(&db_conn.0, q.as_str())?))
|
||||
}
|
||||
|
||||
/// Handles returning of pickup times for a specific address. It returns a list
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/// In here, any non-unit tests are placed.
|
||||
use rocket::http::Status;
|
||||
use rocket::local::Client;
|
||||
use rocket::{http::Status, local::Client};
|
||||
|
||||
fn rocket() -> rocket::Rocket {
|
||||
rocket::ignite().mount("/", super::routes::ivago())
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
VITE_ENDPOINT=https://fej.roosens.me/api
|
|
@ -0,0 +1,15 @@
|
|||
env:
|
||||
browser: true
|
||||
es2021: true
|
||||
extends:
|
||||
- 'plugin:vue/essential'
|
||||
- standard
|
||||
parserOptions:
|
||||
ecmaVersion: 12
|
||||
parser: '@typescript-eslint/parser'
|
||||
sourceType: module
|
||||
plugins:
|
||||
- vue
|
||||
- '@typescript-eslint'
|
||||
rules:
|
||||
indent: ["error", 4]
|
|
@ -0,0 +1,130 @@
|
|||
# Created by https://www.toptal.com/developers/gitignore/api/node
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=node
|
||||
|
||||
### Node ###
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
.env*.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Storybook build outputs
|
||||
.out
|
||||
.storybook-out
|
||||
storybook-static
|
||||
|
||||
# rollup.js default build output
|
||||
dist/
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# Temporary folders
|
||||
tmp/
|
||||
temp/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/node
|
|
@ -0,0 +1,27 @@
|
|||
# Vue 3 + Typescript + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 and Typescript in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Vetur](https://marketplace.visualstudio.com/items?itemName=octref.vetur). Make sure to enable `vetur.experimental.templateInterpolationService` in settings!
|
||||
|
||||
### If Using `<script setup>`
|
||||
|
||||
[`<script setup>`](https://github.com/vuejs/rfcs/pull/227) is a feature that is currently in RFC stage. To get proper IDE support for the syntax, use [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) instead of Vetur (and disable Vetur).
|
||||
|
||||
## Type Support For `.vue` Imports in TS
|
||||
|
||||
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can use the following:
|
||||
|
||||
### If Using Volar
|
||||
|
||||
Run `Volar: Switch TS Plugin on/off` from VSCode command palette.
|
||||
|
||||
### If Using Vetur
|
||||
|
||||
1. Install and add `@vuedx/typescript-plugin-vue` to the [plugins section](https://www.typescriptlang.org/tsconfig#plugins) in `tsconfig.json`
|
||||
2. Delete `src/shims-vue.d.ts` as it is no longer needed to provide module info to Typescript
|
||||
3. Open `src/main.ts` in VSCode
|
||||
4. Open the VSCode command palette
|
||||
5. Search and run "Select TypeScript version" -> "Use workspace version"
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Fej</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "fej-frontend",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc --noEmit && vite build",
|
||||
"serve": "vite preview",
|
||||
"lint": "eslint --ext .js,.vue src",
|
||||
"format": "yarn run lint --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.0.5",
|
||||
"vue-router": "^4.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
||||
"@typescript-eslint/parser": "^4.22.0",
|
||||
"@vitejs/plugin-vue": "^1.2.1",
|
||||
"@vue/compiler-sfc": "^3.0.5",
|
||||
"eslint": "^8.0.0",
|
||||
"eslint-config-standard": "^16.0.2",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.0.0",
|
||||
"eslint-plugin-vue": "^7.9.0",
|
||||
"typescript": "^4.1.3",
|
||||
"vite": "^2.2.1",
|
||||
"vue-tsc": "^0.1.0"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<div>
|
||||
<Nav />
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import Nav from './components/Nav.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'App',
|
||||
components: {
|
||||
Nav
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
margin-top: 60px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,18 @@
|
|||
export interface Street {
|
||||
name: string
|
||||
city: string
|
||||
}
|
||||
|
||||
export async function search (searchTerm: string): Promise<Street[]> {
|
||||
const baseURL = import.meta.env.VITE_ENDPOINT as string
|
||||
|
||||
const r = await fetch(`${baseURL}/ivago/search?` + new URLSearchParams({
|
||||
q: searchTerm
|
||||
}))
|
||||
|
||||
if (!r.ok) {
|
||||
return Promise.reject()
|
||||
}
|
||||
|
||||
return r.json()
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
|
@ -0,0 +1,15 @@
|
|||
<template>
|
||||
<div>
|
||||
<h1>Fej</h1>
|
||||
<p>Welcome to Fej, my frontend/backend combo.</p>
|
||||
<p>If you can see this, the cicd worked!</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Home'
|
||||
})
|
||||
</script>
|
|
@ -0,0 +1,61 @@
|
|||
<template>
|
||||
<div>
|
||||
<h1>Ivago</h1>
|
||||
<input
|
||||
v-model="query"
|
||||
v-on:keyup.enter="search"
|
||||
type="text"
|
||||
placeholder="Street..." />
|
||||
<div id="scroll-list">
|
||||
<ul v-if="msg === ''">
|
||||
<li
|
||||
v-for="item in items"
|
||||
v-bind:key="`${item.name} (${item.city})`" >
|
||||
{{ item.name }} ({{ item.city }})
|
||||
</li>
|
||||
</ul>
|
||||
<p v-else>{{ msg }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { Street, search as ivagoSearch } from '../api/ivago'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Ivago',
|
||||
data () {
|
||||
return {
|
||||
items: [] as Street[],
|
||||
msg: '',
|
||||
query: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
search () {
|
||||
this.items = []
|
||||
this.msg = 'Loading...'
|
||||
|
||||
if (this.query === '') {
|
||||
this.msg = ''
|
||||
return
|
||||
}
|
||||
|
||||
ivagoSearch(this.query)
|
||||
.then((res: Street[]) => {
|
||||
this.items = res
|
||||
this.msg = ''
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#scroll-list {
|
||||
height: 200px;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,43 @@
|
|||
<template>
|
||||
<div id="menu-wrapper">
|
||||
<nav id="menu">
|
||||
<router-link to="/">Home</router-link>
|
||||
<router-link to="/ivago">Ivago</router-link>
|
||||
</nav>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Nav'
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#menu-wrapper {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 150px;
|
||||
background-color: #242624;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#menu {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
#menu > a {
|
||||
display: block;
|
||||
width: 100%;
|
||||
color: #5f635f;
|
||||
text-decoration: none;
|
||||
}
|
||||
#menu > a:hover {
|
||||
color: #c2ccc1;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,8 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(router)
|
||||
|
||||
app.mount('#app')
|
|
@ -0,0 +1,21 @@
|
|||
import { createWebHistory, createRouter } from 'vue-router'
|
||||
import Home from './components/Home.vue'
|
||||
import Ivago from './components/Ivago.vue'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
component: Home
|
||||
},
|
||||
{
|
||||
path: '/ivago',
|
||||
component: Ivago
|
||||
}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes
|
||||
})
|
||||
|
||||
export default router
|
|
@ -0,0 +1,5 @@
|
|||
declare module '*.vue' {
|
||||
import { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["esnext", "dom"],
|
||||
"types": ["vite/client"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()]
|
||||
})
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue