Compare commits

..

48 Commits

Author SHA1 Message Date
Kacper Donat
f49c7287fd #59 - Add ability to replace favourite with confirmation. 2020-10-20 21:10:56 +02:00
Kacper Donat
f2bdeb0004 #59 - add proper style for primary button 2020-10-19 23:11:37 +02:00
Kacper Donat
9420764e9b #62 - Fix some tiny errors related to background 2020-10-02 21:08:38 +02:00
Kacper Donat
ccbe88a532 #18 - Refine modal system 2020-10-02 20:00:24 +02:00
Kacper Donat
ceaa13bf2a #18 - Basic Modal system 2020-10-02 20:00:24 +02:00
Kacper Donat
dcd3962220 #62 - Add background 2020-10-01 22:04:16 +02:00
Kacper Donat
c541cf1a11 #57 - Replace google analytics with google tag manager 2020-09-19 19:26:18 +02:00
Kacper Donat
ec479e5d77 Unify provider and main webapp manifest (manifest.json) 2020-09-18 22:47:22 +02:00
Kacper Donat
3abfa6dac3 Provide better maskable icon 2020-09-18 22:16:29 +02:00
Kacper Donat
bb81077d1c Add basic noscript warning 2020-09-18 21:58:29 +02:00
Kacper Donat
4e86e127d8 Add support for maskable and monochrome icons 2020-09-18 21:57:38 +02:00
Kacper Donat
7b7b59ce23 #40 - (Hot) Fix Aggregate Converter loop 2020-05-03 00:03:54 +02:00
Kacper Donat
0c5ffbb567 #40 - Fix passing provider to Vue 2020-05-02 23:51:50 +02:00
Kacper Donat
af6a2a0756 #40 - Fix typo in provider picker header 2020-05-02 23:39:27 +02:00
Kacper Donat
2659acdc58 #40 - Add map based provider picker 2020-05-02 23:33:15 +02:00
Kacper Donat
03058f251b #40 - Add provider DTO and API endpoint 2020-05-02 00:58:03 +02:00
Kacper Donat
4b9a9c54d8 #48 - Fix bug with non serializing recursive departure 2020-03-21 15:41:49 +01:00
Kacper Donat
057a7d6d01 #41 - Move messaging settings to vuex store 2020-03-19 20:22:50 +01:00
Kacper Donat
984cb37c8f #33 - Relative departure times 2020-03-19 17:28:26 +01:00
Kacper Donat
7a54569820 #47 - Extract departures settings to its own component and store module 2020-03-18 22:05:40 +01:00
Kacper Donat
c781ca3dbc #47 - UI - Add UiNumericInput component 2020-03-18 16:33:06 +01:00
Kacper Donat
7d0e141d4e Merge branch '35_new_repository_pattern_with_filters_and_modifiers' 2020-03-16 21:33:15 +01:00
Kacper Donat
720327424a #35 - Add paginator to properly handle limits 2020-03-16 20:32:15 +01:00
Kacper Donat
db30d69cdb #35 - Add Limit support for departure repository 2020-03-15 22:35:12 +01:00
Kacper Donat
f3a6c3e8eb Add blackfire service for profiling 2020-03-15 17:30:08 +01:00
Kacper Donat
9506881792 #35 - WIP - Add scheduled stop repository 2020-03-15 12:50:38 +01:00
Kacper Donat
b609b81ddf #35 - Extract HandlerProvider to own class 2020-03-14 17:19:43 +01:00
Kacper Donat
5703816498 Fix situation when there are multiple first stops on same trip 2020-03-14 12:37:11 +01:00
Kacper Donat
129a4dc588 Fix situation when there are multiple first stops on same trip 2020-03-14 12:36:24 +01:00
Kacper Donat
7fa5124577 #35 - Add support for multiple related objects filtering 2020-02-23 17:12:23 +01:00
Kacper Donat
e8a31f60d1 Various little fixes and improvements 2020-02-23 15:23:14 +01:00
Kacper Donat
42ee6e091d #35 - Track stops fluent quering 2020-02-20 17:33:31 +01:00
Kacper Donat
f4e3ee6f55 #35 - Add stop filter for tracks 2020-02-18 22:45:16 +01:00
Kacper Donat
9d0e4fdb2a #35 - Rewrite Track Repository into fluent pattern 2020-02-17 21:48:51 +01:00
Kacper Donat
c7dc90bfc5 #35 - Move trip and operator repository to fluent pattern 2020-02-16 21:59:38 +01:00
Kacper Donat
d72fcf777f #35 - Make StopRepository more fluent 2020-02-16 21:09:07 +01:00
Kacper Donat
fd4bcc9c70 #35 - Remove unnecessary methods from LineRepository 2020-02-12 20:16:26 +01:00
Kacper Donat
d7fb3032b7 #35 - Add service subscriber to database repository 2020-02-12 20:08:56 +01:00
Kacper Donat
16882ee06f #35 - fluent repository prototype 2020-02-11 22:48:30 +01:00
Kacper Donat
8ebf5ac137 #22 - Fix missing icon in favourites adder 2020-02-11 20:12:33 +01:00
Kacper Donat
749fd773b6 #12 - rebrand to 'Co Jedzie' as 'Czy Dojade' is taken 2020-02-10 22:38:49 +01:00
Kacper Donat
d6850773b6 #22 - Create icon library 2020-02-09 21:59:33 +01:00
Kacper Donat
8d5bdc061d Restyle inputs 2020-02-09 15:56:29 +01:00
Kacper Donat
0fc0dd07e4 #32 - Switch instead of checkbox 2020-02-09 14:05:46 +01:00
Kacper Donat
493c3852d8 #32 - Switch instead of checkbox 2020-02-09 13:56:22 +01:00
Kacper Donat
449efd7536 Fixed build errors 2020-02-08 21:50:20 +01:00
Kacper Donat
f2f7b19380 #38 - Add lines to destinations
This is useful when we have few different stops, with same destinations and different lines.
2020-02-08 18:36:29 +01:00
Kacper Donat
0895b412d2 #38 - Display only unique destinations 2020-02-08 15:14:46 +01:00
369 changed files with 3487 additions and 7003 deletions

View File

@ -1 +0,0 @@
PHP_IDE_CONFIG=serverName=cojedzie

View File

@ -1,31 +0,0 @@
server {
root /var/www/front/public/;
server_name cojedzie.localhost;
location /_profiler/ {
try_files $uri $uri/ @api;
}
location /bundles/ {
try_files $uri $uri/ @api;
}
location /api/ {
try_files $uri $uri/ @api;
}
location / {
try_files $uri $uri/ @frontend;
}
location @frontend {
proxy_pass http://frontend:3000;
proxy_intercept_errors on;
}
location @api {
proxy_pass http://api:8080;
proxy_intercept_errors on;
}
}

View File

@ -1,44 +0,0 @@
server {
root /var/www/front/public/;
server_name cojedzie.localhost;
location /api/ {
root /var/www/api/public/;
try_files $uri $uri/ index.php$is_args$args;
}
location /_profiler/ {
root /var/www/api/public/;
try_files $uri $uri/ index.php$is_args$args;
}
location /bundles/ {
root /var/www/api/public/;
try_files $uri $uri/;
}
location / {
try_files $uri $uri/ @frontend;
}
location @frontend {
proxy_pass http://frontend:3000;
proxy_intercept_errors on;
}
location ~ (.+).php(/|$) {
root /var/www/api/public/;
fastcgi_pass api:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/public/$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT /var/www/public/;
fastcgi_param APP_ENV "dev";
fastcgi_param DATABASE_URL "sqlite:///%kernel.project_dir%/var/app.db";
internal;
}
}

17
.env.dist Normal file
View File

@ -0,0 +1,17 @@
# This file is a "template" of which env vars need to be defined for your application
# Copy this file to .env file for development, create environment variables when deploying to production
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
GTM_TAG=
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=1bdf86cdc78fba654e4f2c309c6bbdbd
###< symfony/framework-bundle ###
###> doctrine/doctrine-bundle ###
# Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
# Configure your db driver and server_version in config/packages/doctrine.yaml
DATABASE_URL=sqlite:///%kernel.project_dir%/var/app.db
###< doctrine/doctrine-bundle ###

18
.gitignore vendored
View File

