diff --git a/.gitignore b/.gitignore index c6efb61..6e92d06 100644 --- a/.gitignore +++ b/.gitignore @@ -24,10 +24,12 @@ !/bin/console !/bin/symfony_requirements -# assets +# assets, uploads /node_modules/ /web/assets/* !/web/assets/.gitkeep +/web/uploads/* +!/web/uploads/.gitkeep # PHP-CS-Fixer /.php_cs.* diff --git a/.travis.yml b/.travis.yml index ee6f05e..850750f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ php: before_script: - nvm install "$(jq -r '.engines.node' package.json)" - - make install-bin-dev install-bin-prod install-composer install-npm db-build clean + - make install-bin-dev install-bin-prod install-composer install-npm db-build assets-build script: - npm run lint diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f6e48e7..71a6d3c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,15 +24,13 @@ Note: If it unluckily fails at some point, don't hesitate to re-run this command ```shell # connect to the VM make ssh -# install the project for development (you'll have to press "Enter" several times to keep default parameters) +# install the project for development (you'll have to press "Enter" several times to configure the project with default parameters) make install -# serve assets for development environment -npm start ``` #### 4. Enjoy -You should see your application up and running at http://appbuild.dev/app_dev.php/ +You should see your application up and running at http://local.appbuild.com/app_dev.php/ Try to login using one of the following credentials: ``` @@ -46,13 +44,13 @@ user@user.fr => user Front assets (css/js/images) are handled by [Webpack](https://webpack.js.org/). -When you're in development environment (i.e. `http://appbuild.dev/app_dev.php/...`), the project is configured to use webpack dev server to serve assets, it means that the project will seems to be broken until you run the following command: +When you're in production environment (i.e. `http://local.appbuild.com/...`), the project will use the assets found in `web/assets`, it means that you'll have to run `make assets-build` each time you edit an asset file to see the modification in your browser (after refreshing it manually). + +When you're in development environment (i.e. `http://local.appbuild.com/app_dev.php/...`), you can also watch asset modifications to benefit from the hot reloading feature of webpack-dev-server, by typing the following command: ```shell -npm start +make assets-watch ``` -When you're in production environment (i.e. `http://appbuild.dev/...`), the project will use the assets found in `web/assets`, it means that you'll have to run `npm run build` each time you edit an asset file to see the modification in your browser (after refreshing it). - ### Common tasks ```shell # rebuild the whole database with clean fixtures diff --git a/Makefile b/Makefile index 14423eb..9c7e07a 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: provision start stop ssh destroy rebuild clean install update +.PHONY: provision start stop ssh destroy rebuild clean install update clean # # Main targets @@ -56,7 +56,7 @@ install-jwt: test -f var/jwt/private.pem || openssl genrsa -out var/jwt/private.pem -passout pass:Appbuild -aes256 4096 test -f var/jwt/public.pem || openssl rsa -in var/jwt/private.pem -passin pass:Appbuild -pubout -out var/jwt/public.pem -install: install-bin-dev install-bin-prod install-composer install-jwt install-npm db-build assets-build clean +install: install-bin-dev install-bin-prod install-composer install-jwt install-npm db-build assets-build # Update update: update-composer clean @@ -84,12 +84,14 @@ db-update: php bin/console doctrine:migrations:migrate -n # Assets -assets-build: - npm run build +assets-build: clean npm-build -assets-watch: +assets-watch: clean npm start +npm-build: + npm run build + # Production prod-install: install-bin-prod SYMFONY_ENV=prod php bin/composer install --no-dev --optimize-autoloader --no-interaction diff --git a/README.md b/README.md index b4ee9e9..bf021d9 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Appbuild is a "simple" [Symfony 3.3](http://symfony.com/doc/3.3/index.html) appl - [Linux](https://getgnulinux.org) (it may works on Windows/macOS but you can't blame us if it doesn't) - [`php 5.6.19+`](http://php.net) (`php 7+` is recommended) - [`MySQL`](https://www.mysql.com) (it should also work using [`MariaDB`](https://mariadb.org), if not => please let us know) -- [`Node.js`](https://nodejs.org) along with `npm` (it works great with `npm 5.2.0` for instance) +- [`Node.js`](https://nodejs.org) along with `npm` (it works great with `npm 5.7.1` for instance) - HTTP server supporting PHP (such as [`nginx`](http://nginx.org) + [`php-fpm`](http://php.net/manual/fr/install.fpm.php), etc.) ### Application setup @@ -68,6 +68,13 @@ More documentation for specific HTTP servers: ## API documentation +*WARNING* + +*This API is still in BETA, it may be strongly updated.* +*Please be really careful before updating this project if you were already using the API.* + +*/WARNING* + Before using the API, you must read [this documentation about how to be authenticated on the API side](doc/api/authentication.md). - [/api/application](doc/api/application.md) diff --git a/ansible/vagrant-parameters.yml.dist b/ansible/vagrant-parameters.yml.dist index ce60bc6..c59e970 100644 --- a/ansible/vagrant-parameters.yml.dist +++ b/ansible/vagrant-parameters.yml.dist @@ -12,7 +12,7 @@ vm_ip: '192.168.100.70' # List of aliases bound to the Virtual Machine's IP (see "vm_ip") # If the plugin "vagrant-hostmanager" is installed, these aliases will be added to your "/etc/hosts" file automatically. # Else, aliases will be displayed in the console during VM provisioning, then it will be up to you to copy/paste this output in your "/etc/hosts" file. -vm_ip_aliases: ['appbuild.dev'] +vm_ip_aliases: ['local.appbuild.com'] # VM hostname (this will be added to the "vm_ip_aliases" list, displayed in your SSH terminal, etc.) vm_hostname: 'appbuild' diff --git a/ansible/vars.yml b/ansible/vars.yml index 15dc028..faaa7cd 100644 --- a/ansible/vars.yml +++ b/ansible/vars.yml @@ -3,7 +3,7 @@ workspace: '/var/www/Appbuild' sites: - - { name: 'Appbuild', server_name: 'appbuild.dev', template: 'vhost.symfony.j2', client_max_body_size: '1024M' } + - { name: 'Appbuild', server_name: 'local.appbuild.com', template: 'vhost.symfony.j2', client_max_body_size: '1024M' } mysql: users: diff --git a/app/AppKernel.php b/app/AppKernel.php index 23a1424..2b60832 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -65,9 +65,25 @@ public function registerContainerConfiguration(LoaderInterface $loader) // Handle webpack-dev-server assets dynamically served if ($this->getEnvironment() === 'dev') { $loader->load(function (ContainerBuilder $container) { + // Check if webpack dev server is up before using it + @file_get_contents($container->getParameter('webpack_dev_server_base_url')); + if (!isset($http_response_header)) { + return; + } + + // Override "framework.assets.packages.static" configuration to use webpack dev server $container->loadFromExtension('framework', [ 'assets' => [ - 'base_url' => 'http://'.$container->getParameter('webpack_dev_server_host').':8080', + 'packages' => [ + 'static' => [ + 'base_path' => null, + 'base_url' => sprintf( + '%s/%s', + rtrim($container->getParameter('webpack_dev_server_base_url'), '/'), + $container->getParameter('static_assets_base_path') + ), + ], + ], ], ]); }); diff --git a/app/DoctrineMigrations/Version20171019161456.php b/app/DoctrineMigrations/Version20171019161456.php new file mode 100644 index 0000000..2b6c593 --- /dev/null +++ b/app/DoctrineMigrations/Version20171019161456.php @@ -0,0 +1,36 @@ +abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + $this->addSql('ALTER TABLE appbuild_application ADD display_image_file_path VARCHAR(510) DEFAULT NULL, ADD full_size_image_file_path VARCHAR(510) DEFAULT NULL'); + $this->addSql('ALTER TABLE appbuild_build CHANGE file_path file_path VARCHAR(510) DEFAULT NULL'); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + // this down() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + $this->addSql('ALTER TABLE appbuild_application DROP display_image_file_path, DROP full_size_image_file_path'); + $this->addSql('ALTER TABLE appbuild_build CHANGE file_path file_path VARCHAR(255) DEFAULT NULL COLLATE utf8_unicode_ci'); + } +} diff --git a/app/config/config.yml b/app/config/config.yml index 2a74ac9..7c48961 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -2,15 +2,21 @@ imports: - { resource: 'parameters.yml' } - { resource: 'security.yml' } -# Put parameters here that don't need to change on each machine where the app is deployed -# http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration parameters: # Locales routing_locales: '(fr|en)' enabled_locales: ['fr', 'en'] - # Miscellaneous + # Assets + static_assets_base_path: 'assets' # corresponding to __STATIC_ASSETS_BASE_PATH__ value in webpack.config.js + uploads_assets_base_path: 'uploads' + + # Application images + application_images_webroot_relative_dir: '%uploads_assets_base_path%/application_images' + application_images_dir: '%kernel.project_dir%/web/%application_images_webroot_relative_dir%' + + # API build_token_ttl: 600 # seconds framework: @@ -19,7 +25,7 @@ framework: default_locale: '%default_locale%' secret: '%secret%' router: - resource: '%kernel.root_dir%/config/routing.yml' + resource: '%kernel.project_dir%/app/config/routing.yml' strict_requirements: ~ form: ~ csrf_protection: ~ @@ -28,12 +34,14 @@ framework: engines: ['twig'] trusted_hosts: ~ session: - # http://symfony.com/doc/current/reference/configuration/framework.html#handler-id handler_id: 'session.handler.native_file' save_path: '%session_save_path%' fragments: ~ http_method_override: true - assets: ~ + assets: + packages: + static: + base_path: '%static_assets_base_path%' php_errors: log: true @@ -44,6 +52,7 @@ twig: - 'bootstrap_3_layout.html.twig' globals: timezone: '%timezone%' + application_images_webroot_relative_dir: '%application_images_webroot_relative_dir%' doctrine: dbal: diff --git a/app/config/config_dev.yml b/app/config/config_dev.yml index 034680d..2ea0305 100644 --- a/app/config/config_dev.yml +++ b/app/config/config_dev.yml @@ -3,7 +3,7 @@ imports: framework: router: - resource: '%kernel.root_dir%/config/routing_dev.yml' + resource: '%kernel.project_dir%/app/config/routing_dev.yml' strict_requirements: true profiler: { only_exceptions: false } diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist index 6e2ec11..ca0e8f7 100644 --- a/app/config/parameters.yml.dist +++ b/app/config/parameters.yml.dist @@ -1,6 +1,5 @@ # This file is a "template" of what your parameters.yml file should look like -# Set parameters here that may be different on each deployment target of the app, e.g. development, staging, production. -# http://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration +# Set parameters here which may be different on each deployment target of this app, e.g. development, staging, production. parameters: # Database configurations database_host: '127.0.0.1' @@ -16,14 +15,14 @@ parameters: mailer_user: ~ mailer_password: ~ - # A secret key that's used to generate certain security-related tokens + # A secret key that's used to generate some security-related tokens secret: 'ThisTokenIsNotSoSecretChangeIt' # webpack-dev-server (to watch assets modification in development environment) - webpack_dev_server_host: 'appbuild.dev' # could be 'localhost' if you're not using the provided Vagrant environment + webpack_dev_server_base_url: 'http://local.appbuild.com:8080' # could be 'http://localhost:8080' if you're not using the provided Vagrant environment # Symfony session path (set this to '/tmp/sessions' for example if you encounter some issues in dev environment) - session_save_path: '%kernel.root_dir%/../var/sessions/%kernel.environment%' + session_save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%' # Default locale default_locale: 'en' # supported values are 'en' and 'fr' @@ -32,10 +31,10 @@ parameters: timezone: 'UTC' # any PHP timezone (such as 'Europe/Paris') is supported. See http://php.net/manual/fr/timezones.php for complete list. # Path to the directory where builds file will be stored - builds_application_dir: '%kernel.root_dir%/../var/build_files' + builds_application_dir: '%kernel.project_dir%/var/build_files' # JWT parameters for API authentication - jwt_private_key_path: '%kernel.root_dir%/../var/jwt/private.pem' # ssh private key path - jwt_public_key_path: '%kernel.root_dir%/../var/jwt/public.pem' # ssh public key path + jwt_private_key_path: '%kernel.project_dir%/var/jwt/private.pem' # ssh private key path + jwt_public_key_path: '%kernel.project_dir%/var/jwt/public.pem' # ssh public key path jwt_key_pass_phrase: 'Appbuild' # ssh key pass phrase jwt_token_ttl: 31536000 # Approximately one year diff --git a/app/config/security.yml b/app/config/security.yml index 95cb6f2..8786450 100644 --- a/app/config/security.yml +++ b/app/config/security.yml @@ -12,7 +12,7 @@ security: firewalls: # disables authentication for assets and the profiler dev: - pattern: '^/(_(profiler|wdt)|assets)/' + pattern: '^/(_(profiler|wdt)|assets|uploads)/' security: false # API security diff --git a/doc/api/build.md b/doc/api/build.md index 9946f29..d00a07b 100644 --- a/doc/api/build.md +++ b/doc/api/build.md @@ -17,7 +17,7 @@ GET /api/build/{id} "version": "1.5.2", "comment": "This is a comment for this build.\nWith a line break.\nAnd another one.\n", "is_latest": true, - "download_link": "http://app-build.dev/app_dev.php/fr/application/1/build/1/download", + "download_link": "http://my-appbuild.domain/fr/application/1/build/1/download", "application": { "id": 1 } @@ -42,7 +42,7 @@ GET /api/application/{application_id}/build "version": "1.5.2", "comment": "This is a comment for this build.\nWith a line break.\nAnd another one.\n", "is_latest": true, - "download_link": "http://app-build.dev/app_dev.php/fr/application/1/build/1/download", + "download_link": "http://my-appbuild.domain/fr/application/1/build/1/download", "application": { "id": 1 } @@ -67,7 +67,7 @@ GET /api/application/{application_id}/build/latest "id": 1, "version": "1.5.2", "comment": "This is a comment for this build.\nWith a line break.\nAnd another one.\n", - "download_link": "http://app-build.dev/app_dev.php/fr/application/1/build/1/download" + "download_link": "http://my-appbuild.domain/fr/application/1/build/1/download" } ``` @@ -94,19 +94,18 @@ PUT /api/application/{application_id}/build ```json { "build_id": 4, - "upload_location": "http://app-build.domain/api/build/4/file" + "upload_location": "http://my-appbuild.domain/api/build/4/file" } ``` ## Upload a file for a build Note: This route is given by `Create a new build` through `upload_location` response field. -`filename` query param should match the build type (`ipa` or `apk`). ### Request ``` -PUT /api/build/{build_id}/file?filename={filename} +PUT /api/build/{build_id}/file ``` ``` diff --git a/misc/upload_build.sh b/misc/upload_build.sh index 0969bd5..19f4ac3 100755 --- a/misc/upload_build.sh +++ b/misc/upload_build.sh @@ -6,13 +6,13 @@ SCRIPT_NAME=$0 if ! type "jq" > /dev/null 2>&1; then echo "Error: jq command is missing" # only work on recent Bash versions and Zsh echo "Please install command to parse the json response of the api responses." - echo "On Mac : brew install jq" - echo "On Debian : apt-get install jq" + echo "On Mac: brew install jq" + echo "On Debian: apt-get install jq" exit 500 fi # Constants -API_URL='http://appbuild.dev/app_dev.php/api' +API_URL='http://local.appbuild.com/app_dev.php/api' EP_APP_LIST='application/' EP_CREATE_BUILD='application/:application_id/build/' @@ -24,16 +24,16 @@ EP_CREATE_BUILD='application/:application_id/build/' # USAGE function usage() { echo "Usage: $SCRIPT_NAME [-achpruv] file" - echo " - a : Specify an application id" - echo " - c : Specify an build comment" - echo " - h : Help, print this usage" - echo " - p : Specify a password" - echo " - r : Specify a build version number" - echo " - u : Specify a username" - echo " - v : verbose mode" + echo " - a : Specify an application id" + echo " - c : Specify an build comment" + echo " - h: Help, print this usage" + echo " - p : Specify a password" + echo " - r : Specify a build version number" + echo " - u : Specify a username" + echo " - v: verbose mode" echo "" echo "Note: All those options are customisable under the DEFAULT PARAMETERS section in the script" - echo "Example :" + echo "Example:" echo " $SCRIPT_NAME -v -u superadmin@foo.fr -p superadmin -a 78 -r 1.2 -c \"A Comment on the build\" ./build/ios_v2.ipa" } @@ -67,18 +67,18 @@ shift $(( OPTIND - 1 )) p_file="${1:-${BUILD_PATH}}" if [ ! -f "$p_file" ]; then - echo "File not found : ${p_file}" + echo "File not found: ${p_file}" exit 404; fi filename=$(basename $p_file) if test $p_verbose; then - echo "File to upload : $p_file" - echo "with the user : $p_username" - echo "on the application : $p_app_id" - echo "with the version : $p_version" - echo "and the comment : $p_comment" + echo "File to upload: $p_file" + echo "with the user: $p_username" + echo "on the application: $p_app_id" + echo "with the version: $p_version" + echo "and the comment: $p_comment" fi ############################################################################# @@ -117,7 +117,7 @@ function apiCreateBuild() { #{ # "build_id": 10, - # "upload_location": "http://appbuild.dev/app_dev.php/api/build/10/file" + # "upload_location": "http://local.appbuild.com/app_dev.php/api/build/10/file" #} curl -s -X PUT \ $(getAPIUrl ${build_creation_url}) \ @@ -141,8 +141,7 @@ function apiUploadBuild() { ${upload_location} \ -H 'Cache-control: no-cache' \ -H "Authorization: Bearer ${jwt}" \ - --data-binary "@${file_path}" \ - -G --data-urlencode "filename=${filename}" + --data-binary "@${file_path}" } ############################################################################# @@ -151,7 +150,7 @@ function apiUploadBuild() { # Get the jwt to upload the build echo "" -echo -n "Asking for authentication token : " +echo -n "Asking for authentication token: " jwt=`apiLogin ${p_username} ${p_password} | jq -r ".token"` if [ $? -eq 0 ]; then @@ -165,9 +164,9 @@ fi # Create the build with # - jwt: the authentication token # - app_id: the application id (ex: 7) -# - build_version : the version of the build (ex: 1.2) -# - build_comment : a comment on the new build (ex: "A fix on the offline mode") -echo -n "Creation of the build : " +# - build_version: the version of the build (ex: 1.2) +# - build_comment: a comment on the new build (ex: "A fix on the offline mode") +echo -n "Creation of the build: " api_create_build_ret=`apiCreateBuild ${jwt} ${p_app_id} ${p_version} ${p_comment}` upload_location=`echo ${api_create_build_ret} | jq -r ".upload_location"` @@ -183,9 +182,9 @@ fi # Upload the build with # - jwt: the authentication token -# - upload_location : the upload url got from apiCreateBuild -# - file_path : the file's path -echo -n "Upload '${filename}' at ${upload_location} : " +# - upload_location: the upload url got from apiCreateBuild +# - file_path: the file's path +echo -n "Upload '${filename}' at ${upload_location}: " httpcode=`apiUploadBuild ${jwt} ${upload_location} ${p_file}` httpcode=${httpcode//{*}/} diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 177096f..5668201 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1532,6 +1532,7 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", + "fsevents": "1.1.3", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -2908,9 +2909,9 @@ } }, "fine-uploader": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/fine-uploader/-/fine-uploader-5.15.0.tgz", - "integrity": "sha1-R2w8SO8CNJ64E9MqTl/3+wpobfQ=" + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/fine-uploader/-/fine-uploader-5.16.0.tgz", + "integrity": "sha1-hVRJCZYxjGrkCDSYrJxX6S+QtH4=" }, "flat-cache": { "version": "1.2.2", @@ -3017,6 +3018,910 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", + "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.7.0", + "node-pre-gyp": "0.6.39" + }, + "dependencies": { + "abbrev": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ajv": { + "version": "4.11.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.9" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "dev": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.4.2", + "bundled": true, + "dev": true, + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.1" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "1.1.1", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true, + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "mime-db": { + "version": "1.27.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "1.27.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "node-pre-gyp": { + "version": "0.6.39", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "1.0.2", + "hawk": "3.1.3", + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.0", + "rc": "1.2.1", + "request": "2.81.0", + "rimraf": "2.6.1", + "semver": "5.3.0", + "tar": "2.2.1", + "tar-pack": "3.4.0" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.0", + "osenv": "0.1.4" + } + }, + "npmlog": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true, + "dev": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true + }, + "qs": { + "version": "6.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.2.9", + "bundled": true, + "dev": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.1", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.1" + } + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.13.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.8", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.2.9", + "rimraf": "2.6.1", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "uuid": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "extsprintf": "1.0.2" + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + } + } + }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", @@ -6989,15 +7894,6 @@ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", "dev": true }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -7009,6 +7905,15 @@ "strip-ansi": "3.0.1" } }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", diff --git a/package.json b/package.json index bbd96da..e3ae42c 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "node": "7.7.3" }, "scripts": { - "start": "webpack-dev-server --public appbuild.dev:8080 --watch-poll", + "start": "webpack-dev-server --public local.appbuild.com:8080 --watch-poll", "build": "NODE_ENV=production webpack", "lint": "npm run lint-js && npm run lint-scss", "lint-js": "eslint src/", @@ -27,30 +27,30 @@ "fix-js": "eslint --fix src/" }, "dependencies": { - "fine-uploader": "^5.14.1", - "foundation-sites": "^6.3.0", - "jquery": "^3.1.1" + "fine-uploader": "5.16.0", + "foundation-sites": "6.4.3", + "jquery": "3.2.1" }, "devDependencies": { - "babel-core": "^6.26.0", - "babel-loader": "^7.1.2", - "babel-minify-webpack-plugin": "^0.2.0", - "babel-preset-env": "^1.6.0", - "copy-webpack-plugin": "^4.0.1", - "css-loader": "^0.27.3", - "eslint": "^3.19.0", - "eslint-loader": "^1.7.1", - "extract-text-webpack-plugin": "^3.0.0", - "file-loader": "^0.10.1", - "isdev": "^1.0.1", - "node-sass": "^4.5.0", - "postcss-loader": "^1.3.3", - "sass-lint": "^1.10.2", - "sass-loader": "^6.0.3", - "source-map-loader": "^0.2.1", - "style-loader": "^0.14.0", - "url-loader": "^0.5.8", - "webpack": "^3.5.6", - "webpack-dev-server": "^2.8.2" + "babel-core": "6.26.0", + "babel-loader": "7.1.2", + "babel-minify-webpack-plugin": "0.2.0", + "babel-preset-env": "1.6.0", + "copy-webpack-plugin": "4.0.1", + "css-loader": "0.27.3", + "eslint": "3.19.0", + "eslint-loader": "1.9.0", + "extract-text-webpack-plugin": "3.0.0", + "file-loader": "0.10.1", + "isdev": "1.0.1", + "node-sass": "4.5.3", + "postcss-loader": "1.3.3", + "sass-lint": "1.11.1", + "sass-loader": "6.0.6", + "source-map-loader": "0.2.1", + "style-loader": "0.14.1", + "url-loader": "0.5.9", + "webpack": "3.5.6", + "webpack-dev-server": "2.8.2" } } diff --git a/src/AppBundle/Resources/public/favicons/browserconfig.xml b/src/AppBundle/Resources/public/favicons/browserconfig.xml index e2f6c52..0f64f71 100644 --- a/src/AppBundle/Resources/public/favicons/browserconfig.xml +++ b/src/AppBundle/Resources/public/favicons/browserconfig.xml @@ -2,7 +2,7 @@ - + #09345e diff --git a/src/AppBundle/Resources/public/favicons/manifest.json b/src/AppBundle/Resources/public/favicons/manifest.json index ca61c96..cb67cae 100644 --- a/src/AppBundle/Resources/public/favicons/manifest.json +++ b/src/AppBundle/Resources/public/favicons/manifest.json @@ -2,12 +2,12 @@ "name": "Appbuild", "icons": [ { - "src": "/assets/favicons/android-chrome-192x192.png", + "src": "/__STATIC_ASSETS_BASE_PATH__/favicons/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" }, { - "src": "/assets/favicons/android-chrome-256x256.png", + "src": "/__STATIC_ASSETS_BASE_PATH__/favicons/android-chrome-256x256.png", "sizes": "256x256", "type": "image/png" } diff --git a/src/AppBundle/Resources/public/js/application-form.js b/src/AppBundle/Resources/public/js/application-form.js index 15017d7..5c2b849 100644 --- a/src/AppBundle/Resources/public/js/application-form.js +++ b/src/AppBundle/Resources/public/js/application-form.js @@ -1,7 +1,126 @@ -// TODO application.image (should look like build-form.js) +import $ from 'jquery'; +import Routing from 'fos-js-routing'; +import Translator from 'bazinga-translator'; +import 'fine-uploader/jquery.fine-uploader/jquery.fine-uploader.min.js'; -//$('#uploader-img').fineUploader({ -// validation: { -// allowedExtensions: ['jpeg', 'jpg', 'gif', 'png'], -// }, -//}); +const locale = $('html').attr('lang'); +const $form = $('form[name="appbuild_application"]'); + +const commonFineUploaderConfig = { + template: 'upload-container-template', + multiple: false, + validation: { + allowedExtensions: ['jpeg', 'jpg', 'png'], + itemLimit: 1, + }, + text: { + defaultResponseError: Translator.trans('admin.upload.message.default'), + failUpload: Translator.trans('admin.upload.message.upload_failure'), + formatProgress: Translator.trans('admin.upload.message.progress_bar'), + waitingForResponse: Translator.trans('admin.upload.message.waiting_for_response'), + }, + messages: { + typeError: Translator.trans('admin.upload.message.invalid_extension'), + onLeave: Translator.trans('admin.upload.message.on_leave'), + tooManyItemsError: Translator.trans('admin.upload.message.too_many_items'), + }, + deleteFile: { + enabled: true, + endpoint: Routing.generate('appbuild_admin_application_delete_image', { + _locale: locale, + }), + method: 'POST', + deletingFailedText: Translator.trans('admin.upload.message.delete_failed'), + deletingStatusText: Translator.trans('admin.upload.message.deleting'), + }, +}; + +$('#appbuild_application_displayImageFile').fineUploader(Object.assign( + {}, + commonFineUploaderConfig, + { + request: { + endpoint: Routing.generate('appbuild_admin_application_display_image_upload', { + _locale: locale, + }), + inputName: 'displayImageFile', + }, + }, + !$form.data('id') ? {} : { + session: { + endpoint: Routing.generate('appbuild_admin_application_get_display_image', { + _locale: locale, + id: $form.data('id'), + }), + }, + } +)).on('submitted', () => { + // Remove the ability to send files + $form.find('.qq-upload-button-selector, qq-upload-drop-area-selector').hide(); +}).on('cancel', () => { + // Reset the ability to send files + $form.find('.qq-upload-button-selector, qq-upload-drop-area-selector').show(); +}).on('complete', (event, id, name, responseJSON) => { + if (responseJSON.success) { + // Set filename field + $('#appbuild_application_displayImageFilename').val(responseJSON.filename); + } +}).on('sessionRequestComplete', (event, files) => { + if (files[0]) { + // Set filename field + $('#appbuild_application_displayImageFilename').val(files[0].name); + } +}).on('deleteComplete', () => { + // Clear filename field + $('#appbuild_application_displayImageFilename').val(''); +}).on('error', (event, id, name, errorReason) => { + // Clear filename field + $('#appbuild_application_displayImageFilename').val(''); + // Show error message + alert(errorReason); +}); + +$('#appbuild_application_fullSizeImageFile').fineUploader(Object.assign( + {}, + commonFineUploaderConfig, + { + request: { + endpoint: Routing.generate('appbuild_admin_application_full_size_image_upload', { + _locale: locale, + }), + inputName: 'fullSizeImageFile', + }, + }, + !$form.data('id') ? {} : { + session: { + endpoint: Routing.generate('appbuild_admin_application_get_full_size_image', { + _locale: locale, + id: $form.data('id'), + }), + }, + } +)).on('submitted', () => { + // Remove the ability to send files + $form.find('.qq-upload-button-selector, qq-upload-drop-area-selector').hide(); +}).on('cancel', () => { + // Reset the ability to send files + $form.find('.qq-upload-button-selector, qq-upload-drop-area-selector').show(); +}).on('complete', (event, id, name, responseJSON) => { + if (responseJSON.success) { + // Set filename field + $('#appbuild_application_fullSizeImageFilename').val(responseJSON.filename); + } +}).on('sessionRequestComplete', (event, files) => { + if (files[0]) { + // Set filename field + $('#appbuild_application_fullSizeImageFilename').val(files[0].name); + } +}).on('deleteComplete', () => { + // Clear filename field + $('#appbuild_application_fullSizeImageFilename').val(''); +}).on('error', (event, id, name, errorReason) => { + // Clear filename field + $('#appbuild_application_fullSizeImageFilename').val(''); + // Show error message + alert(errorReason); +}); diff --git a/src/AppBundle/Resources/public/js/components/required-when-checked.js b/src/AppBundle/Resources/public/js/components/required-when-checked.js index 4c9aba0..e07ef21 100644 --- a/src/AppBundle/Resources/public/js/components/required-when-checked.js +++ b/src/AppBundle/Resources/public/js/components/required-when-checked.js @@ -1,15 +1,11 @@ import $ from 'jquery'; +const dataAttrName = 'data-required-when-checked'; const requireWhenChecked = ($el) => { - if ($el.prop('checked')) { - $(`#${$el.attr('data-required-when-checked')}`).attr('required', 'required'); - } else { - $(`#${$el.attr('data-required-when-checked')}`).removeAttr('required'); - } + ($el.prop('checked')) ? $($el.attr(dataAttrName)).attr('required', 'required') : $($el.attr(dataAttrName)).removeAttr('required'); }; -const $inputs = $('input[data-required-when-checked]'); -$inputs.each((idx, elem) => { +$(`input[${dataAttrName}]`).each((idx, elem) => { const $input = $(elem); const $inputsWithSameName = $(`input[name="${$input.attr('name')}"]`); diff --git a/src/AppBundle/Resources/public/js/components/show-when-checked.js b/src/AppBundle/Resources/public/js/components/show-when-checked.js index 6e4e2c3..28d886a 100644 --- a/src/AppBundle/Resources/public/js/components/show-when-checked.js +++ b/src/AppBundle/Resources/public/js/components/show-when-checked.js @@ -1,15 +1,11 @@ import $ from 'jquery'; +const dataAttrName = 'data-show-when-checked'; const showWhenChecked = ($el) => { - if ($el.prop('checked')) { - $(`#${$el.attr('data-show-when-checked')}`).show(); - } else { - $(`#${$el.attr('data-show-when-checked')}`).hide(); - } + ($el.prop('checked')) ? $($el.attr(dataAttrName)).show() : $($el.attr(dataAttrName)).hide(); }; -const $inputs = $('input[data-show-when-checked]'); -$inputs.each((idx, elem) => { +$(`input[${dataAttrName}]`).each((idx, elem) => { const $input = $(elem); const $inputsWithSameName = $(`input[name="${$input.attr('name')}"]`); diff --git a/src/AppBundle/Resources/public/scss/components/forms/_file.scss b/src/AppBundle/Resources/public/scss/components/forms/_file.scss index faf59f0..cd94aed 100644 --- a/src/AppBundle/Resources/public/scss/components/forms/_file.scss +++ b/src/AppBundle/Resources/public/scss/components/forms/_file.scss @@ -1,9 +1,23 @@ $uploader-large-height: rem-calc(200px); -$uploader-small-height: rem-calc(30px); +$uploader-small-height: rem-calc(60px); $uploader-large-fz: rem-calc(30px); $uploader-small-fz: rem-calc(16px); +.file-wrapper { + position: relative; + + .qq-upload-delete { + position: absolute; + top: 0; + right: 0; + cursor: pointer; + + .icon { + font-size: $uploader-large-fz; + } + } +} .input-wrap__file { position: relative; @@ -34,7 +48,6 @@ $uploader-small-fz: rem-calc(16px); } .input-wrap__file-label { - position: absolute; z-index: 7; } @@ -43,7 +56,7 @@ $uploader-small-fz: rem-calc(16px); overflow-y: hidden; &:before { - content: attr(qq-area-drop-text) " "; + content: attr(qq-area-drop-text) ' '; position: absolute; z-index: 3; font-size: rem-calc(30px); @@ -99,7 +112,7 @@ $uploader-small-fz: rem-calc(16px); transition-timing-function: $form-transition-timing; &:before { - content: attr(qq-area-drop-text) " "; + content: attr(qq-area-drop-text) ' '; position: absolute; z-index: 3; left: 50%; diff --git a/src/AppBundle/Resources/public/scss/components/table/_table-content.scss b/src/AppBundle/Resources/public/scss/components/table/_table-content.scss index 8d677e0..5d1b976 100644 --- a/src/AppBundle/Resources/public/scss/components/table/_table-content.scss +++ b/src/AppBundle/Resources/public/scss/components/table/_table-content.scss @@ -3,13 +3,6 @@ text-overflow: ellipsis; overflow: hidden; - @include breakpoint(small only) { - height: $table-line-height; - } - - @include breakpoint(medium down) { - width: 100%; - } } .app-name-wrap { @@ -113,6 +106,7 @@ .label-version { width: map-get($label-width, latest-build); + margin-left: 5px; } .label-role { @@ -241,9 +235,19 @@ display: flex; align-items: center; justify-content: center; + + @include breakpoint(small only) { + width: map-get($button-icon-download-mobile-size, width); + height: map-get($button-icon-download-mobile-size, height); + line-height: map-get($button-icon-download-mobile-size, height); + + &:hover, + &:focus { + box-shadow: inset (- map-get($button-icon-download-mobile-size, width)) 0 0 darken($primary-color, 5%); + } + } } .icon-action_download__label { - padding-left: rem-calc(2); font-size: rem-calc(12); } diff --git a/src/AppBundle/Resources/public/scss/components/table/_table-structure.scss b/src/AppBundle/Resources/public/scss/components/table/_table-structure.scss index 2f471f5..fd022f2 100644 --- a/src/AppBundle/Resources/public/scss/components/table/_table-structure.scss +++ b/src/AppBundle/Resources/public/scss/components/table/_table-structure.scss @@ -45,6 +45,7 @@ } } + // vertical separator between cells &:not(:first-child) { .table__cell__content, @@ -62,7 +63,7 @@ } } - &.table__cell-head.table__cell-head-action { + &.table__cell-head.table__cell-head-actions { .table__cell-head__content { @@ -74,23 +75,9 @@ @include breakpoint(small only) { - &.table__cell_mobile-right, &.table__cell-head-app, - &.table__cell-app { - .table__cell-head__content, - .table__cell__content { - - &:after { - background-color: transparent; - } - } - } - - } - - @include breakpoint(medium down) { - &.table__cell-head-app, - &.table__cell-app { + &.table__cell-app, + &.table__cell-actions { .table__cell-head__content, .table__cell__content { @@ -163,6 +150,7 @@ transition-duration: $table-link-transition-duration; transition-property: $table-link-transition-prop; transition-timing-function: $table-link-transition-timing; + outline: none; &:not(.icon-action):hover, &:not(.icon-action):focus { @@ -222,21 +210,6 @@ @include breakpoint(small only) { - .table__cell_mobile-right { - - position: absolute; - right: 0; - height: 100%; - - .table__cell__content { - padding-left: 0; - } - } - - .table__cell-last { - padding-right: map-get($button-icon-size, width) + ($table-padding-side-mobile); - } - .table__cell-firstname, .table__cell-head-firstname { flex: 0 0 150px; @@ -254,11 +227,4 @@ flex: 0 0 calc(100% - 200px); max-width: calc(100% - 200px); } - - .table__cell-app, - .table__cell-head-app, - .table__cell-last { - flex: 0 0 50%; - max-width: 50%; - } } diff --git a/src/AppBundle/Resources/public/scss/components/table/_var.scss b/src/AppBundle/Resources/public/scss/components/table/_var.scss index 0783b1d..fc35ec6 100644 --- a/src/AppBundle/Resources/public/scss/components/table/_var.scss +++ b/src/AppBundle/Resources/public/scss/components/table/_var.scss @@ -40,9 +40,9 @@ $button-icon-size: ( height: rem-calc(35) ); -$label-height: ( - small: rem-calc(20px), - medium: rem-calc(30px) +$button-icon-download-mobile-size: ( + width: rem-calc(150), + height: rem-calc(35) ); $label-width: ( diff --git a/src/AppBundle/Resources/public/scss/partials/_header.scss b/src/AppBundle/Resources/public/scss/partials/_header.scss index f36fc45..195e4d5 100644 --- a/src/AppBundle/Resources/public/scss/partials/_header.scss +++ b/src/AppBundle/Resources/public/scss/partials/_header.scss @@ -107,90 +107,6 @@ $header-space: ( } -.form-search { - z-index: 1; - - @include breakpoint(medium) { - display: flex; - flex-wrap: nowrap; - } -} - -.form-search__input { - display: inline-block; - height: map-get($button-height, small); - margin-bottom: map-get($header-space, small); - padding: rem-calc(10); - transition: all .4s cubic-bezier(0, .795, 0, 1); - background: $secondary-color; - color: $white; - - @include breakpoint(small only) { - position: absolute; - top: 0; - right: 0; - width: map-get($button-height, small); - margin-bottom: map-get($header-space, small); - cursor: pointer; - opacity: 0; - z-index: 3; - - &:focus { - width: 100%; - cursor: text; - opacity: 1; - z-index: 1; - } - } - - @include breakpoint(medium) { - flex: 1 1 0; - order: 2; - height: map-get($button-height, medium); - margin-bottom: map-get($header-space, medium); - padding: rem-calc(10 20); - } - - &, - &:focus { - transition: all .4s cubic-bezier(0, .795, 0, 1); - border: 2px solid $light-secondary; - outline: none; - } - - &:focus { - background: lighten($secondary-color, 2%); - } -} - -.form-search__button { - width: map-get($button-height, small); - height: map-get($button-height, small); - margin-bottom: map-get($header-space, small); - padding: 0; - font-size: map-get($header-icon-fz, small); - - - @include breakpoint(small only) { - position: absolute; - top: 0; - right: 0; - z-index: 2; - } - - @include breakpoint(medium) { - flex: 0 1 auto; - order: 1; - width: map-get($button-height, medium); - height: map-get($button-height, medium); - margin-right: map-get($header-space, medium); - margin-bottom: map-get($header-space, medium); - font-size: map-get($header-icon-fz, medium); - } -} - - - .button_account, .button_language { min-width: map-get($button-height, small); diff --git a/src/AppBundle/Resources/translations/messages.en.yml b/src/AppBundle/Resources/translations/messages.en.yml index ad8e5b5..d6d6fdc 100644 --- a/src/AppBundle/Resources/translations/messages.en.yml +++ b/src/AppBundle/Resources/translations/messages.en.yml @@ -44,6 +44,8 @@ admin: too_many_items: 'Too many files to upload. The max files limit is {itemLimit}' progress_bar: '{percent}% of {total_size}' waiting_for_response: Processing... + delete_failed: Delete failed + deleting: Deleting... datetime: datetime: 'Y-m-d H:i:s' diff --git a/src/AppBundle/Resources/translations/messages.fr.yml b/src/AppBundle/Resources/translations/messages.fr.yml index 4ae9f44..ec7b2fa 100644 --- a/src/AppBundle/Resources/translations/messages.fr.yml +++ b/src/AppBundle/Resources/translations/messages.fr.yml @@ -6,7 +6,7 @@ admin: baseline: by LinkValue header: search: - submit: Search + submit: Rechercher language: fr: fr en: en @@ -44,6 +44,8 @@ admin: too_many_items: 'Trop de fichiers à envoyer. Le nombre maximum de fichiers pouvant être envoyés est [{itemLimit}]' progress_bar: '{percent}% de {total_size}' waiting_for_response: En cours de traitement... + delete_failed: Suppression échouée + deleting: Suppression... datetime: datetime: 'd/m/Y H:i:s' diff --git a/src/AppBundle/Resources/views/upload-container-template.html.twig b/src/AppBundle/Resources/views/Includes/upload-container-template.html.twig similarity index 94% rename from src/AppBundle/Resources/views/upload-container-template.html.twig rename to src/AppBundle/Resources/views/Includes/upload-container-template.html.twig index 0732793..b1e8bf8 100644 --- a/src/AppBundle/Resources/views/upload-container-template.html.twig +++ b/src/AppBundle/Resources/views/Includes/upload-container-template.html.twig @@ -19,7 +19,7 @@
    -
  • +
  • @@ -41,8 +41,8 @@
    - #} - {##} - {##} {% if is_granted('ROLE_USER') %}