diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 0c4ed0c..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,140 +0,0 @@ -version: 2.1 -jobs: - build: - working_directory: ~/phovea - docker: - - image: circleci/python:3.7.11-buster-node-browsers # for node version see Dockerfile on https://hub.docker.com/r/circleci/python - steps: - - checkout - - setup_remote_docker - - run: - name: Show Node.js and npm version - command: | - node -v - npm -v - - run: - name: Show Python and pip version - command: | - python --version - pip --version - - restore_cache: - key: dependency2-cache-{{ checksum "package.json" }} - - run: - name: Install npm dependencies - command: npm install - - save_cache: - key: dependency2-cache-{{ checksum "package.json" }} - paths: - - ./node_modules - - run: - name: Show installed npm dependencies - command: npm list --depth=1 || true - - restore_cache: - key: awscli-1.16.312 - - run: - name: Install AWS CLI - command: | - virtualenv ~/venv - . ~/venv/bin/activate - pip install awscli==1.16.312 - - save_cache: - key: awscli-1.16.312 - paths: - - ~/venv - - run: - name: Login AWS ECR and DockerHub - command: | - . ~/venv/bin/activate - cat > ~/.dockercfg \<< EOF - { - "https://index.docker.io/v1/": { - "auth": "$DOCKER_AUTH" - } - } - EOF - export AWS_DEFAULT_REGION=eu-central-1 - login="$(aws ecr get-login --no-include-email)" - ${login} - - deploy: - name: Build and deploy - command: | - . ~/venv/bin/activate - case "${CIRCLE_BRANCH}${CIRCLE_TAG}" in - master) - awsTag="latest" - ;; - *) - awsTag="${CIRCLE_BRANCH//\//_}${CIRCLE_TAG}" # replace `/` with `_` in branch name - ;; - esac - echo "using tag: --${awsTag}--" - node build.js --skipSaveImage --useSSH --skipTests --noDefaultTags --pushExtra=${awsTag} --pushTo=478950388974.dkr.ecr.eu-central-1.amazonaws.com/caleydo - - store_artifacts: - path: build - destination: build - - deploy: - name: Cleanup untagged AWS repositories - command: | - . ~/venv/bin/activate - export AWS_DEFAULT_REGION=eu-central-1 - baseName=${CIRCLE_PROJECT_REPONAME%_product} - # list repos filter to just the one of this product and delete untagged ones - aws ecr describe-repositories --output text | cut -f6 | grep "caleydo/${baseName}" | while read line; do aws ecr list-images --repository-name $line --filter tagStatus=UNTAGGED --query 'imageIds[*]' --output text | while read imageId; do aws ecr batch-delete-image --output text --repository-name $line --image-ids imageDigest=$imageId; done; done - - deploy: - name: Restart AWS task # assumes the task definition is called - - command: | - . ~/venv/bin/activate - export AWS_DEFAULT_REGION=eu-central-1 - # cleanup name by removing the _product suffix - baseName=${CIRCLE_PROJECT_REPONAME%_product} - awsFamily="${baseName}-${CIRCLE_BRANCH//\//_}" # replace `/` with `_` in branch name - echo "awsFamily --${awsFamily}--" - tasksExists=$(aws --output text ecs list-task-definitions --family-prefix ${awsFamily}) - echo "existsTaskDefinition? --${tasksExists}--" - if [ ! -z "$tasksExists" ]; then - isTaskRunning=$(aws --output text ecs list-tasks --cluster JKU_ASG_Cluster --family ${awsFamily}) - echo "isTaskRunning? --${isTaskRunning}--" - if [ ! -z "$isTaskRunning" ]; then - taskId=$(echo "${isTaskRunning}" | cut -f2) - echo "taskId--${taskId}--" - aws --output text ecs stop-task --cluster JKU_ASG_Cluster --task ${taskId} - fi - aws --output text ecs run-task --cluster JKU_ASG_Cluster --task-definition ${awsFamily} --started-by CircleCIAutoUpdate - fi - - slack/status: - success_message: ':tada: Running _$CIRCLE_JOB job_ for _$CIRCLE_PROJECT_REPONAME $CIRCLE_BRANCH branch_ has succeeded!' - failure_message: ':skull_and_crossbones: Running _$CIRCLE_JOB job_ for _$CIRCLE_PROJECT_REPONAME $CIRCLE_BRANCH branch_ has failed!' -workflows: - version: 2 - build-nightly: - triggers: - - schedule: - cron: "45 0 * * 1-5" # "At 00:45 on every day-of-week from Monday through Friday.”, see: https://crontab.guru/#45_0_*_*_1-5 - filters: - branches: - only: - - develop - jobs: - - build: - context: - - org-global - build-branch: - jobs: - - build: - context: - - org-global - filters: - tags: - ignore: /^v.*/ - build-tag: - jobs: - - build: - context: - - org-global - filters: - branches: - ignore: /.*/ - tags: - only: /^v.*/ -orbs: - slack: circleci/slack@3.4.2 diff --git a/.gitignore b/.gitignore index cde3b69..c11c403 100644 --- a/.gitignore +++ b/.gitignore @@ -10,18 +10,25 @@ package-lock.json !/.circleci/* !/.github !templates/ +!templates/web !templates/web/* !templates/web/config !templates/web/config/* !templates/web/deploy +!templates/web/deploy/* !templates/web/deploy/web !templates/web/deploy/web/* !templates/api/ +!templates/api/* !templates/api/deploy +!templates/api/deploy/* !templates/api/deploy/api !templates/api/deploy/api/* +!templates/api/deploy/kokiri +!templates/api/deploy/kokiri/* !.editorconfig !.gitattributes +!.gitignore !.yo-rc.json !ISSUE_TEMPLATE.md !LICENSE diff --git a/build.js b/build.js index 6fa588e..c1c4aa6 100644 --- a/build.js +++ b/build.js @@ -220,10 +220,9 @@ function spawn(cmd, args, opts) { * @param cmd the command to execute as a string * @return {*} */ -function npm(cwd, cmd) { - console.log(cwd, chalk.blue('running npm', cmd)); - const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm'; - return spawn(npm, (cmd || 'install').split(' '), {cwd, env}); +function yarn(cwd, cmd) { + console.log(cwd, chalk.blue('running yarn', cmd)); + return spawn('yarn', (cmd || 'install').split(' '), {cwd, env}); } /** @@ -667,13 +666,13 @@ function createWorkspace(p) { } function installWebDependencies(p) { - return npm(p.tmpDir, 'install'); + return yarn(p.tmpDir, 'install --no-immutable'); } function showWebDependencies(p) { // `npm ls` fails if some peerDependencies are not installed // since this function is for debug purposes only, we catch possible errors of `npm()` and resolve it with status code `0`. - return npm(p.tmpDir, 'list --depth=1') + return yarn(p.tmpDir, 'info --recursive --dependents') .catch(() => Promise.resolve(0)); // status code = 0 } @@ -692,7 +691,7 @@ function resolvePluginTypes(p) { } function buildWeb(p) { - const step = npm(p.tmpDir, `run dist`); + const step = yarn(p.tmpDir, `run dist`); // move to target directory return step.then(() => fs.renameAsync(`${p.tmpDir}/dist/bundles.tar.gz`, `./build/${p.label}.tar.gz`)); } diff --git a/package.json b/package.json index 5a111a8..e6d4f86 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "bluebird": "3.7.2", "chalk": "3.0.0", "fs-extra": "^9.1.0", - "generator-phovea": "git+ssh://git@github.com:phovea/generator-phovea#develop", "lodash": ">=4.17.21", "yamljs": "0.3.0", "yargs-parser": ">=18.1.2", diff --git a/phovea_product.json b/phovea_product.json index c1109cc..de14462 100644 --- a/phovea_product.json +++ b/phovea_product.json @@ -3,22 +3,22 @@ "type": "web", "label": "coral_frontend", "repo": "Caleydo/coral_public", - "branch": "develop", + "branch": "v4.0.0", "additional": [ { "name": "coral", "repo": "Caleydo/coral", - "branch": "develop" + "branch": "comparison_2023" }, { "name": "phovea_security_store_generated", "repo": "datavisyn/phovea_security_store_generated", - "branch": "develop" + "branch": "v15.0.0" }, { "name": "tdp_core", "repo": "datavisyn/tdp_core", - "branch": "develop" + "branch": "v20.0.0" } ] }, @@ -26,23 +26,29 @@ "type": "api", "label": "coral_backend", "repo": "datavisyn/tdp_core", - "branch": "develop", + "branch": "v20.0.0", "additional": [ { "name": "coral", "repo": "Caleydo/coral", - "branch": "develop" + "branch": "comparison_2023" }, { "name": "phovea_security_store_generated", "repo": "datavisyn/phovea_security_store_generated", - "branch": "develop" + "branch": "v15.0.0" }, { "name": "tdp_publicdb", "repo": "Caleydo/tdp_publicdb", - "branch": "develop" + "branch": "v14.0.0" } ] + }, + { + "type": "api", + "label": "kokiri", + "repo": "jku-vds-lab/kokiri", + "branch": "main" } ] diff --git a/templates/api/deploy/kokiri/Dockerfile b/templates/api/deploy/kokiri/Dockerfile new file mode 100644 index 0000000..d154d8f --- /dev/null +++ b/templates/api/deploy/kokiri/Dockerfile @@ -0,0 +1,19 @@ +FROM python:3.10-buster +LABEL maintainer="klaus.eckelt@jku.at" + +WORKDIR /phovea + +ENV PYTHONUNBUFFERED=1 +ENV ENV=production +ENV PHOVEA_CONFIG_PATH=/phovea/config.json + +# install dependencies last step such that everything before can be cached +COPY requirements.txt . +RUN apt-get update && pip install --no-cache-dir -r /phovea/requirements.txt + +COPY ./build/source ./ +COPY ./kokiri/data ./kokiri/data + +CMD ["python", "-m", "uvicorn", "kokiri.server:app", "--host", "0.0.0.0", "--port", "80"] + +EXPOSE 80 diff --git a/templates/web/config/webpack.dev.js b/templates/web/config/webpack.dev.js new file mode 100644 index 0000000..917e71e --- /dev/null +++ b/templates/web/config/webpack.dev.js @@ -0,0 +1,327 @@ +const {CleanWebpackPlugin} = require('clean-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const Dotenv = require('dotenv-webpack'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +//for debugging issues +//const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; +//helper module +const webpackHelper = require('./webpackHelper'); +//general constants +const path = require('path'); +const webpack = require('webpack'); +const resolve = require('path').resolve; +const workspacePath = resolve(__dirname, '../'); +const now = new Date(); +const prefix = (n) => n < 10 ? ('0' + n) : n.toString(); +const buildId = `${now.getUTCFullYear()}${prefix(now.getUTCMonth() + 1)}${prefix(now.getUTCDate())}-${prefix(now.getUTCHours())}${prefix(now.getUTCMinutes())}${prefix(now.getUTCSeconds())}`; +const envMode = process.argv.indexOf('--mode') >= 0 ? process.argv[process.argv.indexOf('--mode') + 1].trim().toLowerCase() : 'development'; +const isDev = envMode === 'development'; +//workspace constants +const workspaceYoRcFile = require(path.join(workspacePath, '.yo-rc-workspace.json')); +const workspaceBuildInfoFile = path.join(workspacePath, 'package-lock.json'); +const workspaceMetaDataFile = path.join(workspacePath, 'metaData.json'); +const workspaceRegistryFile = path.join(workspacePath, 'phovea_registry.js'); +const workspaceAliases = workspaceYoRcFile.workspaceAliases || []; +const workspaceRegistry = workspaceYoRcFile.registry || []; +const workspaceVendors = workspaceYoRcFile.vendors || []; +const workspaceName = workspacePath.substr(workspacePath.lastIndexOf('/') + 1); +const workspaceProxy = workspaceYoRcFile.devServerProxy || {}; +const workspaceRepos = workspaceYoRcFile.frontendRepos || []; +//app constants +const envApp = process.argv.filter((e) => e.startsWith('--app=')); +const defaultApp = envApp.length > 0 ? envApp[0].substring(6).trim() : workspaceYoRcFile.defaultApp; +const defaultAppPath = path.join(workspacePath, defaultApp); +const appPkg = require(path.join(defaultAppPath, 'package.json')); +const libName = appPkg.name; +const libDesc = appPkg.description; +const {entries, registry, vendors, libraryAliases, filesToLoad, copyFiles} = require(path.join(defaultAppPath, '.yo-rc.json'))['generator-phovea']; +const fileLoaderRegex = filesToLoad && filesToLoad['file-loader'] ? RegExp(String.raw`(.*)\/(${filesToLoad['file-loader']})\.(html|txt)$`) : RegExp(/^$/); +const copyAppFiles = copyFiles ? copyFiles.map((file) => ({from: path.join(defaultAppPath, file), to: path.join(workspacePath, 'bundles', path.basename(file)) })) : []; +// Merge app and workspace properties +const mergedAliases = { + ...libraryAliases, + ...workspaceAliases +}; +const mergedRegistry = { + ...registry, + ...workspaceRegistry +}; +const mergedVendors = { + ...vendors, + ...workspaceVendors +}; +// Regex for cacheGroups +const workspaceRegex = new RegExp(String.raw`[\\/]${workspaceName}[\\/](${workspaceRepos.join('|')})[\\/]`); +const vendorRegex = Object.assign({}, + ...Object.entries(mergedVendors). + map((item) => ({[item[0]]: new RegExp(`[\\/]node_modules[\\/](${item[1]})`)}) + ) +); +const vendorWorkspaceRegex = Object.assign({}, + ...Object.entries(mergedVendors). + map((item) => ({[item[0]]: new RegExp(`[\\/]${workspaceName}[\\/](${item[1]})`)}) + ) +); +// html webpack entries +let HtmlWebpackPlugins = []; +Object.values(entries).map(function (entry) { + HtmlWebpackPlugins.push(new HtmlWebpackPlugin({ + inject: true, + template: path.join(defaultAppPath, entry['template']), + filename: entry['html'], + title: libName, + excludeChunks: entry['excludeChunks'], + chunksSortMode: 'auto', + minify: { + removeComments: true, + collapseWhitespace: true + }, + meta: { + description: libDesc + } + })); +}); +//include/exclude feature of the registry +const preCompilerFlags = {flags: (mergedRegistry || {}).flags || {}}; +const includeFeature = mergedRegistry ? (extension, id) => { + const exclude = mergedRegistry.exclude || []; + const include = mergedRegistry.include || []; + if (!exclude && !include) { + return true; + } + const test = (f) => Array.isArray(f) ? extension.match(f[0]) && (id || '').match(f[1]) : extension.match(f); + return include.every(test) && !exclude.some(test); +} : () => true; +//webpack config +const config = { + mode: envMode, + devtool: 'inline-source-map', + output: { + path: path.join(workspacePath, 'bundles'), + filename: '[name].[hash].js', + publicPath: '', + library: libName, + libraryTarget: 'umd', + umdNamedDefine: false + }, + entry: webpackHelper.injectRegistry(workspacePath, defaultAppPath, [workspaceRegistryFile], entries), + resolve: { + cacheWithContext: false, //for performance: we don't use context specific plugins + symlinks: false, //don't need symlinks because of alias for workspace + extensions: ['.js'], + alias: + Object.assign({}, + ...workspaceRepos.map((item) => ({[item]: (workspacePath + `/${item}`)})), + ...Object.entries(mergedAliases).map((item) => ({[item[0]]: path.join(workspacePath, 'node_modules', item[1])})) + ), + modules: [ + path.join(workspacePath, 'node_modules') + ], + }, + devServer: { + static: resolve(workspacePath, 'bundles'), + compress: true, + host: 'localhost', + open: false, + proxy: { + // Append on top to allow overriding /api/v1/ for example + ...workspaceProxy, + ...{ + '/api/*': { + target: 'http://localhost:9000', + secure: false, + ws: true + }, + '/login': { + target: 'http://localhost:9000', + secure: false + }, + '/logout': { + target: 'http://localhost:9000', + secure: false + }, + '/loggedinas': { + target: 'http://localhost:9000', + secure: false + }, + '/kokiri/*': { + target: 'http://localhost:9666', + secure: false, + ws: true + }, + // Append on bottom to allow override of exact key matches like /api/* + ...workspaceProxy + } + }, + client: { + overlay: false, + }, + }, + watchOptions: { + poll: true, + aggregateTimeout: 2000, + ignored: /node_modules/ + }, + module: { + rules: [ + { + test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, + loader: 'url-loader', + options: { + limit: 10000, // inline <= 10kb + mimetype: 'application/font-woff' + } + }, + { + test: /\.svg(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, + loader: 'url-loader', + options: { + limit: 10000, // inline <= 10kb + mimetype: 'image/svg+xml', + esModule: false + } + }, + {test: /\.(ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader'}, + { + test: /\.(css)$/, + use: [ + MiniCssExtractPlugin.loader, 'css-loader' + ] + }, + { + test: /\.(scss)$/, + use: [ + MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader' + ] + }, + { + test: /\.js$/, + enforce: 'pre', + use: ['source-map-loader'], + exclude: /[\\/]node_modules[\\/](lineupjs|lineupengine)[\\/]/ + }, + {test: /\.(xml)$/, use: 'xml-loader'}, + {test: /\.(txt)$/, use: 'raw-loader'}, + {test: /\.(html)$/, use: 'html-loader'}, + { + test: /\.(png|jpg|gif|webp)$/, + use: [ + { + loader: `url-loader`, + options: { + esModule: false + } + }] + }, + { + test: /(.*)\/phovea(_registry)?\.(js|ts)$/, use: [{ + loader: 'ifdef-loader', + options: Object.assign({include: includeFeature}, preCompilerFlags), + + }] + }, + { + test: require.resolve('jquery'), + loader: 'expose-loader', + options: { + exposes: ['window.jQuery', '$'] + } + }, + // used to remove inline loaders + {test: fileLoaderRegex, loader: 'file-loader?name=[name].[ext]'} + ], + }, + optimization: { + nodeEnv: false, // will be set by DefinePlugin + minimize: false, // only in dev mode + namedModules: true, // only in dev mode + namedChunks: true, // only in dev mode + removeAvailableModules: false, // only in dev mode, because of performance issue + removeEmptyChunks: true, // should always be set to true + mergeDuplicateChunks: true, // should always be set to true + providedExports: true, // should always be set to true + usedExports: true, // should always be set to true + sideEffects: true, // should always be set to true as long as we don't change our code + portableRecords: false, // should always be set to false + flagIncludedChunks: false, // only in dev mode + occurrenceOrder: false, // only in dev mode + concatenateModules: false, // only in dev mode + moduleIds: 'hashed', + chunkIds: 'named', // only in dev mode + runtimeChunk: 'single', //one runtime instance for all entries + splitChunks: { + chunks: 'all', + cacheGroups: { + workspace: { + test: workspaceRegex, + priority: -5, + name(module) { + const key = Object.keys(mergedVendors).find((key) => vendorWorkspaceRegex[key].test(module.context)); + return key ? key : 'workspace'; + } + }, + vendors: { + test: /[\\/]node_modules[\\/]/, + priority: -10, + name(module) { + const key = Object.keys(mergedVendors).find((key) => vendorRegex[key].test(module.context)); + return key ? key : 'vendors'; + } + } + } + }, + }, + plugins: [ + new CleanWebpackPlugin({ + cleanOnceBeforeBuildPatterns: [ + '**/*', + path.join(workspacePath, 'bundles/**/*') + ] + }), + ...HtmlWebpackPlugins, + new MiniCssExtractPlugin(), + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify(envMode), + 'process.env.__VERSION__': JSON.stringify(appPkg.version), + 'process.env.__LICENSE__': JSON.stringify(appPkg.license), + 'process.env.__BUILD_ID__': JSON.stringify(buildId), + 'process.env.__APP_CONTEXT__': JSON.stringify('/'), + 'process.env.__DEBUG__': JSON.stringify(isDev) + }), + new Dotenv({ + path: path.join(workspacePath, '.env'), // load this now instead of the ones in '.env' + safe: false, // load '.env.example' to verify the '.env' variables are all set. Can also be a string to a different file. + allowEmptyValues: true, // allow empty variables (e.g. `FOO=`) (treat it as empty string, rather than missing) + systemvars: true, // load all the predefined 'process.env' variables which will trump anything local per dotenv specs. + silent: true, // hide any errors + defaults: false // load '.env.defaults' as the default values if empty. + }), + new CopyWebpackPlugin({ + patterns: copyAppFiles.concat([ + { + from: workspaceMetaDataFile, to: path.join(workspacePath, 'bundles', 'phoveaMetaData.json'), + //generate meta data file + transform() { + return webpackHelper.generateMetaDataFile(defaultAppPath, {buildId}); + } + }, + //use package-lock json as buildInfo + {from: workspaceBuildInfoFile, to: path.join(workspacePath, 'bundles', 'buildInfo.json')} + ] + )}), + //for debugging issues + /*new BundleAnalyzerPlugin({ + // set to 'server' to start analyzer during build + analyzerMode: 'disabled', + generateStatsFile: true, + statsOptions: {source: false} + })*/ + ], + stats: { + //for source-map-loader: lineup/js warnings + warningsFilter: [/Failed to parse source map/], + } +}; +//console.log(JSON.stringify(config, null, '\t')); +module.exports = config; diff --git a/templates/web/deploy/web/Dockerfile b/templates/web/deploy/web/Dockerfile index ecd2b11..2f59876 100644 --- a/templates/web/deploy/web/Dockerfile +++ b/templates/web/deploy/web/Dockerfile @@ -3,8 +3,12 @@ FROM nginx:alpine LABEL maintainer="samuel.gratzl@datavisyn.io" ENV PHOVEA_API_SERVER=api +ENV KOKIRI_SERVER=kokiri ENV PHOVEA_NGINX_PORT=80 COPY ./deploy/web/nginx-default.conf /etc/nginx/conf.d/default.conf -CMD sed -i -e "s/PHOVEA_API_SERVER/${PHOVEA_API_SERVER-api}/g" /etc/nginx/conf.d/default.conf && sed -i -e "s/PHOVEA_NGINX_PORT/${PHOVEA_NGINX_PORT-api}/g" /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;' +CMD sed -i -e "s/PHOVEA_API_SERVER/${PHOVEA_API_SERVER-api}/g" /etc/nginx/conf.d/default.conf && \ + sed -i -e "s/KOKIRI_SERVER/${KOKIRI_SERVER-kokiri}/g" /etc/nginx/conf.d/default.conf && \ + sed -i -e "s/PHOVEA_NGINX_PORT/${PHOVEA_NGINX_PORT-api}/g" /etc/nginx/conf.d/default.conf && \ + nginx -g 'daemon off;' COPY ./bundles /usr/share/nginx/html COPY ./deploy/web/*.html /usr/share/nginx/html/ diff --git a/templates/web/deploy/web/nginx-default.conf b/templates/web/deploy/web/nginx-default.conf index 66bc64e..687b023 100644 --- a/templates/web/deploy/web/nginx-default.conf +++ b/templates/web/deploy/web/nginx-default.conf @@ -73,6 +73,35 @@ server { proxy_intercept_errors on; } + + location ~ ^/(kokiri) { + + proxy_pass http://KOKIRI_SERVER; + # HTTP 1.1 support + proxy_http_version 1.1; + proxy_buffering off; + proxy_set_header Host $http_host; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $proxy_connection; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; + + # Mitigate httpoxy attack (see README for details) + proxy_set_header Proxy ""; + + # timeout in 600sec = 10min + proxy_connect_timeout 600; + proxy_send_timeout 600; + proxy_read_timeout 600; + send_timeout 600; + client_max_body_size 64m; + + add_header Cache-Control private; + expires $expires; + + proxy_intercept_errors on; + } location /app/phoveaMetaData.json { # get file from root and not the app directory diff --git a/templates/web/workspace.scss b/templates/web/workspace.scss index 6d902f7..ffa133f 100644 --- a/templates/web/workspace.scss +++ b/templates/web/workspace.scss @@ -22,20 +22,17 @@ @import "~tdp_core/dist/scss/abstracts/variables"; // then all other plugins in this workspace (excluding other apps) -@import "~tdp_gene/dist/scss/abstracts/variables"; @import "~tdp_publicdb/dist/scss/abstracts/variables"; @import "~tourdino/dist/scss/abstracts/variables"; -@import "~@fortawesome/fontawesome-free/scss/variables"; +@import "~tdp_core/dist/scss/fontawesome"; // import mixins -@import "~@fortawesome/fontawesome-free/scss/mixins"; @import "~tdp_core/dist/scss/abstracts/mixins"; @debug('import plugin main scss'); // all main scss (in opposite order of the variables scss @import "~tourdino/dist/scss/main"; @import "~tdp_publicdb/dist/scss/main"; -@import "~tdp_gene/dist/scss/main"; @import "~tdp_core/dist/scss/main"; @import "~ordino/dist/scss/main"; @import "~coral/dist/scss/main";