@ -1 +1,19 @@
###> symfony/framework-bundle ###
/.env
/public/bundles/
/var/
/vendor/
###< symfony/framework-bundle ###
###> symfony/web-server-bundle ###
/.web-server-pid
###< symfony/web-server-bundle ###
/node_modules/
/.idea/ /.idea/
/public/*
!/public/index.php
!/public/manifest.jso
/yarn-error.log

71
CLA.md
View File

@ -1,71 +0,0 @@
# Co Jedzie Individual Contributor License Agreement
Adapted from http://www.apache.org/licenses/icla.txt © The Apache Software Foundation
Thank you for your interest in Co Jedzie (the **"Project"**) by Kacper Donat (the **"Author"**). In order to clarify the
intellectual property license granted with Contributions from any person or entity, the Author must have a Contributor
License Agreement ("CLA") on file that has been signed by each Contributor, indicating agreement to the license terms
below. This license is for your protection as a Contributor as well as the protection of the Author and its users; it
does not change your rights to use your own Contributions for any other purpose.
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to the
Author. In return, the Author shall not use Your Contributions in a way that is contrary to the public benefit or
inconsistent with its bylaws in effect at the time of the Contribution. Except for the license granted herein to the
Author and recipients of software distributed by the Author, You reserve all right, title, and interest in and to Your
Contributions.
1. Definitions.
- **"You"** (or **"Your"**) shall mean the copyright owner or legal entity authorized by the copyright owner that is
making this Agreement with the Author. For legal entities, the entity making a Contribution and all other entities
that control, are controlled by, or are under common control with that entity are considered to be a single
Contributor. For the purposes of this definition, **"control"** means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or
more of the outstanding shares, or (iii) beneficial ownership of such entity.
- **"Contribution"** shall mean any original work of authorship, including any modifications or additions to an existing
work, that is intentionally submitted by You to the Author for inclusion in, or documentation of, any of the products
owned or managed by the Author (the **"Work"**). For the purposes of this definition, **"submitted"** means any form
of electronic, verbal, or written communication sent to the Author or its representatives, including but not limited
to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed
by, or on behalf of, the Author for the purpose of discussing and improving the Work, but excluding communication that
is conspicuously marked or otherwise designated in writing by You as **"Not a Contribution."**
2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to the Author and
to recipients of software distributed by the Author a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform,
sublicense, re-license, and distribute Your Contributions and such derivative works.
3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to the Author and to
recipients of software distributed by the Author a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import,
and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are
necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which
such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (
including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have
contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity
under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
4. You represent that you are legally entitled to grant the above license. If your employer(s) has rights to
intellectual property that you create that includes your Contributions, you represent that you have received
permission to make Contributions on behalf of that employer, that your employer has waived such rights for your
Contributions to the Author, or that your employer has executed a separate Corporate CLA with the Author.
5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of
others). You represent that Your Contribution submissions include complete details of any third-party license or
other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware
and which are associated with any part of Your Contributions.
6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support.
You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in
writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT,
MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
7. Should You wish to submit work that is not Your original creation, You may submit it to the Author separately from
any Contribution, identifying the complete details of its source and of any license or other restriction (including,
but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and
conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
8. You agree to notify the Author of any facts or circumstances of which you become aware that would make these
representations inaccurate in any respect.

View File

@ -1,38 +0,0 @@
# How to contribute?
Thanks for your interest in the project!
## I'd like to propose some feature / change...
Cool! Go ahead, [create an issue] and describe your proposal so anyone can see it. You can also vote on features that
you want the most.
## I've found a bug!
Well, less cool! Before creating an issue, please check if the bug remains after hard refreshing (usually `ctrl+F5`) the
application. If the answer is yes, or this is not the first encounter of it please [create an issue] and describe the
problem. If you can, please attach screenshots (especially if this is visual bug), and console logs (especially for
connection problems) - this will help to reproduce the problem.
## I've got some spare resources on my server...
Soon you will be able to help the project by hosting your own API node that will be available for clients to use.
More details to come soon.
## I want to contribute some code...
That's great! If you want to make changes to API (which is responsible for collecting and supplying applicaiton with
data) please check the [API contribution guidelines], if you are interested in UI side of the app please read the
[frontend contribution guidelines].
### Contributor License Agreement
Unfortunately due to this project nature and license I need you to sign [Contributor License Agreement] - the nice thing
is that it can be done with simple push of a button! **You still will have full copyright to your contribution** but
basically you consent that you are entitled to code you are submitting and also to allow me to license this project on
other terms if needed to, for example, local governments. If you don't want to sign - I understand - but I won't be able
to accept your contribution :(
[Contributor License Agreement]: ./CLA.md
[create an issue]: https://github.com/cojedzie/cojedzie/issues/new
[API contribution guidelines]: ./api/CONTRIBUTING.md
[frontend contribution guidelines]: ./front/CONTRIBUTING.md

View File

@ -1,41 +0,0 @@
“Commons Clause” License Condition v1.0
The Software is provided to you by the Licensor under the License, as defined
below, subject to the following condition.
Without limiting other conditions in the License, the grant of rights under the
License will not include, and the License does not grant to you, the right to
Sell the Software.
For purposes of the foregoing, “Sell” means practicing any or all of the rights
granted to you under the License to provide to third parties, for a fee or other
consideration (including without limitation fees for hosting or consulting/
support services related to the Software), a product or service whose value
derives, entirely or substantially, from the functionality of the Software. Any
license notice or attribution required by the License must also include this
Commons Clause License Condition notice.
Software: Co Jedzie
License: MIT
Licensor: Kacper Donat
Copyright 2020 Kacper Donat
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,32 +0,0 @@
# [Co Jedzie](https://cojedzie.pl)
![Co Jedzie logo](https://i.imgur.com/oMCMAxa.png)
![screenshot](https://i.imgur.com/kpcwgjb.png)
Co Jedzie is an app that allows you to quickly and easily check realtime departure times on public transport stops. It
aims to be the central hub for all public transport information you will need.
You can use the app at [cojedzie.pl](https://cojedzie.pl).
## Roadmap
Co Jedzie is in active development, roadmap of the project can be found on [trello]. This roadmap is regularly updated
and represents current state of the project. Feel free to take a look.
### Contributing to roadmap
If you have found a bug or want to propose some changes feel free to create an [issue] explaining your proposal or
problem. Issue management and discussion would be done on the github, but planning will be carried away to the [trello]
trello with linked issue.
## Contributing
Wan't to contribute? Nice! Please see [CONTRIBUTING.md]
## License
This project is [fair-code](https://faircode.io/) licensed under [MIT with Commons Clause](./LICENSE.md). Basically, Co
Jedzie is free and code is available to everyone, but it's not allowed to make money directly with it without
authors permission.
Note that data collected from available data sources is licensed by their respective owners, thus it may be
available under different terms than the project itself and may require additional permissions to use.
[trello]: https://trello.com/b/QXqDvmoG/co-jedzie
[issue]: https://github.com/cojedzie/cojedzie/issues/new
[CONTRIBUTING.md]: ./CONTRIBUTING.md

View File

@ -1,2 +0,0 @@
/vendor/
/var/

View File

@ -1,22 +0,0 @@
# This file is a "template" of which env vars need to be defined for your application
# Copy this file to .env file for development, create environment variables when deploying to production
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=494a9d1f8cc383f16075f4d5e54ae1a2
#TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
#TRUSTED_HOSTS='^(localhost|example\.com)$'
###< symfony/framework-bundle ###
###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
#
DATABASE_URL="sqlite:///%kernel.project_dir%/var/app.db"
# DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7"
###< doctrine/doctrine-bundle ###
###> symfony/messenger ###
APP_EVENT_QUEUE_DSN="doctrine://default"
###< symfony/messenger ###

16
api/.gitignore vendored
View File

@ -1,16 +0,0 @@
###> symfony/framework-bundle ###
/.env.local
/.env.local.php
/.env.*.local
/config/secrets/prod/prod.decrypt.private.php
/public/bundles/
/var/
/vendor/
###< symfony/framework-bundle ###
/node_modules/
/public/*
!/public/index.php
###> baldinof/roadrunner-bundle ###
/bin/rr
###< baldinof/roadrunner-bundle ###

View File

@ -1,11 +0,0 @@
include:
- .rr.yaml
reload:
enabled: true
interval: 1s
patterns: [".php"]
services:
http:
dirs: ["."]
recursive: true

View File

@ -1,13 +0,0 @@
http:
address: "0.0.0.0:8080"
uploads:
forbid: [".php", ".exe", ".bat"]
workers:
command: "php bin/console baldinof:roadrunner:worker"
relay: "unix://var/roadrunner.sock"
static:
dir: "public"
forbid: [".php", ".htaccess"]

View File

@ -1,3 +0,0 @@
# Contributing guidelines
TBD

View File

@ -1,28 +0,0 @@
FROM php:7.4-fpm-alpine
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN install-php-extensions bcmath intl opcache zip sockets xdebug-^3.0;
RUN apk add git;
# XDebug
RUN echo "xdebug.mode=debug" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.discover_client_host=On" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini;
# Blackfire
RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \
&& curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/$version \
&& mkdir -p /tmp/blackfire \
&& tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \
&& mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \
&& printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \
&& rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz
# Timezone
RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime && \
echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini;
WORKDIR /var/www
EXPOSE 9001

View File

@ -1,3 +0,0 @@
#!/bin/sh
exec "$@"

View File

@ -1,5 +0,0 @@
#!/bin/sh
./bin/console doctrine:migrations:migrate --no-interaction
exec "$@"

View File

@ -1,23 +0,0 @@
<?php
use Symfony\Component\Dotenv\Dotenv;
require dirname(__DIR__).'/vendor/autoload.php';
if (!class_exists(Dotenv::class)) {
throw new LogicException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.');
}
// Load cached env vars if the .env.local.php file exists
// Run "composer dump-env prod" to create it (requires symfony/flex >=1.2)
if (is_array($env = @include dirname(__DIR__).'/.env.local.php') && (!isset($env['APP_ENV']) || ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? $env['APP_ENV']) === $env['APP_ENV'])) {
(new Dotenv(false))->populate($env);
} else {
// load all the .env files
(new Dotenv(false))->loadEnv(dirname(__DIR__).'/.env');
}
$_SERVER += $_ENV;
$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev';
$_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV'];
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0';

View File

@ -1,18 +0,0 @@
baldinof_road_runner:
# The kernel is preserved between requests. Change this to `true`
# if you want to reboot it, and use a fresh container on each request.
should_reboot_kernel: false
# Integrations are automatically detected, depending on installed bundle & current configuration
# See https://github.com/baldinof/roadrunner-bundle#integrations
default_integrations: true
# Allow to send prometheus metrics to the master RoadRunner process,
# via a `Spiral\RoadRunner\MetricsInterface` service.
# See https://github.com/baldinof/roadrunner-bundle#metrics
metrics_enabled: false
# You can use middlewares to manipulate PSR requests & responses.
# See https://github.com/baldinof/roadrunner-bundle#middlewares
# middlewares:
# - App\Middleware\YourMiddleware

View File

@ -1,19 +0,0 @@
framework:
cache:
# Unique name of your app: used to compute stable namespaces for cache keys.
#prefix_seed: your_vendor_name/app_name
# The "app" cache stores to the filesystem by default.
# The data in this cache should persist between deploys.
# Other options include:
# Redis
#app: cache.adapter.redis
#default_redis_provider: redis://localhost
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
#app: cache.adapter.apcu
# Namespaced pools use the above "app" backend by default
#pools:
#my.dedicated.cache: null

View File

@ -1,3 +0,0 @@
doctrine_migrations:
migrations_paths:
'DoctrineMigrations': '%kernel.project_dir%/migrations'

View File

@ -1,6 +0,0 @@
framework:
secret: '%env(APP_SECRET)%'
csrf_protection: false
php_errors:
log: true

View File

@ -1,11 +0,0 @@
parameters:
env(APP_EVENT_QUEUE): "doctrine://default"
framework:
messenger:
transports:
main: '%env(resolve:APP_EVENT_QUEUE)%'
sync: 'sync://'
routing:
'App\Message\UpdateDataMessage': main

View File

@ -1,20 +0,0 @@
doctrine:
orm:
auto_generate_proxy_classes: false
metadata_cache_driver:
type: pool
pool: doctrine.system_cache_pool
query_cache_driver:
type: pool
pool: doctrine.system_cache_pool
result_cache_driver:
type: pool
pool: doctrine.result_cache_pool
framework:
cache:
pools:
doctrine.result_cache_pool:
adapter: cache.app
doctrine.system_cache_pool:
adapter: cache.system

View File

@ -1,2 +0,0 @@
twig:
strict_variables: true

View File

@ -1,5 +0,0 @@
twig:
default_path: '%kernel.project_dir%/templates'
debug: '%kernel.debug%'
strict_variables: '%kernel.debug%'
exception_controller: null

View File

@ -1,9 +0,0 @@
<?php
if (file_exists(dirname(__DIR__).'/var/cache/prod/srcApp_KernelProdContainer.preload.php')) {
require dirname(__DIR__).'/var/cache/prod/srcApp_KernelProdContainer.preload.php';
}
if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) {
require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php';
}

View File

@ -1,16 +0,0 @@
api_v1:
resource: ../src/Controller/Api/v1
type: annotation
prefix: /api/v1/{provider}
api_v1_providers:
path: /api/v1/providers
methods: ["GET"]
defaults:
_controller: '\App\Controller\Api\v1\ProviderController::index'
api_v1_providers_one:
path: /api/v1/providers/{id}
methods: ["GET"]
defaults:
_controller: '\App\Controller\Api\v1\ProviderController::one'

View File

@ -1,3 +0,0 @@
_errors:
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
prefix: /_error

View File

@ -1,27 +0,0 @@
<?php
use App\Kernel;
use Symfony\Component\ErrorHandler\Debug;
use Symfony\Component\HttpFoundation\Request;
require dirname(__DIR__).'/config/bootstrap.php';
if ($_SERVER['APP_DEBUG']) {
umask(0000);
Debug::enable();
}
if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? false) {
Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO);
}
if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? false) {
Request::setTrustedHosts([$trustedHosts]);
}
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

View File

@ -1,29 +0,0 @@
FROM cojedzie/api:latest-rr
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN install-php-extensions xdebug-^3.0;
RUN apk add git;
# XDebug
RUN echo "xdebug.mode=debug" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.client_host=172.17.0.1" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.start_with_request=On" >> $PHP_INI_DIR/conf.d/docker-php-ext-xdebug.ini;
# Blackfire
RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \
&& curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/$version \
&& mkdir -p /tmp/blackfire \
&& tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \
&& mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \
&& printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \
&& rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz
# Timezone
RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime && \
echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini;
WORKDIR /var/www
EXPOSE 9001

View File

@ -1,48 +0,0 @@
<?php
namespace App\Command;
use App\Message\UpdateDataMessage;
use App\Service\DataUpdater;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Messenger\MessageBusInterface;
class UpdateCommand extends Command
{
/** @var DataUpdater */
private $updater;
/** @var MessageBusInterface */
private $bus;
public function __construct(DataUpdater $updater, MessageBusInterface $bus)
{
parent::__construct('app:update');
$this->updater = $updater;
$this->bus = $bus;
}
protected function configure()
{
$this->addOption(
'async', 'a',
InputOption::VALUE_NONE,
'Run in worker process via message queue.'
);
}
protected function execute(InputInterface $input, OutputInterface $output)
{
if ($input->getOption('async')) {
$this->bus->dispatch(new UpdateDataMessage());
$output->writeln("Update request sent to message queue.");
} else {
$this->updater->update($output);
}
return Command::SUCCESS;
}
}

View File

@ -1,3 +0,0 @@
<?php
require_once __DIR__ . '/helpers.php';

View File

@ -1,7 +0,0 @@
<?php
namespace App\Message;
final class UpdateDataMessage
{
}

View File

@ -1,34 +0,0 @@
<?php
namespace App\MessageHandler;
use App\Message\UpdateDataMessage;
use App\Output\LoggerOutput;
use App\Service\DataUpdater;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
final class UpdateDataMessageHandler implements MessageHandlerInterface, LoggerAwareInterface
{
use LoggerAwareTrait;
/** @var DataUpdater */
private $updater;
public function __construct(DataUpdater $updater)
{
$this->updater = $updater;
}
public function __invoke(UpdateDataMessage $message)
{
try {
$this->updater->update(new LoggerOutput($this->logger));
} catch (\Exception $exception) {
$this->logger->critical($exception->getMessage(), [
'backtrace' => $exception->getTraceAsString()
]);
}
}
}

View File

@ -1,30 +0,0 @@
<?php
namespace App\Output;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
use Symfony\Component\Console\Output\Output;
class LoggerOutput extends Output
{
/** @var LoggerInterface */
private $logger;
public function __construct(
LoggerInterface $logger,
?int $verbosity = self::VERBOSITY_NORMAL,
bool $decorated = false,
OutputFormatterInterface $formatter = null
) {
parent::__construct($verbosity, $decorated, $formatter);
$this->logger = $logger;
}
protected function doWrite(string $message, bool $newline)
{
$this->logger->info($message);
}
}

View File

@ -1,9 +0,0 @@
<?php
namespace App\Service;
use Symfony\Contracts\Service\ResetInterface;
interface CacheableConverter extends Converter, ResetInterface
{
}

View File

@ -1,17 +0,0 @@
<?php
namespace App\Service\Proxy;
final class FileLocator extends \ProxyManager\FileLocator\FileLocator
{
public function __construct(string $proxiesDirectory)
{
$absolutePath = realpath($proxiesDirectory);
if ($absolutePath === false) {
mkdir($proxiesDirectory, 0755, true);
}
parent::__construct($proxiesDirectory);
}
}

View File

@ -1,28 +0,0 @@
<?php
namespace App\Subscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class JSONFormatSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => "onRequest",
];
}
public function onRequest(RequestEvent $event)
{
$request = $event->getRequest();
if (!$request->attributes->has('_format')) {
$request->attributes->set('_format', 'json');
}
}
}

View File

@ -1,39 +0,0 @@
<?php
namespace App\Subscriber;
use App\Service\Converter;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Contracts\Service\ResetInterface;
class RequestCleanupSubscriber implements EventSubscriberInterface
{
/** @var ContainerInterface */
private ContainerInterface $container;
private Converter $converter;
public function __construct(ContainerInterface $container, Converter $converter)
{
$this->container = $container;
$this->converter = $converter;
}
public static function getSubscribedEvents()
{
return [
KernelEvents::TERMINATE => ['onTerminate']
];
}
public function onTerminate(TerminateEvent $event)
{
$this->container->get('doctrine')->reset();
if ($this->converter instanceof ResetInterface) {
$this->converter->reset();
}
}
}

View File

@ -1,6 +0,0 @@
ARG BASE_VERSION=latest
ARG REGISTRY=docker.io
FROM $REGISTRY/cojedzie/base:${BASE_VERSION}-fpm as base
CMD ["./bin/docker-init.sh", "php-fpm"]

View File

@ -1,10 +0,0 @@
ARG BASE_VERSION=latest
ARG REGISTRY=docker.io
FROM $REGISTRY/cojedzie/base:${BASE_VERSION} as base
COPY --from=spiralscout/roadrunner:1.9.2 /usr/bin/rr /usr/bin/rr
EXPOSE 8080
CMD ["./bin/docker-init.sh", "rr", "serve", "-v"]

View File

@ -1,32 +0,0 @@
FROM php:7.4-alpine
LABEL maintainer="Kacper Donat <kacper@kadet.net>"
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /var/www
RUN install-php-extensions bcmath intl opcache zip sockets;
COPY composer.json composer.lock ./
RUN apk add git && \
composer install --no-dev --no-scripts --no-plugins --prefer-dist --no-progress --no-interaction && \
composer dump-autoload --optimize && \
composer check-platform-reqs && \
composer clear-cache && \
apk del --purge git
COPY . .
ENV APP_ENV=prod
ENV DATABASE_URL="sqlite:////var/db/app.db"
ENV PATH=$PATH:/var/www/bin
RUN composer run-script post-install-cmd
VOLUME /var/db
# This image is not meant to be run, just to prepare all required files
CMD ["/bin/false"]

View File

@ -1,27 +0,0 @@
ARG BASE_VERSION=latest
ARG REGISTRY=docker.io
FROM $REGISTRY/cojedzie/base:$BASE_VERSION as base
FROM php:7.4-cli-alpine
LABEL maintainer="Kacper Donat <kacper@kadet.net>"
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
WORKDIR /var/www
RUN install-php-extensions bcmath intl opcache zip sockets;
COPY composer.json composer.lock ./
COPY --from=base /var/www /var/www
ENV APP_ENV=prod
ENV DATABASE_URL="sqlite:////var/db/app.db"
ENV PATH=$PATH:/var/www/bin
VOLUME /var/db
# This image is not meant to be run, just to prepare all required files
CMD ["/bin/false"]

View File

@ -1,27 +0,0 @@
ARG BASE_VERSION=latest
ARG REGISTRY=docker.io
FROM $REGISTRY/cojedzie/base:$BASE_VERSION as base
FROM php:7.4-fpm-alpine
LABEL maintainer="Kacper Donat <kacper@kadet.net>"
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
WORKDIR /var/www
RUN install-php-extensions bcmath intl opcache zip sockets;
COPY composer.json composer.lock ./
COPY --from=base /var/www /var/www
ENV APP_ENV=prod
ENV DATABASE_URL="sqlite:////var/db/app.db"
ENV PATH=$PATH:/var/www/bin
VOLUME /var/db
# This image is not meant to be run, just to prepare all required files
CMD ["/bin/false"]

View File

@ -1,36 +0,0 @@
FROM node:15.2.1 as build
WORKDIR /app
COPY . .
# install dependencies
RUN yarn install
RUN find resources/fontawesome -type f -name '*.tgz' | sed s/^/file:/ | xargs yarn add-no-save
# build stuff
RUN yarn run build:app
RUN yarn run build:server
# server dependencies step
FROM node:15.2.1 as prod-dependencies
WORKDIR /app
COPY . .
# install dependencies
RUN yarn install --production
FROM node:15.2.1-slim
LABEL maintainer="Kacper Donat <kacper@kadet.net>"
WORKDIR /app
COPY --from=build /app/build/ build
COPY --from=build /app/resources/ resources
COPY --from=prod-dependencies /app/node_modules/ node_modules
EXPOSE 3000
CMD ["node", "build/server.js"]

View File

@ -1,171 +0,0 @@
#!/bin/bash
TAGS=$*
BUILD=$(dirname $0)
ROOT=$BUILD/..
REGISTRY="docker.io"
TAGS=()
DRY=0
PUSH=0
BUILD_BASE=1
BUILT_TAGS=()
export DOCKER_BUILDKIT=1
usage () {
echo "usage: $0 [-h|--help] [-d|--dry] [--no-base|-B] [-p|--push] [-r|--registry registry] [-t|--tag tag] -- images...";
}
run () {
if [[ $DRY == 1 ]]; then
echo "$@"
else
"$@"
fi
}
# usage: build [-d|--default] [-v|--variant variant] [-R|--no-register] <image> <context>
build () {
ARGS=()
IS_DEFAULT=0
SUFFIX=""
VARIANT=""
REGISTER=1
options=$(getopt -l "default,variant:,no-register" -o "dv:R" -- "$@")
eval set -- "$options"
while true;
do
case "$1" in
-d|--default)
IS_DEFAULT=1
shift
;;
-v|--variant)
VARIANT="$2"
shift 2
;;
-R|--no-register)
REGISTER=0
shift
;;
--)
shift
break
;;
*)
echo "build: unknown option $1"
exit 1
esac
done
IMAGE=$1
CONTEXT=$2
shift 2;
# check for variant
if [[ -z "$VARIANT" ]]; then
ARGS+=("-f" "$BUILD/$IMAGE/Dockerfile")
else
ARGS+=("-f" "$BUILD/$IMAGE/$VARIANT.Dockerfile")
SUFFIX="-$VARIANT"
fi
for TAG in "${TAGS[@]}"; do
ARGS+=("-t" "$REGISTRY/cojedzie/$IMAGE:$TAG$SUFFIX")
[[ $REGISTER -eq 1 ]] && BUILT_TAGS+=("$REGISTRY/cojedzie/$IMAGE:$TAG$SUFFIX")
if [[ $IS_DEFAULT == 1 ]]; then
ARGS+=("-t" "$REGISTRY/cojedzie/$IMAGE:$TAG")
[[ $REGISTER -eq 1 ]] && BUILT_TAGS+=("$REGISTRY/cojedzie/$IMAGE:$TAG")
fi
done
echo "Building $IMAGE $VARIANT"
run docker build --build-arg "BASE_VERSION=${TAGS[0]}" --build-arg "REGISTRY=$REGISTRY" "$CONTEXT" "${ARGS[@]}" "$@"
}
options=$(getopt -l "help,dry,registry:,tag:,push,no-base" -o "hdr:t:pB" -- "$@")
eval set -- "$options"
while true;
do
case "$1" in
-h|--help)
usage
exit 0
;;
-t|--tag)
TAGS+=("$2")
shift 2
;;
-p|--push)
PUSH=1
shift
;;
-B|--no-base)
BUILD_BASE=0
shift
;;
-r|--registry)
REGISTRY="$2"
shift 2
;;
-d|--dry)
DRY=1
shift
;;
--)
shift
break;
esac
done
# set default tags if user have not provided any
if [ ${#TAGS[@]} -eq 0 ]; then
TAGS=("latest")
fi
if [ $# -eq 0 ]; then
set -- api standalone worker front
fi
if [ $BUILD_BASE -eq 1 ]; then
build --no-register base $ROOT/api/ || exit 1
build --no-register --variant fpm base $ROOT/api/ || exit 1
build --no-register --variant cli base $ROOT/api/ || exit 1
fi
while [ $# -gt 0 ]
do
case "$1" in
api)
build api $BUILD/api/ --variant rr --default || exit 1
build api $BUILD/api/ --variant fpm || exit 1
;;
standalone)
build standalone $BUILD/standalone/ --variant rr --default || exit 1
;;
worker)
build worker $BUILD/worker/ || exit 1
;;
front)
build front $ROOT/front/ || exit 1
;;
*)
>&2 echo "$1 is not a valid image to build"
esac
shift
done
if [ $PUSH -eq 1 ]; then
for TAG in "${BUILT_TAGS[@]}"; do
docker push $TAG
done
else
echo "Created tags:"
printf " - %s\n" "${BUILT_TAGS[@]}"
fi

View File

@ -1,38 +0,0 @@
ARG BASE_VERSION=latest
ARG REGISTRY=docker.io
FROM ${REGISTRY}/cojedzie/api:${BASE_VERSION}-rr
# escape=`
RUN apk add supervisor gettext && \
{ \
echo '[supervisord]'; \
echo 'nodaemon=true'; \
echo ; \
echo '[program:roadrunner]'; \
echo 'command=rr serve -v'; \
echo 'startsecs=0'; \
echo 'start=true'; \
echo 'autorestart=true'; \
echo 'stdout_logfile=/dev/stdout'; \
echo 'stderr_logfile=/dev/stderr'; \
echo 'stdout_logfile_maxbytes=0'; \
echo 'stderr_logfile_maxbytes=0'; \
echo ; \
echo '[program:messenger-consumer]'; \
echo 'command=php /var/www/bin/console messenger:consume $COJEDZIE_WORKER_OPTS $COJEDZIE_WORKER_QUEUES'; \
echo 'startsecs=0'; \
echo 'start=true'; \
echo 'autorestart=true'; \
echo 'stdout_logfile=/dev/stdout'; \
echo 'stderr_logfile=/dev/stderr'; \
echo 'stdout_logfile_maxbytes=0'; \
echo 'stderr_logfile_maxbytes=0'; \
} | tee /etc/supervisord.conf.tpl;
COPY ./supervisord-init.sh ./bin/
ENV COJEDZIE_WORKER_QUEUES=main
ENV COJEDZIE_WORKER_OPTS="-vv --time-limit=86400 --limit=10 --memory-limit=128M"
CMD ["./bin/supervisord-init.sh", "supervisord", "-c", "/etc/supervisord.conf"]

View File

@ -1,7 +0,0 @@
#!/bin/sh
if [ -f /etc/supervisord.conf.tpl ]; then
envsubst < /etc/supervisord.conf.tpl > /etc/supervisord.conf
fi
exec "$@"

View File

@ -1,27 +0,0 @@
ARG BASE_VERSION=latest
ARG REGISTRY=docker.io
FROM $REGISTRY/cojedzie/base:${BASE_VERSION}-cli
RUN apk add supervisor gettext && \
{ \
echo '[supervisord]'; \
echo 'nodaemon=true'; \
echo ; \
echo '[program:messenger-consumer]'; \
echo 'command=php /var/www/bin/console messenger:consume $COJEDZIE_WORKER_OPTS $COJEDZIE_WORKER_QUEUES'; \
echo 'startsecs=0'; \
echo 'start=true'; \
echo 'autorestart=true'; \
echo 'stdout_logfile=/dev/stdout'; \
echo 'stderr_logfile=/dev/stderr'; \
echo 'stdout_logfile_maxbytes=0'; \
echo 'stderr_logfile_maxbytes=0'; \
} | tee /etc/supervisord.conf.tpl;
COPY ./supervisord-init.sh ./bin/
ENV COJEDZIE_WORKER_QUEUES=main
ENV COJEDZIE_WORKER_OPTS="-vv --time-limit=86400 --limit=10 --memory-limit=128M"
CMD ["./bin/supervisord-init.sh", "supervisord", "-c", "/etc/supervisord.conf"]

View File

@ -1,7 +0,0 @@
#!/bin/sh
if [ -f /etc/supervisord.conf.tpl ]; then
envsubst < /etc/supervisord.conf.tpl > /etc/supervisord.conf
fi
exec "$@"

View File

@ -1,37 +1,34 @@
{ {
"name": "kadet/cojedzie", "name": "kadet/cojedzie",
"description": "Co Jedzie",
"type": "project", "type": "project",
"license": "MIT with Commons Clause", "license": "MIT",
"require": { "require": {
"php": "^7.4", "php": "^7.1.3",
"ext-ctype": "*", "ext-ctype": "*",
"ext-iconv": "*", "ext-iconv": "*",
"ext-json": "*", "ext-json": "*",
"baldinof/roadrunner-bundle": "^1.3",
"cerbero/json-objects": "^1.1", "cerbero/json-objects": "^1.1",
"illuminate/collections": "^8.35", "doctrine/doctrine-cache-bundle": "^1.4",
"jms/serializer-bundle": "^3.5", "jms/serializer-bundle": "^3.5",
"kadet/functional": "dev-master",
"nelmio/api-doc-bundle": "^3.5", "nelmio/api-doc-bundle": "^3.5",
"nesbot/carbon": "^2.46.0", "nesbot/carbon": "^1.33",
"ocramius/proxy-manager": "^2.0", "ocramius/proxy-manager": "^2.0",
"sensio/framework-extra-bundle": "^5.2", "sensio/framework-extra-bundle": "^5.2",
"spiral/roadrunner": "^1.8", "symfony/asset": "^4.4",
"symfony/asset": "^5.2", "symfony/console": "^4.4",
"symfony/console": "^5.2",
"symfony/doctrine-messenger": "5.2.*",
"symfony/flex": "^1.1", "symfony/flex": "^1.1",
"symfony/framework-bundle": "^5.2", "symfony/framework-bundle": "^4.4",
"symfony/messenger": "5.2.*",
"symfony/monolog-bundle": "^3.3", "symfony/monolog-bundle": "^3.3",
"symfony/orm-pack": "^1.0", "symfony/orm-pack": "^1.0",
"symfony/profiler-pack": "^1.0", "symfony/profiler-pack": "^1.0",
"symfony/twig-bundle": "^5.2", "symfony/twig-bundle": "^4.4",
"symfony/yaml": "^5.2", "symfony/yaml": "^4.4",
"symfony/dotenv": "5.2.*", "tightenco/collect": "^5.6"
"symfony/amqp-messenger": "5.2.*", },
"symfony/redis-messenger": "5.2.*" "require-dev": {
"symfony/dotenv": "^4.4",
"symfony/web-server-bundle": "^4.4",
"kadet/functional": "dev-master"
}, },
"config": { "config": {
"preferred-install": { "preferred-install": {
@ -40,17 +37,14 @@
"sort-packages": true, "sort-packages": true,
"secure-http": false, "secure-http": false,
"platform": { "platform": {
"php": "7.4.15" "php": "7.3.12"
} }
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"App\\": "src/" "App\\": "src/"
}, },
"files": [ "files": ["./src/Functions/index.php"]
"vendor/symfony/dependency-injection/Loader/Configurator/ContainerConfigurator.php",
"./src/Functions/index.php"
]
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
@ -81,8 +75,7 @@
}, },
"extra": { "extra": {
"symfony": { "symfony": {
"allow-contrib": true, "allow-contrib": true
"require": "5.2.*"
} }
}, },
"repositories": [ "repositories": [
@ -90,8 +83,5 @@
"type": "vcs", "type": "vcs",
"url": "https://git.kadet.net/kadet/functional-php.git" "url": "https://git.kadet.net/kadet/functional-php.git"
} }
], ]
"require-dev": {
"symfony/maker-bundle": "^1.30"
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -2,14 +2,14 @@
return [ return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\WebServerBundle\WebServerBundle::class => ['dev' => true],
Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true], Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle::class => ['all' => true],
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Nelmio\ApiDocBundle\NelmioApiDocBundle::class => ['all' => true], Nelmio\ApiDocBundle\NelmioApiDocBundle::class => ['all' => true],
JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true], JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
Baldinof\RoadRunnerBundle\BaldinofRoadRunnerBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
]; ];

View File

@ -1,5 +1,5 @@
web_profiler: web_profiler:
toolbar: false toolbar: true
intercept_redirects: false intercept_redirects: false
framework: framework:

View File

@ -5,13 +5,14 @@ doctrine:
dbal: dbal:
driver: 'pdo_sqlite' driver: 'pdo_sqlite'
url: '%env(resolve:DATABASE_URL)%' url: '%env(resolve:DATABASE_URL)%'
logging: '%kernel.debug%' logging: true
profiling: '%kernel.debug%' profiling: true
types: types:
datetime: App\Doctrine\CarbonDateTimeType datetime: App\Doctrine\CarbonDateTimeType
orm: orm:
auto_generate_proxy_classes: true auto_generate_proxy_classes: '%kernel.debug%'
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true auto_mapping: true
mappings: mappings:
App: App:
@ -19,4 +20,4 @@ doctrine:
type: annotation type: annotation
dir: '%kernel.project_dir%/src/Entity' dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity' prefix: 'App\Entity'
alias: App alias: Entity

View File

@ -0,0 +1,3 @@
doctrine_migrations:
dir_name: '%kernel.project_dir%/src/Migrations'
namespace: DoctrineMigrations

View File

@ -0,0 +1,30 @@
framework:
secret: '%env(APP_SECRET)%'
#default_locale: en
#csrf_protection: true
#http_method_override: true
# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.
session:
handler_id: ~
#esi: true
#fragments: true
php_errors:
log: true
cache:
# Put the unique name of your app here: the prefix seed
# is used to compute stable namespaces for cache keys.
#prefix_seed: your_vendor_name/app_name
# The app cache caches to the filesystem by default.
# Other options include:
# Redis
#app: cache.adapter.redis
#default_redis_provider: redis://localhost
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
#app: cache.adapter.apcu

View File

@ -13,7 +13,7 @@ nelmio_api_doc:
areas: areas:
path_patterns: path_patterns:
- /api(?!/doc$) # Accepts routes under /api except /api/doc - ^/[^\/]+/api(?!/doc$) # Accepts routes under /api except /api/doc

View File

@ -0,0 +1,31 @@
doctrine:
orm:
metadata_cache_driver:
type: service
id: doctrine.system_cache_provider
query_cache_driver:
type: service
id: doctrine.system_cache_provider
result_cache_driver:
type: service
id: doctrine.result_cache_provider
services:
doctrine.result_cache_provider:
class: Symfony\Component\Cache\DoctrineProvider
public: false
arguments:
- '@doctrine.result_cache_pool'
doctrine.system_cache_provider:
class: Symfony\Component\Cache\DoctrineProvider
public: false
arguments:
- '@doctrine.system_cache_pool'
framework:
cache:
pools:
doctrine.result_cache_pool:
adapter: cache.app
doctrine.system_cache_pool:
adapter: cache.system

View File

@ -1,4 +1,3 @@
framework: framework:
router: router:
strict_requirements: ~ strict_requirements: ~

View File

@ -0,0 +1,6 @@
twig:
paths: ['%kernel.project_dir%/templates']
debug: '%kernel.debug%'
strict_variables: '%kernel.debug%'
globals:
gtm_tracking: "%env(GTM_TAG)%"

9
config/routes.yaml Normal file
View File

@ -0,0 +1,9 @@
api_v1:
resource: ../src/Controller/Api/v1
type: annotation
prefix: /{provider}/api/v1
api_v1_providers:
path: /api/v1/providers
defaults:
_controller: '\App\Controller\Api\v1\ProviderController::index'

View File

@ -0,0 +1,3 @@
_errors:
resource: '@TwigBundle/Resources/config/routing/errors.xml'
prefix: /_error

View File

@ -42,6 +42,13 @@ services:
resource: '../src/Handler' resource: '../src/Handler'
tags: [ app.handler ] tags: [ app.handler ]
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
#assets
assets.modified_time_version_strategy:
class: App\Asset\ModifiedTimeVersionStrategy
#eerialziser #eerialziser
jms_serializer.serialized_name_annotation_strategy: jms_serializer.serialized_name_annotation_strategy:
class: JMS\Serializer\Naming\SerializedNameAnnotationStrategy class: JMS\Serializer\Naming\SerializedNameAnnotationStrategy
@ -53,7 +60,7 @@ services:
#proxy configuration #proxy configuration
proxy.locator: proxy.locator:
class: 'App\Service\Proxy\FileLocator' class: 'ProxyManager\FileLocator\FileLocator'
arguments: ['%kernel.cache_dir%/proxy'] arguments: ['%kernel.cache_dir%/proxy']
proxy.strategy: proxy.strategy:
@ -68,6 +75,7 @@ services:
ProxyManager\Configuration: '@proxy.config' ProxyManager\Configuration: '@proxy.config'
# converter # converter
App\Service\AggregateConverter: App\Service\AggregateConverter:
arguments: arguments:

View File

@ -1,43 +0,0 @@
version: '3.4'
services:
nginx:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./front:/var/www/front:cached
- ./api:/var/www/api:cached
- .docker-compose/nginx/cojedzie-rr.conf:/etc/nginx/conf.d/cojedzie-rr.conf
api:
build:
context: ./api
dockerfile: rr.Dockerfile
env_file:
- .docker-compose/api/.env
- api/.env.local
environment:
- TRUSTED_PROXIES=172.0.0.0/8
ports:
- 8888:8080
volumes:
- ./api:/var/www:cached
- .docker-compose/api/log.conf:/usr/local/etc/php-fpm.d/zz-log.conf
command: ["rr", "serve", "-c", ".rr.yaml"]
frontend:
image: node:15.2.1
working_dir: /app
environment:
- APP_API=http://nginx/api
volumes:
- ./front:/app
command: ["node", "build/server.js"]
blackfire:
image: blackfire/blackfire
ports: ["8707"]
environment:
- BLACKFIRE_SERVER_ID
- BLACKFIRE_SERVER_TOKEN

View File

@ -6,28 +6,18 @@ services:
ports: ports:
- "8080:80" - "8080:80"
volumes: volumes:
- ./front:/var/www/front:cached - ./:/var/www:cached
- ./api:/var/www/api:cached - ./docker/nginx/czydojade:/etc/nginx/conf.d/czydojade.conf
- .docker-compose/nginx/cojedzie.conf:/etc/nginx/conf.d/cojedzie.conf
api: php:
build: build: docker/php
context: ./api
dockerfile: Dockerfile
env_file: env_file:
- .docker-compose/api/.env - ./docker/php/.env
volumes: volumes:
- ./api:/var/www:cached - ./:/var/www:cached
- .docker-compose/api/log.conf:/usr/local/etc/php-fpm.d/zz-log.conf - ./docker/php/log.conf:/usr/local/etc/php-fpm.d/zz-log.conf
frontend:
image: node:15.2.1
working_dir: /app
environment:
- APP_API=http://nginx/api
volumes:
- ./front:/app
command: ["node", "build/server.js"]
blackfire: blackfire:
image: blackfire/blackfire image: blackfire/blackfire

29
docker/nginx/czydojade Normal file
View File

@ -0,0 +1,29 @@
server {
root /var/www/public/;
server_name czydojade.localhost;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
location ~ \.(js|css)$ {
expires 1y;
}
location ~ ^/index\.php(/|$) {
fastcgi_pass php:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_param APP_ENV "dev";
fastcgi_param DATABASE_URL "sqlite:///%kernel.project_dir%/var/app.db";
fastcgi_param GTM_TAG "GTM-00000";
internal;
}
}
}

1
docker/php/.env Normal file
View File

@ -0,0 +1 @@
PHP_IDE_CONFIG=serverName=czydojade

37
docker/php/Dockerfile Normal file
View File

@ -0,0 +1,37 @@
FROM php:7.3-fpm
ARG XDEBUG_REMOTE_HOST="172.17.0.1"
RUN apt-get update && \
apt-get install -y --no-install-recommends git zip libzip-dev
RUN docker-php-ext-install zip
# XDebug
RUN pecl install xdebug-2.9.0 && docker-php-ext-enable xdebug
RUN echo "xdebug.remote_enable = 1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.remote_host = ${XDEBUG_REMOTE_HOST}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini;
# Blackfire
RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \
&& curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/$version \
&& mkdir -p /tmp/blackfire \
&& tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \
&& mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \
&& printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8707\n" > $PHP_INI_DIR/conf.d/blackfire.ini \
&& rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz
#Composer
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php composer-setup.php \
&& php -r "unlink('composer-setup.php');" \
&& mv composer.phar /usr/local/bin/composer \
&& chmod +x /usr/local/bin/composer
# Timezone
RUN ln -snf /usr/share/zoneinfo/Europe/Warsaw /etc/localtime
RUN echo "date.timezone = Europe/Warsaw" >> /usr/local/etc/php/conf.d/datetime.ini;
WORKDIR /var/www
EXPOSE 9001

View File

@ -1,4 +0,0 @@
/node_modules/
/build/
yarn-error*
npm-debug*

6
front/.gitignore vendored
View File

@ -1,6 +0,0 @@
yarn-error.log
/public/*
!/public/.gitkeep
/node_modules/
/build/

View File

@ -1,3 +0,0 @@
# Contributing guidelines
TBD

View File

@ -1,3 +0,0 @@
# this folder is created to store fontawesome pro packages
*
!.gitignore

View File

@ -1,39 +0,0 @@
{
"name": "Co Jedzie?",
"short_name": "Co Jedzie?",
"orientation": "portrait",
"lang": "pl-PL",
"start_url": "/",
"display": "standalone",
"background_color": "white",
"theme_color": "white",
"description": "Odpowiedź na odwieczne pytanie ludzkości - czy tramwaje jeżdżą?",
"categories": ["navigation", "transport", "travel", "utilities"],
"icons": [{
"src": "/images/icon-256.png",
"sizes": "256x256"
},{
"src": "/images/icon-512.png",
"sizes": "512x512"
},{
"src": "/images/icon-64.png",
"sizes": "64x64"
},{
"src": "/images/icon-128.png",
"sizes": "128x128"
},{
"src": "/images/icon-192.png",
"sizes": "192x192"
},{
"src": "/images/icon-96.png",
"sizes": "96x96"
},{
"src": "/images/icon-maskable.png",
"sizes": "512x512",
"purpose": "any maskable"
},{
"src": "/images/icon-monochrome.png",
"sizes": "512x512",
"purpose": "monochrome"
}]
}

View File

@ -1,65 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="/dist/main.css"/>
<link rel="manifest" href="<%= manifest_path %>"/>
<!-- icons -->
<link rel="icon" href="/images/favicon.png" sizes="16x16"/>
<link rel="icon" href="/images/favicon-2x.png" sizes="32x32"/>
<link rel="icon" href="/images/favicon.ico"/>
<!-- Apple shit -->
<link rel="apple-touch-icon" href="/images/ios.png" sizes="512x512">
<link rel="apple-touch-icon" href="/images/ios-80.png" sizes="80x80">
<link rel="apple-touch-icon" href="/images/ios-192.png" sizes="192x192">
<meta name="apple-mobile-web-app-title" content="Co Jedzie?">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="theme-color" content="white"/>
<title>Co Jedzie?</title>
<% if (gtm_tracking) { %>
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','<%= gtm_tracking %>');</script>
<!-- End Google Tag Manager -->
<% } %>
</head>
<body>
<noscript>
<% if (gtm_tracking) { %>
<!-- Google Tag Manager (noscript) -->
<iframe src="https://www.googletagmanager.com/ns.html?id=<%= gtm_tracking %>"
height="0" width="0" style="display:none;visibility:hidden"></iframe>
<!-- End Google Tag Manager (noscript) -->
<% } %>
<div class="container">
<div class="alert alert-danger">
Aplikacja wymaga do działania obsługi JavaScriptu.
</div>
</div>
</noscript>
<main id="root" class="container not-ready">
</main>
<footer class="container">
<span>
<img src="/images/logo.png" alt="co jedzie logo"/>
v.<%= version %> &bullet;
<a href="/api/doc">API</a>
</span>
<span class="copyright flex flex-space-left justify-content-end">
<a href="https://kadet.net"><img src="/images/kadet-net-logo.png" alt="kadet.net logo" class="mx-1"/></a>
&copy; <%= year %>
</span>
</footer>
<script src="/dist/main.js"></script>
</body>
</html>

View File

@ -1,87 +0,0 @@
import express from 'express';
import path from "path";
import fs from "fs";
import request from "request";
const server = express();
const port = parseInt(process.env.APP_PORT) || 3000;
const host = process.env.APP_HOST || '0.0.0.0';
const api = process.env.APP_API || "https://cojedzie.pl/api";
const gtm_tracking = process.env.APP_GTM || '';
const version = "2020.11-dev";
const manifest = JSON.parse(
fs.readFileSync(path.join(__dirname, "../resources/manifest.json")).toString("utf-8")
);
const provider_manifests = {}
function generateProviderManifest(provider: any) {
return {
...manifest,
start_url: `/${provider.id}`,
name: `${manifest.name} - ${provider.name}`,
short_name: `${manifest.short_name} - ${provider.shortName}`,
};
}
server.set("views", path.join(__dirname, "../resources/views/"));
server.set("view engine", "ejs");
server.use(express.static(path.join(__dirname, "../build/public/")))
server.get("/:provider?/manifest.json", (req, res) => {
const provider = req.params.provider;
if (typeof provider === "undefined") {
res.send(manifest);
return;
}
if (typeof provider_manifests[provider] !== "undefined") {
res.send(provider_manifests[provider]);
return;
}
console.log(`No manifest entry for ${provider}, calling ${api}/providers/${provider}`);
request.get(`${api}/v1/providers/${provider}`, (err, _, body) => {
try {
const info = JSON.parse(body);
provider_manifests[provider] = generateProviderManifest(info);
console.info(`Generated manifest for ${provider}`, provider_manifests[provider]);
res.send(provider_manifests[provider]);
} catch(error) {
console.error(`Problem with generating manifest for ${provider}: ${error.message}`);
res.send(manifest);
}
})
})
server.get("/:provider?/*", (req, res) => {
const manifest_path = req.params.provider
? `/${req.params.provider}/manifest.json`
: "/manifest.json";
const year = (new Date()).getFullYear();
res.render("index", {
manifest_path,
gtm_tracking,
version,
year,
})
})
server.listen(port, host, () => {
console.info(`Server started at ${host}:${port}`);
});
process.on('SIGINT', function() {
console.info("Terminating server...");
process.exit();
});

View File

@ -1,15 +0,0 @@
{
"compilerOptions": {
"lib": ["es2015", "es2016.array.include", "es2017.object"],
"sourceMap": true,
"esModuleInterop": true,
"target": "es6",
"module": "commonjs",
"moduleResolution": "node",
"baseUrl": "./",
"outDir": "../build/",
"skipLibCheck": true
},
"files": ["./server.ts"],
"include": ["./**/*.ts"]
}

View File

@ -1,20 +0,0 @@
import Vue from "vue";
import Component from "vue-class-component";
import VueRouter, { RouteConfig } from "vue-router";
import { Main, ProviderChooser } from "@/components";
import store from "@/store";
const routes: RouteConfig[] = [
{ path: "/:provider", component: Main },
{ path: "/", component: ProviderChooser },
]
export const router = new VueRouter({
routes,
mode: 'history',
});
@Component({ template: require("@templates/app.html"), router, store })
export class Application extends Vue {
}

View File

@ -1,13 +0,0 @@
import Component from "vue-class-component";
import Vue from "vue";
import { History } from "@/store";
import { HistoryEntry } from "@/store/history";
import { Mutation } from "vuex-class";
import { Stop } from "@/model";
@Component({ template: require('@templates/stop/history.html' )})
export class StopHistory extends Vue {
@History.Getter all: HistoryEntry[];
@Mutation("add") select: (stops: Stop[]) => void;
}

View File

@ -1,66 +0,0 @@
import { Stop } from "@/model";
import { Module } from "vuex";
import { RootState } from "./root";
import * as moment from "moment";
import { Moment } from "moment";
import { Jsonified } from "@/utils";
export interface HistoryEntry {
stop: Stop,
date: Moment,
}
export interface HistorySettings {
maxEntries: number,
}
export interface HistoryState {
entries: Jsonified<HistoryEntry>[],
settings: HistorySettings,
}
export function serializeHistoryEntry(entry: HistoryEntry): Jsonified<HistoryEntry> {
return {
...entry,
date: entry.date.toISOString(),
}
}
export function deserializeHistoryEntry(serialized: Jsonified<HistoryEntry>): HistoryEntry {
return {
...serialized,
date: moment(serialized.date),
}
}
export const history: Module<HistoryState, RootState> = {
namespaced: true,
state: {
entries: [],
settings: {
maxEntries: 10,
}
},
mutations: {
clear(state: HistoryState) {
state.entries = [];
},
push(state: HistoryState, entry: HistoryEntry) {
state.entries = state.entries.filter(cur => cur.stop.id != entry.stop.id);
state.entries.unshift(serializeHistoryEntry(entry));
if (state.entries.length > state.settings.maxEntries) {
state.entries = state.entries.slice(0, state.settings.maxEntries);
}
},
saveSettings(state: HistoryState, settings: Partial<HistorySettings>) {
Object.assign(state.settings, settings);
}
},
getters: {
all: ({ entries, settings }) => entries.slice(0, settings.maxEntries).map(deserializeHistoryEntry),
latest: ({ entries }) => n => entries.slice(0, n).map(deserializeHistoryEntry),
}
}
export default history;

View File

@ -1,5 +0,0 @@
<main class="d-flex">
<router-view />
<portal-target name="popups" multiple />
</main>

View File

@ -1,142 +0,0 @@
<div class="container" id="app">
<div class="row">
<div class="col-md-8 order-md-last">
<section class="section messages" v-show="messages.count > 0">
<header class="section__title flex">
<h2>
<ui-icon icon="messages" fixed-width class="mr-2"></ui-icon>
Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ messages.count }}</span>
</h2>
<button class="btn btn-action flex-space-left" ref="settings-messages" id="settings-messages"
@click="visibility.messages = !visibility.messages">
<tooltip>ustawienia</tooltip>
<ui-icon icon="settings" fixed-width></ui-icon>
</button>
<button class="btn btn-action" @click="updateMessages" ref="btn-messages-refresh">
<tooltip>odśwież</tooltip>
<ui-icon icon="refresh" :spin="messages.state === 'fetching'" fixed-width></ui-icon>
</button>
<button class="btn btn-action" @click="sections.messages = !sections.messages">
<tooltip>
{{ sections.messages ? 'zwiń' : 'rozwiń' }}
<span class="sr-only">sekcję komunikatów</span>
</tooltip>
<ui-icon :icon="sections.messages ? 'chevron-up' : 'chevron-down'" fixed-width></ui-icon>
</button>
<portal to="popups">
<ui-dialog reference="#settings-messages" v-if="visibility.messages" arrow placement="left-start"
@leave="visibility.messages = false">
<settings-messages></settings-messages>
</ui-dialog>
</portal>
</header>
<fold :visible="sections.messages">
<messages></messages>
</fold>
</section>
<section class="section">
<header class="section__title flex">
<h2>
<ui-icon icon="timetable" fixed-width></ui-icon>
<span class="text">Odjazdy</span>
</h2>
<button class="btn btn-action flex-space-left" ref="settings-departures" id="settings-departures"
@click="visibility.departures = !visibility.departures">
<tooltip>ustawienia</tooltip>
<ui-icon icon="settings" fixed-width></ui-icon>
</button>
<button class="btn btn-action" @click="updateDepartures({ stops })">
<tooltip>odśwież</tooltip>
<ui-icon icon="refresh" :spin="departures.state === 'fetching'" fixed-width></ui-icon>
</button>
<portal to="popups">
<ui-dialog reference="#settings-departures" v-if="visibility.departures"
@leave="visibility.departures = false" arrow placement="left-start">
<settings-departures></settings-departures>
</ui-dialog>
</portal>
</header>
<departures :stops="stops" v-if="stops.length > 0"></departures>
<div class="alert alert-info" v-else>
<ui-icon icon="info"></ui-icon>
Wybierz przystanki korzystając z wyszukiwarki poniżej, aby zobaczyć listę odjazdów.
</div>
<div class="attribution" v-if="provider && provider.attribution">
<ui-icon icon="info"></ui-icon>
Pochodzenie danych: <span class="attribution__attribution" v-html="provider.attribution"></span>
</div>
</section>
</div>
<div class="col-md-4 order-md-first">
<section class="section picker" v-if="stops.length > 0">
<header class="section__title flex">
<h2>
<ui-icon icon="stop" fixed-width></ui-icon>
<span class="text">Przystanki</span>
</h2>
<button class="btn btn-action flex-space-left" @click="clear">
<tooltip>usuń wszystkie</tooltip>
<ui-icon icon="delete" fixed-width></ui-icon>
</button>
</header>
<ul class="picker__stops list-underlined">
<li v-for="stop in stops" :key="stop.id" class="picker__stop">
<picker-stop :stop="stop">
<template v-slot:primary-action>
<button @click="remove(stop)" class="btn btn-action">
<tooltip>usuń przystanek</tooltip>
<ui-icon icon="remove-stop"></ui-icon>
</button>
</template>
</picker-stop>
</li>
</ul>
<div class="d-flex mt-2">
<button class="btn btn-action btn-sm flex-space-left" @click="visibility.save = true" ref="save">
<ui-icon icon="favourite" fixed-width></ui-icon>
zapisz jako...
</button>
</div>
<ui-dialog reference="save" v-if="visibility.save" arrow placement="bottom-end"
@leave="visibility.save = false" title="Dodaj do ulubionych">
<favourites-adder @saved="visibility.save = false"/>
</ui-dialog>
</section>
<section class="section picker">
<header class="section__title flex">
<template v-if="visibility.picker === 'search'">
<h2 class="flex-grow-1">
<ui-icon icon="search" fixed-width class="mr-1"></ui-icon>
Wybierz przystanki
</h2>
<button class="btn btn-action" @click="visibility.picker = 'favourites'">
<tooltip>Zapisane</tooltip>
<ui-icon icon="favourite" fixed-witdth></ui-icon>
</button>
</template>
<template v-else>
<h2 class="flex-grow-1">
<ui-icon icon="favourite" fixed-width class="mr-1"></ui-icon>
Zapisane
</h2>
<button class="btn btn-action" @click="visibility.picker = 'search'">
<tooltip>Wybierz przystanki</tooltip>
<ui-icon icon="search" fixed-witdth></ui-icon>
</button>
</template>
</header>
<div class="transition-box">
<transition name="fade">
<stop-finder @select="add" :blacklist="stops" v-if="visibility.picker === 'search'"></stop-finder>
<favourites v-else-if="visibility.picker === 'favourites'"></favourites>
</transition>
</div>
</section>
</div>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More