Use injected configuration from Nginx at runtime instead of build time (#30)

* Use envsubst and nginx templates to generate nginx configs which can substitute environment variables and inject into the index.html file

* Fix path in dockerfile. Add .gitignore and .env.example files. Fix nginx-linux template.

* Add all environment variables. Add prefix to all environment variables. Update scripts to attempt to substitute all environment variables with the prefix

* Setup dockerfile to execute a bash script. use env.example for fetching environment variables in development

* Toggle features based on injected configs. Fix nginx template substitution script.

* Update env.example file

* Remove debug code from start-nginx.sh

* Fix nginx config templates by adding quotes by default. Fix sed regex to include numerals. Toggle social login buttons on Login page based on the config.

* Update rapid api environment variable name. Toggle oauth buttons based on config in SignUp page. Update .env.example to be a union of server and client environment variables

* Adding a Map disabled message on Map widget

* Adding links to Privacy policy and TNC

* Use REACT_APP_ env variables with higher priority over injected config variables for toggling features

* Update netlify.toml by commenting out the build environment variables

* Remove env variables not required by the client

* Remove start-storybook entry from package.json

* Fix netlify.toml. Fallback algolia configs

* Add contexts to netlify.toml for successful deploys. Swith to using APPSMITH_MARKETPLACE_URL as the toggle for RapidAPI feature on the client. Remove comments in nginx config templates. Fix template used in dockerfile.

Co-authored-by: Satbir Singh <apple@apples-MacBook-Pro.local>
Co-authored-by: Satbir Singh <satbir121@gmail.com>
This commit is contained in:
Abhinav Jha 2020-07-07 15:52:17 +05:30 committed by GitHub
parent d85376b90c
commit 94b28311c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 822 additions and 630 deletions

50
.env.example Normal file
View File

@ -0,0 +1,50 @@
# Rename this to .env
# Note: Please donot include quotes (double or single) in the values
# Sentry
APPSMITH_SENTRY_DSN=
# Hotjar
APPSMITH_HOTJAR_HJID=
APPSMITH_HOTJAR_HJSV=
# Google OAuth
APPSMITH_OAUTH2_GOOGLE_CLIENT_ID=
APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET=
# Github OAuth
APPSMITH_OAUTH2_GITHUB_CLIENT_ID=
APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET=
# Segment
APPSMITH_SEGMENT_KEY=
# RapidAPI
APPSMITH_RAPID_API_KEY_VALUE=
APPSMITH_MARKETPLACE_URL=
# Optimizely
APPSMITH_OPTIMIZELY_KEY=
# Algolia Search (Docs)
APPSMITH_ALGOLIA_API_ID=
APPSMITH_ALGOLIA_API_KEY=
APPSMITH_ALGOLIA_SEARCH_INDEX_NAME=
#Client log level (debug | error)
APPSMITH_CLIENT_LOG_LEVEL=
# GOOGLE client API KEY
APPSMITH_GOOGLE_MAPS_API_KEY=
# Email server
APPSMITH_MAIL_ENABLED=
APPSMITH_MAIL_HOST=
APPSMITH_MAIL_PORT=
APPSMITH_MAIL_USERNAME=
APPSMITH_MAIL_PASSWORD=
# Email server feature toggles
# true | false values
APPSMITH_MAIL_SMTP_AUTH=
APPSMITH_MAIL_SMTP_TLS_ENABLED=

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
.DS_Store
.idea
*.iml
.env

View File

@ -33,3 +33,5 @@ cypress/screenshots
results/
/docker/*.pem
/docker/nginx.conf

View File

@ -1,7 +1,8 @@
FROM nginx:1.17.9-alpine
COPY ./build /var/www/appsmith
RUN ls -al /var/www/appsmith
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
COPY ./docker/templates/nginx-linux.conf.template /nginx.conf.template
COPY ./docker/start-nginx.sh /start-nginx.sh
CMD ["/start-nginx.sh"]

View File

@ -1,88 +0,0 @@
#### TODO: Please change the backend endpoint from release-api.appsmith.com --> https://release-api.appsmith.com when merged into release
server {
listen 80;
server_name dev.appsmith.com;
client_max_body_size 10m;
gzip on;
gzip_proxied any;
proxy_ssl_server_name on;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
location / {
proxy_pass http://localhost:3000;
}
location /f {
proxy_pass https://cdn.optimizely.com/;
}
location /api {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /oauth2 {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /login {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
}
server {
listen 443 ssl http2;
server_name dev.appsmith.com;
ssl_certificate /etc/certificate/dev.appsmith.com.pem;
ssl_certificate_key /etc/certificate/dev.appsmith.com-key.pem;
# include /etc/letsencrypt/options-ssl-nginx.conf;
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
gzip on;
proxy_ssl_server_name on;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
location / {
proxy_pass http://localhost:3000;
}
location /f {
proxy_pass https://cdn.optimizely.com/;
}
location /api {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /oauth2 {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /login {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
}

View File

@ -1,87 +0,0 @@
#### TODO: Please change the backend endpoint from release-api.appsmith.com --> https://release-api.appsmith.com when merged into release
server {
listen 80;
server_name dev.appsmith.com;
client_max_body_size 10m;
gzip on;
gzip_proxied any;
proxy_ssl_server_name on;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
location / {
proxy_pass http://host.docker.internal:3000;
}
location /f {
proxy_pass https://cdn.optimizely.com/;
}
location /api {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /oauth2 {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /login {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
}
server {
listen 443 ssl http2;
server_name dev.appsmith.com;
ssl_certificate /etc/certificate/dev.appsmith.com.pem;
ssl_certificate_key /etc/certificate/dev.appsmith.com-key.pem;
# include /etc/letsencrypt/options-ssl-nginx.conf;
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
gzip on;
proxy_ssl_server_name on;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
location / {
proxy_pass http://host.docker.internal:3000;
}
location /f {
proxy_pass https://cdn.optimizely.com/;
}
location /api {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /oauth2 {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /login {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
}

View File

@ -0,0 +1,4 @@
#!/bin/sh
set -ue
cat /nginx.conf.template | envsubst "$(printf '$%s,' $(env | grep -Eo '^APPSMITH_[A-Z0-9_]+'))" | sed -e 's|\${\(APPSMITH_[A-Z0-9_]*\)}||g' | tee /etc/nginx/conf.d/app.conf
exec nginx -g 'daemon off;'

View File

@ -0,0 +1,121 @@
server {
listen 80;
server_name dev.appsmith.com;
client_max_body_size 10m;
gzip on;
gzip_proxied any;
proxy_ssl_server_name on;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Accept-Encoding "";
sub_filter_once off;
location / {
proxy_pass http://localhost:3000;
sub_filter __APPSMITH_SENTRY_DSN__ '${APPSMITH_SENTRY_DSN}';
sub_filter __APPSMITH_APPSMITH_HOTJAR_HJID__ '${APPSMITH_HOTJAR_HJID}';
sub_filter __APPSMITH_HOTJAR_HJSV__ '${APPSMITH_HOTJAR_HJSV}';
sub_filter __APPSMITH_OAUTH2_GOOGLE_CLIENT_ID__ '${APPSMITH_OAUTH2_GOOGLE_CLIENT_ID}';
sub_filter __APPSMITH_OAUTH2_GITHUB_CLIENT_ID__ '${APPSMITH_OAUTH2_GITHUB_CLIENT_ID}';
sub_filter __APPSMITH_MARKETPLACE_URL__ '${APPSMITH_MARKETPLACE_URL}';
sub_filter __APPSMITH_SEGMENT_KEY__ '${APPSMITH_SEGMENT_KEY}';
sub_filter __APPSMITH_OPTIMIZELY_KEY__ '${APPSMITH_OPTIMIZELY_KEY}';
sub_filter __APPSMITH_ALGOLIA_API_ID__ '${APPSMITH_ALGOLIA_API_ID}';
sub_filter __APPSMITH_ALGOLIA_SEARCH_INDEX_NAME__ '${APPSMITH_ALGOLIA_SEARCH_INDEX_NAME}';
sub_filter __APPSMITH_ALGOLIA_API_KEY__ '${APPSMITH_ALGOLIA_API_KEY}';
sub_filter __APPSMITH_CLIENT_LOG_LEVEL__ '${APPSMITH_CLIENT_LOG_LEVEL}';
sub_filter __APPSMITH_GOOGLE_MAPS_API_KEY__ '${APPSMITH_GOOGLE_MAPS_API_KEY}';
sub_filter __APPSMITH_TNC_PP__ '${APPSMITH_TNC_PP}';
}
location /f {
proxy_pass https://cdn.optimizely.com/;
}
location /api {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /oauth2 {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /login {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
}
server {
listen 443 ssl http2;
server_name dev.appsmith.com;
ssl_certificate /etc/certificate/dev.appsmith.com.pem;
ssl_certificate_key /etc/certificate/dev.appsmith.com-key.pem;
# include /etc/letsencrypt/options-ssl-nginx.conf;
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
gzip on;
proxy_ssl_server_name on;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Accept-Encoding "";
sub_filter_once off;
location / {
proxy_pass http://localhost:3000;
sub_filter __APPSMITH_SENTRY_DSN__ '${APPSMITH_SENTRY_DSN}';
sub_filter __APPSMITH_HOTJAR_HJID__ '${APPSMITH_HOTJAR_HJID}';
sub_filter __APPSMITH_HOTJAR_HJSV__ '${APPSMITH_HOTJAR_HJSV}';
sub_filter __APPSMITH_OAUTH2_GOOGLE_CLIENT_ID__ '${APPSMITH_OAUTH2_GOOGLE_CLIENT_ID}';
sub_filter __APPSMITH_OAUTH2_GITHUB_CLIENT_ID__ '${APPSMITH_OAUTH2_GITHUB_CLIENT_ID}';
sub_filter __APPSMITH_MARKETPLACE_URL__ '${APPSMITH_MARKETPLACE_URL}';
sub_filter __APPSMITH_SEGMENT_KEY__ '${APPSMITH_SEGMENT_KEY}';
sub_filter __APPSMITH_OPTIMIZELY_KEY__ '${APPSMITH_OPTIMIZELY_KEY}';
sub_filter __APPSMITH_ALGOLIA_API_ID__ '${APPSMITH_ALGOLIA_API_ID}';
sub_filter __APPSMITH_ALGOLIA_SEARCH_INDEX_NAME__ '${APPSMITH_ALGOLIA_SEARCH_INDEX_NAME}';
sub_filter __APPSMITH_ALGOLIA_API_KEY__ '${APPSMITH_ALGOLIA_API_KEY}';
sub_filter __APPSMITH_CLIENT_LOG_LEVEL__ '${APPSMITH_CLIENT_LOG_LEVEL}';
sub_filter __APPSMITH_GOOGLE_MAPS_API_KEY__ '${APPSMITH_GOOGLE_MAPS_API_KEY}';
sub_filter __APPSMITH_TNC_PP__ '${APPSMITH_TNC_PP}';
}
location /f {
proxy_pass https://cdn.optimizely.com/;
}
location /api {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /oauth2 {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /login {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
}

View File

@ -0,0 +1,123 @@
server {
listen 80;
server_name dev.appsmith.com;
client_max_body_size 10m;
gzip on;
gzip_proxied any;
proxy_ssl_server_name on;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Accept-Encoding "";
index index.html index.htm;
sub_filter_once off;
location / {
proxy_pass http://host.docker.internal:3000;
sub_filter __APPSMITH_SENTRY_DSN__ '${APPSMITH_SENTRY_DSN}';
sub_filter __APPSMITH_HOTJAR_HJID__ '${APPSMITH_HOTJAR_HJID}';
sub_filter __APPSMITH_HOTJAR_HJSV__ '${APPSMITH_HOTJAR_HJSV}';
sub_filter __APPSMITH_OAUTH2_GOOGLE_CLIENT_ID__ '${APPSMITH_OAUTH2_GOOGLE_CLIENT_ID}';
sub_filter __APPSMITH_OAUTH2_GITHUB_CLIENT_ID__ '${APPSMITH_OAUTH2_GITHUB_CLIENT_ID}';
sub_filter __APPSMITH_MARKETPLACE_URL__ '${APPSMITH_MARKETPLACE_URL}';
sub_filter __APPSMITH_SEGMENT_KEY__ '${APPSMITH_SEGMENT_KEY}';
sub_filter __APPSMITH_OPTIMIZELY_KEY__ '${APPSMITH_OPTIMIZELY_KEY}';
sub_filter __APPSMITH_ALGOLIA_API_ID__ '${APPSMITH_ALGOLIA_API_ID}';
sub_filter __APPSMITH_ALGOLIA_SEARCH_INDEX_NAME__ '${APPSMITH_ALGOLIA_SEARCH_INDEX_NAME}';
sub_filter __APPSMITH_ALGOLIA_API_KEY__ '${APPSMITH_ALGOLIA_API_KEY}';
sub_filter __APPSMITH_CLIENT_LOG_LEVEL__ '${APPSMITH_CLIENT_LOG_LEVEL}';
sub_filter __APPSMITH_GOOGLE_MAPS_API_KEY__ '${APPSMITH_GOOGLE_MAPS_API_KEY}';
sub_filter __APPSMITH_TNC_PP__ '${APPSMITH_TNC_PP}';
}
location /f {
proxy_pass https://cdn.optimizely.com/;
}
location /api {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /oauth2 {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /login {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
}
server {
listen 443 ssl http2;
server_name dev.appsmith.com;
ssl_certificate /etc/certificate/dev.appsmith.com.pem;
ssl_certificate_key /etc/certificate/dev.appsmith.com-key.pem;
# include /etc/letsencrypt/options-ssl-nginx.conf;
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
gzip on;
proxy_ssl_server_name on;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Accept-Encoding "";
index index.html index.htm;
sub_filter_once off;
location / {
proxy_pass http://host.docker.internal:3000;
sub_filter __APPSMITH_SENTRY_DSN__ '${APPSMITH_SENTRY_DSN}';
sub_filter __APPSMITH_HOTJAR_HJID__ '${APPSMITH_HOTJAR_HJID}';
sub_filter __APPSMITH_HOTJAR_HJSV__ '${APPSMITH_HOTJAR_HJSV}';
sub_filter __APPSMITH_OAUTH2_GOOGLE_CLIENT_ID__ '${APPSMITH_OAUTH2_GOOGLE_CLIENT_ID}';
sub_filter __APPSMITH_OAUTH2_GITHUB_CLIENT_ID__ '${APPSMITH_OAUTH2_GITHUB_CLIENT_ID}';
sub_filter __APPSMITH_MARKETPLACE_URL__ '${APPSMITH_MARKETPLACE_URL}';
sub_filter __APPSMITH_SEGMENT_KEY__ '${APPSMITH_SEGMENT_KEY}';
sub_filter __APPSMITH_OPTIMIZELY_KEY__ '${APPSMITH_OPTIMIZELY_KEY}';
sub_filter __APPSMITH_ALGOLIA_API_ID__ '${APPSMITH_ALGOLIA_API_ID}';
sub_filter __APPSMITH_ALGOLIA_SEARCH_INDEX_NAME__ '${APPSMITH_ALGOLIA_SEARCH_INDEX_NAME}';
sub_filter __APPSMITH_ALGOLIA_API_KEY__ '${APPSMITH_ALGOLIA_API_KEY}';
sub_filter __APPSMITH_CLIENT_LOG_LEVEL__ '${APPSMITH_CLIENT_LOG_LEVEL}';
sub_filter __APPSMITH_GOOGLE_MAPS_API_KEY__ '${APPSMITH_GOOGLE_MAPS_API_KEY}';
sub_filter __APPSMITH_TNC_PP__ '${APPSMITH_TNC_PP}';
}
location /f {
proxy_pass https://cdn.optimizely.com/;
}
location /api {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /oauth2 {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
location /login {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_pass https://release-api.appsmith.com;
}
}

View File

@ -1,7 +1,18 @@
[[headers]]
for = "/static/*"
[header.values]
cache-control = "max-age=604800"
[build]
[build.environment]
# REACT_APP_SENTRY_DSN=
# REACT_APP_HOTJAR_HJID=
# REACT_APP_HOTJAR_HJSV=
# REACT_APP_OAUTH2_GOOGLE_CLIENT_ID=
# REACT_APP_OAUTH2_GITHUB_CLIENT_ID=
# REACT_APP_SEGMENT_KEY=
# REACT_APP_MARKETPLACE_URL=
# REACT_APP_OPTIMIZELY_KEY=
# REACT_APP_ALGOLIA_API_ID=
# REACT_APP_ALGOLIA_API_KEY=
# REACT_APP_ALGOLIA_SEARCH_INDEX_NAME=
REACT_APP_CLIENT_LOG_LEVEL="debug"
# REACT_APP_GOOGLE_MAPS_API_KEY=
[context.production]
[context.production.environment]
@ -15,30 +26,18 @@
REACT_APP_BASE_URL = "https://release-api.appsmith.com"
APP_HOST = "release.app.appsmith.com"
[context.develop]
[context.develop.environment]
REACT_APP_ENVIRONMENT = "DEVELOPMENT"
REACT_APP_BASE_URL = "https://release-api.appsmith.com"
APP_HOST = "develop.app.appsmith.com"
[context.a]
[context.a.environment]
REACT_APP_ENVIRONMENT = "STAGING"
REACT_APP_BASE_URL = "https://release-api.appsmith.com"
APP_HOST = "a.app.appsmith.com"
[context.b]
[context.b.environment]
REACT_APP_ENVIRONMENT = "STAGING"
REACT_APP_BASE_URL = "https://release-api.appsmith.com"
APP_HOST = "b.app.appsmith.com"
[context.deploy-preview]
[context.deploy-preview.environment]
REACT_APP_ENVIRONMENT = "STAGING"
REACT_APP_BASE_URL = "https://release-api.appsmith.com"
# Not adding an APP_HOST here because the URL is dynamic in nature and cannot be determined.
[[headers]]
for = "/static/*"
[header.values]
cache-control = "max-age=604800"
[[redirects]]
from = "/api/*"
to = "API_PLACEHOLDER/api/:splat"

View File

@ -117,11 +117,11 @@
"start": "REACT_APP_BASE_URL=https://release-api.appsmith.com REACT_APP_ENVIRONMENT=DEVELOPMENT HOST=dev.appsmith.com craco start",
"build": "./build.sh",
"build-local": "craco --max-old-space-size=4096 build --config craco.build.config.js",
"build-staging": "REACT_APP_BASE_URL=https://release-api.appsmith.com REACT_APP_ENVIRONMENT=STAGING craco --max-old-space-size=4096 build --config craco.build.config.js",
"build-staging": " REACT_APP_ENVIRONMENT=STAGING craco --max-old-space-size=4096 build --config craco.build.config.js",
"test": "CYPRESS_BASE_URL=https://dev.appsmith.com cypress/test.sh",
"test:ci": "CYPRESS_BASE_URL=https://dev.appsmith.com cypress/test.sh --env=ci",
"eject": "react-scripts eject",
"start-prod": "REACT_APP_BASE_URL=https://api.appsmith.com REACT_APP_ENVIRONMENT=PRODUCTION craco start",
"start-prod": "REACT_APP_ENVIRONMENT=PRODUCTION craco start",
"cytest": "REACT_APP_TESTING=TESTING REACT_APP_ENVIRONMENT=DEVELOPMENT craco start & ./node_modules/.bin/cypress open",
"test:unit": "$(npm bin)/jest -b --colors"
},

View File

@ -43,7 +43,37 @@
}
};
registerPageServiceWorker();
</script>
<script type="text/javascript">
const parseConfig = (config) => {
if(config.indexOf("__") === 0 || config.indexOf("$") === 0)
return "";
return config.trim();
}
const LOG_LEVELS = ["debug", "error"];
const CONFIG_LOG_LEVEL_INDEX = LOG_LEVELS.indexOf(parseConfig("__APPSMITH_CLIENT_LOG_LEVEL__"));
window.SENTRY_CONFIG = parseConfig("__APPSMITH_SENTRY_DSN__");
window.APPSMITH_FEATURE_CONFIGS = {
sentry: parseConfig("__APPSMITH_SENTRY_DSN__"),
hotjar: {
id: parseConfig("__APPSMITH_HOTJAR_HJID__"),
sv: parseConfig("__APPSMITH_HOTJAR_HJSV__"),
},
enableGoogleOAuth: parseConfig("__APPSMITH_OAUTH2_GOOGLE_CLIENT_ID__").length > 0,
enableGithubOAuth: parseConfig("__APPSMITH_OAUTH2_GITHUB_CLIENT_ID__").length > 0,
enableRapidAPI: parseConfig("__APPSMITH_MARKETPLACE_URL__").length > 0,
segment: parseConfig("__APPSMITH_SEGMENT_KEY__"),
optimizely: parseConfig("__APPSMITH_OPTIMIZELY_KEY__"),
enableMixpanel: parseConfig("__APPSMITH_SEGMENT_KEY__").length > 0,
algolia: {
apiId: parseConfig("__APPSMITH_ALGOLIA_API_ID__"),
apiKey: parseConfig("__APPSMITH_ALGOLIA_API_KEY__"),
indexName: parseConfig("__APPSMITH_ALGOLIA_SEARCH_INDEX_NAME__"),
},
logLevel: CONFIG_LOG_LEVEL_INDEX > -1 ? LOG_LEVELS[CONFIG_LOG_LEVEL_INDEX] : LOG_LEVELS[1],
google: parseConfig("__APPSMITH_GOOGLE_MAPS_API_KEY__"),
enableTNCPP: parseConfig("__APPSMITH_TNC_PP__").length > 0
};
</script>
<script rel="prefetch" type="text/javascript" src="/shims/realms-shim.umd.min.js"></script>
</body>

View File

@ -1,6 +1,5 @@
import _ from "lodash";
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
import { getAppsmithConfigs } from "configs";
import {
REQUEST_TIMEOUT_MS,
API_REQUEST_HEADERS,
@ -9,11 +8,10 @@ import { ActionApiResponse } from "./ActionAPI";
import { AUTH_LOGIN_URL } from "constants/routes";
import { setRouteBeforeLogin } from "utils/storage";
import history from "utils/history";
const { apiUrl, baseUrl } = getAppsmithConfigs();
//TODO(abhinav): Refactor this to make more composable.
export const apiRequestConfig = {
baseURL: baseUrl + apiUrl,
baseURL: "/api/",
timeout: REQUEST_TIMEOUT_MS,
headers: API_REQUEST_HEADERS,
withCredentials: true,

View File

@ -4,17 +4,12 @@ import {
InstantSearch,
Hits,
SearchBox,
// Pagination,
Highlight,
// ClearRefinements,
// RefinementList,
Configure,
PoweredBy,
} from "react-instantsearch-dom";
// import "instantsearch.css/themes/reset.css";
import "instantsearch.css/themes/algolia.css";
// import "./search.css";
import PropTypes from "prop-types";
import { Icon } from "@blueprintjs/core";
@ -27,35 +22,10 @@ import styled from "styled-components";
import { HelpIcons } from "icons/HelpIcons";
import { HelpBaseURL } from "constants/HelpConstants";
import { getDefaultRefinement } from "selectors/helpSelectors";
const searchClient = algoliasearch(
"AZ2Z9CJSJ0",
"d113611dccb80ac14aaa72a6e3ac6d10",
);
// const StyledBack = styled(Button)`
// position: absolute;
// top: 36px;
// left: 5px;
// z-index: 26;
// `;
// const StyledAnchor = styled.a`
// position: absolute;
// right: 24px;
// top: 40px;
// z-index: 26;
// `;
// const headerHeight = 91;
// const OpenIcon = styled(Icon)`
// position: absolute;
// right: 0;
// top: 3px;
// color: #888;
// `;
import { getAppsmithConfigs } from "configs";
const { algolia } = getAppsmithConfigs();
const searchClient = algoliasearch(algolia.apiId, algolia.apiKey);
console.log({ algolia });
const OenLinkIcon = HelpIcons.OPEN_LINK;
const DocumentIcon = HelpIcons.DOCUMENT;
@ -63,7 +33,6 @@ const StyledOpenLinkIcon = styled(OenLinkIcon)`
position: absolute;
right: 14px;
top: 1px;
// color: #888;
width: 12px;
height: 12px;
display: none;
@ -80,8 +49,6 @@ const StyledDocumentIcon = styled(DocumentIcon)`
position: absolute;
`;
function Hit(props: any) {
// const dispatch = useDispatch();
return (
<div
className="t--docHit"
@ -90,15 +57,6 @@ function Hit(props: any) {
(props.hit.path as string).replace("master", HelpBaseURL),
"_blank",
);
// console.log(props);
// dispatch(
// setHelpUrl(
// (props.hit.path as string).replace(
// "master",
// HelpBaseURL,
// ),
// ),
// );
}}
>
<div className="hit-name t--docHitTitle">
@ -113,11 +71,6 @@ function Hit(props: any) {
color={"#181F24"}
></StyledOpenLinkIcon>
</div>
{/* <div className="hit-description t--docHitDesc">
<Highlight attribute="description" hit={props.hit} />
<Highlight attribute="document" hit={props.hit} />
</div> */}
</div>
);
}
@ -129,8 +82,6 @@ Hit.propTypes = {
const Header = styled.div`
position: absolute;
width: 100%;
// background: #363e44;
// padding-bottom: 20px;
border-top-right-radius: 3px;
border-top-left-radius: 3px;
`;
@ -160,7 +111,6 @@ const SearchContainer = styled.div`
margin-top: 86px;
height: calc(100% - 86px);
overflow: auto;
// border: 1px solid #d0d7dd;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
}
@ -193,8 +143,6 @@ const SearchContainer = styled.div`
padding: 5px;
border: 0;
cursor: pointer;
// border-bottom: 1px solid #d0d7dd;
// box-sizing: border-box;
box-shadow: none;
}
@ -206,8 +154,6 @@ const SearchContainer = styled.div`
}
.hit-name {
// margin-bottom: 0.5em;
// font-weight: 500;
font-size: 14px;
line-height: 16px;
color: #e7e9e9;
@ -274,7 +220,8 @@ const StyledPoweredBy = styled(PoweredBy)`
export default function DocumentationSearch(props: { hitsPerPage: number }) {
const dispatch = useDispatch();
const defaultRefinement = useSelector(getDefaultRefinement);
console.log({ algolia });
if (!algolia.enabled) return null;
return (
<SearchContainer className="ais-InstantSearch t--docSearchModal">
<Icon
@ -301,7 +248,10 @@ export default function DocumentationSearch(props: { hitsPerPage: number }) {
overflow: "auto",
}}
>
<InstantSearch indexName="test_appsmith" searchClient={searchClient}>
<InstantSearch
indexName={algolia.indexName}
searchClient={searchClient}
>
<Configure hitsPerPage={props.hitsPerPage} />
<Header>
<h3
@ -316,7 +266,6 @@ export default function DocumentationSearch(props: { hitsPerPage: number }) {
style={{
textAlign: "center",
color: "white",
// zIndex: 55,
position: "relative",
fontWeight: 500,
fontSize: "14px",

View File

@ -16,7 +16,8 @@ import { theme } from "constants/DefaultTheme";
import ModalComponent from "components/designSystems/blueprint/ModalComponent";
import { LayersContext } from "constants/Layers";
import { HelpIcons } from "icons/HelpIcons";
import { getAppsmithConfigs } from "configs";
const { algolia } = getAppsmithConfigs();
const HelpButton = styled.div<{
highlight: boolean;
layer: number;
@ -35,7 +36,6 @@ const HelpButton = styled.div<{
border: 0;
cursor: pointer;
font-size: 20px;
// box-shadow: 2px 4px 5px #888888;
svg {
width: 25px;
@ -77,16 +77,18 @@ export function HelpModal() {
>
<DocumentationSearch hitsPerPage={5} />
</ModalComponent>
<HelpButton
className="t--helpGlobalButton"
highlight={!helpModalOpen}
layer={layers.help}
onClick={() => {
dispatch(setHelpModalVisibility(!helpModalOpen));
}}
>
<HelpIcon />
</HelpButton>
{algolia.enabled && (
<HelpButton
className="t--helpGlobalButton"
highlight={!helpModalOpen}
layer={layers.help}
onClick={() => {
dispatch(setHelpModalVisibility(!helpModalOpen));
}}
>
<HelpIcon />
</HelpButton>
)}
</>
);
}

View File

@ -1,20 +0,0 @@
import { AppsmithUIConfigs } from "./types";
import stageConfig from "./stage.config";
const autoConfig = (baseUrl: string): AppsmithUIConfigs => ({
...stageConfig(baseUrl),
segment: {
enabled: false,
key: "NZALSCjsaxOIyprzITLz2yZwFzQynGt1",
},
featureFlag: {
// remoteConfig: {
// optimizely: "PVDSYRhBhvUVY3tN6mkV1s",
// },
default: {
lightningmenu: false,
},
},
});
export default autoConfig;

View File

@ -1,29 +0,0 @@
import { SENTRY_STAGE_CONFIG } from "constants/ThirdPartyConstants";
import { AppsmithUIConfigs } from "./types";
const devConfig = (baseUrl: string): AppsmithUIConfigs => ({
sentry: {
enabled: false,
config: SENTRY_STAGE_CONFIG,
},
hotjar: {
enabled: false,
},
segment: {
enabled: false,
key: "NZALSCjsaxOIyprzITLz2yZwFzQynGt1",
},
featureFlag: {
remoteConfig: {
optimizely: "PVDSYRhBhvUVY3tN6mkV1s",
},
default: {
lightningmenu: true,
},
},
apiUrl: "/api/",
baseUrl,
logLevel: "debug",
});
export default devConfig;

View File

@ -1,31 +1,159 @@
import prodConfig from "./prod.config";
import stageConfig from "./stage.config";
import autoConfig from "./stage.config";
import devConfig from "./dev.config";
import { AppsmithUIConfigs } from "./types";
import { AppsmithUIConfigs, FeatureFlagConfig } from "./types";
type INJECTED_CONFIGS = {
sentry: string;
hotjar: {
id: string;
sv: string;
};
enableGoogleOAuth: boolean;
enableGithubOAuth: boolean;
enableRapidAPI: boolean;
segment: string;
optimizely: string;
enableMixpanel: boolean;
google: string;
enableTNCPP: boolean;
algolia: {
apiId: string;
apiKey: string;
indexName: string;
};
logLevel: "debug" | "error";
};
declare global {
interface Window {
BASE_URL: string;
APPSMITH_FEATURE_CONFIGS: INJECTED_CONFIGS;
}
}
// TODO(Abhinav): See if this is called so many times, that we may need memoization.
export const getAppsmithConfigs = (): AppsmithUIConfigs => {
const BASE_URL = "";
switch (process.env.REACT_APP_ENVIRONMENT) {
case "PRODUCTION":
return prodConfig(BASE_URL);
case "STAGING":
return stageConfig(BASE_URL);
case "DEVELOPMENT":
return devConfig(BASE_URL);
case "AUTOMATION":
return autoConfig(BASE_URL);
default:
console.log(
"Unknown environment set: ",
process.env.REACT_APP_ENVIRONMENT,
);
return devConfig(BASE_URL);
}
const getConfigsFromEnvVars = (): INJECTED_CONFIGS => {
return {
sentry: process.env.REACT_APP_SENTRY_DSN || "",
hotjar: {
id: process.env.REACT_APP_HOTJAR_HJID || "",
sv: process.env.REACT_APP_HOTJAR_HJSV || "",
},
enableGoogleOAuth: process.env.REACT_APP_OAUTH2_GOOGLE_CLIENT_ID
? process.env.REACT_APP_OAUTH2_GOOGLE_CLIENT_ID.length > 0
: false,
enableGithubOAuth: process.env.REACT_APP_OAUTH2_GITHUB_CLIENT_ID
? process.env.REACT_APP_OAUTH2_GITHUB_CLIENT_ID.length > 0
: false,
segment: process.env.REACT_APP_SEGMENT_KEY || "",
optimizely: process.env.REACT_APP_OPTIMIZELY_KEY || "",
enableMixpanel: process.env.REACT_APP_SEGMENT_KEY
? process.env.REACT_APP_SEGMENT_KEY.length > 0
: false,
algolia: {
apiId: process.env.REACT_APP_ALGOLIA_API_ID || "",
apiKey: process.env.REACT_APP_ALGOLIA_API_KEY || "",
indexName: process.env.REACT_APP_ALGOLIA_SEARCH_INDEX_NAME || "",
},
logLevel:
(process.env.REACT_APP_CLIENT_LOG_LEVEL as
| "debug"
| "error"
| undefined) || "debug",
google: process.env.REACT_APP_GOOGLE_MAPS_API_KEY || "",
enableTNCPP: process.env.REACT_APP_TNC_PP
? process.env.REACT_APP_TNC_PP.length > 0
: false,
enableRapidAPI: process.env.REACT_APP_MARKETPLACE_URL
? process.env.REACT_APP_MARKETPLACE_URL.length > 0
: false,
};
};
const getConfig = (fromENV: string, fromWindow: string) => {
if (fromENV.length > 0) return { enabled: true, value: fromENV };
else if (fromWindow.length > 0) return { enabled: true, value: fromWindow };
return { enabled: false, value: "" };
};
// TODO(Abhinav): See if this is called so many times, that we may need some form of memoization.
export const getAppsmithConfigs = (): AppsmithUIConfigs => {
const { APPSMITH_FEATURE_CONFIGS } = window;
const ENV_CONFIG = getConfigsFromEnvVars();
const getFeatureFlags = (
optimizelyApiKey: string,
): FeatureFlagConfig | undefined => {
if (optimizelyApiKey.length > 0) {
return {
remoteConfig: {
optimizely: optimizelyApiKey,
},
default: {},
};
}
return;
};
const sentry = getConfig(ENV_CONFIG.sentry, APPSMITH_FEATURE_CONFIGS.sentry);
const segment = getConfig(
ENV_CONFIG.segment,
APPSMITH_FEATURE_CONFIGS.segment,
);
const google = getConfig(ENV_CONFIG.google, APPSMITH_FEATURE_CONFIGS.google);
// As the following shows, the config variables can be set using a combination
// of env variables and injected configs
const hotjarId = getConfig(
ENV_CONFIG.hotjar.id,
APPSMITH_FEATURE_CONFIGS.hotjar.id,
);
const hotjarSV = getConfig(
ENV_CONFIG.hotjar.sv,
APPSMITH_FEATURE_CONFIGS.hotjar.sv,
);
const algoliaAPIID = getConfig(
ENV_CONFIG.algolia.apiId,
APPSMITH_FEATURE_CONFIGS.algolia.apiKey,
);
const algoliaAPIKey = getConfig(
ENV_CONFIG.algolia.apiKey,
APPSMITH_FEATURE_CONFIGS.algolia.apiKey,
);
const algoliaIndex = getConfig(
ENV_CONFIG.algolia.indexName,
APPSMITH_FEATURE_CONFIGS.algolia.indexName,
);
return {
sentry: { enabled: sentry.enabled, apiKey: sentry.value },
hotjar: {
enabled: hotjarId.enabled && hotjarSV.enabled,
id: hotjarId.value,
sv: hotjarSV.value, //parse as int?
},
segment: {
enabled: segment.enabled,
apiKey: segment.value,
},
algolia: {
enabled: true,
apiId: algoliaAPIID.value || "AZ2Z9CJSJ0",
apiKey: algoliaAPIKey.value || "d113611dccb80ac14aaa72a6e3ac6d10",
indexName: algoliaIndex.value || "test_appsmith",
},
google: {
enabled: google.enabled,
apiKey: google.value,
},
enableRapidAPI:
ENV_CONFIG.enableRapidAPI || APPSMITH_FEATURE_CONFIGS.enableRapidAPI,
enableGithubOAuth:
ENV_CONFIG.enableGithubOAuth ||
APPSMITH_FEATURE_CONFIGS.enableGithubOAuth,
enableGoogleOAuth:
ENV_CONFIG.enableGoogleOAuth ||
APPSMITH_FEATURE_CONFIGS.enableGoogleOAuth,
enableMixpanel:
ENV_CONFIG.enableMixpanel || APPSMITH_FEATURE_CONFIGS.enableMixpanel,
featureFlag: getFeatureFlags(
ENV_CONFIG.optimizely || APPSMITH_FEATURE_CONFIGS.optimizely,
),
logLevel: ENV_CONFIG.logLevel || APPSMITH_FEATURE_CONFIGS.logLevel,
enableTNCPP: ENV_CONFIG.enableTNCPP || APPSMITH_FEATURE_CONFIGS.enableTNCPP,
};
};

View File

@ -1,37 +0,0 @@
import {
SENTRY_PROD_CONFIG,
HOTJAR_PROD_HJID,
HOTJAR_PROD_HJSV,
} from "constants/ThirdPartyConstants";
import { AppsmithUIConfigs } from "./types";
export const prodConfig = (baseUrl: string): AppsmithUIConfigs => ({
sentry: {
enabled: true,
config: SENTRY_PROD_CONFIG,
},
hotjar: {
enabled: true,
config: {
id: HOTJAR_PROD_HJID,
sv: HOTJAR_PROD_HJSV,
},
},
segment: {
enabled: true,
key: "O7rsLdWq7fhJI9rYsj1eatGAjuULTmfP",
},
apiUrl: "/api/",
baseUrl,
logLevel: "error",
featureFlag: {
remoteConfig: {
optimizely: "Jq3K2kVdvuvxecHyHbVYcj",
},
default: {
lightningmenu: false,
},
},
});
export default prodConfig;

View File

@ -1,29 +0,0 @@
import { SENTRY_STAGE_CONFIG } from "constants/ThirdPartyConstants";
import { AppsmithUIConfigs } from "./types";
const stageConfig = (baseUrl: string): AppsmithUIConfigs => ({
sentry: {
enabled: true,
config: SENTRY_STAGE_CONFIG,
},
hotjar: {
enabled: false,
},
segment: {
enabled: true,
key: "NZALSCjsaxOIyprzITLz2yZwFzQynGt1",
},
featureFlag: {
remoteConfig: {
optimizely: "2qP3XSwgM9pHYTEYbtbAQx",
},
default: {
lightningmenu: true,
},
},
apiUrl: "/api/",
baseUrl,
logLevel: "info",
});
export default stageConfig;

View File

@ -12,9 +12,7 @@ export type HotjarConfig = {
type Milliseconds = number;
export enum FeatureFlagsEnum {
LightningMenu = "lightningmenu",
}
export enum FeatureFlagsEnum {}
export type FeatureFlags = Record<FeatureFlagsEnum, boolean>;
@ -28,18 +26,35 @@ export type FeatureFlagConfig = {
export type AppsmithUIConfigs = {
sentry: {
enabled: boolean;
config?: SentryConfig;
apiKey: string;
};
hotjar: {
enabled: boolean;
config?: HotjarConfig;
id: string;
sv: string;
};
featureFlag: FeatureFlagConfig;
segment: {
enabled: boolean;
key: string;
apiKey: string;
};
apiUrl: string;
baseUrl: string;
algolia: {
enabled: boolean;
apiId: string;
apiKey: string;
indexName: string;
};
google: {
enabled: boolean;
apiKey: string;
};
enableRapidAPI: boolean;
enableGoogleOAuth: boolean;
enableGithubOAuth: boolean;
enableMixpanel: boolean;
enableTNCPP: boolean;
featureFlag?: FeatureFlagConfig;
logLevel: LogLevelDesc;
};

View File

@ -1,8 +1,6 @@
import { GoogleOAuthURL, GithubOAuthURL } from "constants/ApiConstants";
import GithubLogo from "assets/images/Github.png";
import GoogleLogo from "assets/images/Google.png";
import { getAppsmithConfigs } from "configs";
const { baseUrl } = getAppsmithConfigs();
export type SocialLoginButtonProps = {
url: string;
name: string;
@ -10,13 +8,13 @@ export type SocialLoginButtonProps = {
};
export const GoogleSocialLoginButtonProps: SocialLoginButtonProps = {
url: baseUrl + GoogleOAuthURL,
url: GoogleOAuthURL,
name: "Google",
logo: GoogleLogo,
};
export const GithubSocialLoginButtonProps: SocialLoginButtonProps = {
url: baseUrl + GithubOAuthURL,
url: GithubOAuthURL,
name: "Github",
logo: GithubLogo,
};

View File

@ -1,14 +1 @@
export type ENVIRONMENT = "PRODUCTION" | "STAGING" | "LOCAL";
export const SENTRY_PROD_CONFIG = {
dsn: "https://a63362b692d64edeb175741f1f80b091@sentry.io/1546547",
environment: "Production",
release: process.env.REACT_APP_SENTRY_RELEASE,
};
export const SENTRY_STAGE_CONFIG = {
dsn: "https://26e99889a7f14b418a66cb2deafeb40c@sentry.io/4113637",
environment: "Staging",
release: process.env.REACT_APP_SENTRY_RELEASE,
};
export const HOTJAR_PROD_HJID = "1465835";
export const HOTJAR_PROD_HJSV = "6";

View File

@ -49,6 +49,8 @@ import {
import { getInitialsAndColorCode } from "utils/AppsmithUtils";
import AnalyticsUtil from "utils/AnalyticsUtil";
import { CURL } from "constants/ApiConstants";
import { getAppsmithConfigs } from "configs";
const { enableRapidAPI } = getAppsmithConfigs();
const SearchContainer = styled.div`
display: flex;
@ -403,13 +405,13 @@ class ApiHomeScreen extends React.Component<Props, ApiHomeScreenState> {
providersTotal,
providerCategories,
} = this.props;
if (providerCategories.length === 0) {
if (providerCategories.length === 0 && enableRapidAPI) {
this.props.fetchProviderCategories();
}
if (importedCollections.length === 0) {
if (importedCollections.length === 0 && enableRapidAPI) {
this.props.fetchImportedCollections();
}
if (!providersTotal) {
if (!providersTotal && enableRapidAPI) {
this.props.clearProviders();
this.props.change("category", DEFAULT_PROVIDER_OPTION);
this.props.fetchProvidersWithCategory({
@ -423,7 +425,8 @@ class ApiHomeScreen extends React.Component<Props, ApiHomeScreenState> {
componentDidUpdate(prevProps: Props) {
if (
prevProps.currentCategory !== this.props.currentCategory &&
this.props.currentCategory !== this.props.previouslySetCategory
this.props.currentCategory !== this.props.previouslySetCategory &&
enableRapidAPI
) {
this.props.setCurrentCategory(this.props.currentCategory);
this.props.clearProviders();
@ -498,96 +501,99 @@ class ApiHomeScreen extends React.Component<Props, ApiHomeScreenState> {
const ApiHomepageTopSection = (
<React.Fragment>
<SearchContainer>
<SearchBar
icon="search"
input={{
onChange: this.handleSearchChange,
onFocus: e => {
if (e.target.value) {
this.setState({ showSearchResults: true });
} else {
this.setState({ showSearchResults: false });
}
},
}}
placeholder="Search"
/>
</SearchContainer>
<div>
{showSearchResults && (
<div className="searchResultsContainer">
<Icon
icon="cross"
iconSize={20}
className="searchCloseBtn"
onClick={() => {
this.setState({ showSearchResults: false });
}}
/>
<StyledContainer>
<div>
<p className="sectionHeadings">{"Providers"}</p>
{apiOrProviderSearchResults.providers.map(
providerSearchResult => (
<React.Fragment key={providerSearchResult.id}>
<p
className="providerSearchCard"
onClick={() =>
history.push(
getProviderTemplatesURL(
applicationId,
pageId,
providerSearchResult.id +
`/?importTo=${destinationPageId}`,
),
)
}
>
{providerSearchResult.imageUrl ? (
<img
src={providerSearchResult.imageUrl}
className="providerSearchResultImage"
alt="img"
/>
) : (
<div
style={{
backgroundColor: getInitialsAndColorCode(
providerSearchResult.name,
)[1],
padding: 11,
width: 60,
color: "#fff",
borderRadius: 2,
fontSize: 16,
fontWeight: "bold",
textAlign: "center",
}}
>
<span>
{
getInitialsAndColorCode(
{enableRapidAPI && (
<SearchContainer>
<SearchBar
icon="search"
input={{
onChange: this.handleSearchChange,
onFocus: e => {
if (e.target.value) {
this.setState({ showSearchResults: true });
} else {
this.setState({ showSearchResults: false });
}
},
}}
placeholder="Search"
/>
</SearchContainer>
)}
{enableRapidAPI && (
<div>
{showSearchResults && (
<div className="searchResultsContainer">
<Icon
icon="cross"
iconSize={20}
className="searchCloseBtn"
onClick={() => {
this.setState({ showSearchResults: false });
}}
/>
<StyledContainer>
<div>
<p className="sectionHeadings">{"Providers"}</p>
{apiOrProviderSearchResults.providers.map(
providerSearchResult => (
<React.Fragment key={providerSearchResult.id}>
<p
className="providerSearchCard"
onClick={() =>
history.push(
getProviderTemplatesURL(
applicationId,
pageId,
providerSearchResult.id +
`/?importTo=${destinationPageId}`,
),
)
}
>
{providerSearchResult.imageUrl ? (
<img
src={providerSearchResult.imageUrl}
className="providerSearchResultImage"
alt="img"
/>
) : (
<div
style={{
backgroundColor: getInitialsAndColorCode(
providerSearchResult.name,
)[0]
}
</span>
</div>
)}
<span className="providerSearchResultName">
{providerSearchResult.name}
{/* |{" "} {providerSearchResult.noOfApis} APIs */}
</span>
</p>
</React.Fragment>
),
)}
</div>
</StyledContainer>
</div>
)}
</div>
)[1],
padding: 11,
width: 60,
color: "#fff",
borderRadius: 2,
fontSize: 16,
fontWeight: "bold",
textAlign: "center",
}}
>
<span>
{
getInitialsAndColorCode(
providerSearchResult.name,
)[0]
}
</span>
</div>
)}
<span className="providerSearchResultName">
{providerSearchResult.name}
{/* |{" "} {providerSearchResult.noOfApis} APIs */}
</span>
</p>
</React.Fragment>
),
)}
</div>
</StyledContainer>
</div>
)}
</div>
)}
<StyledContainer>
<p className="sectionHeadings">{"Import API"}</p>
<ApiCard>
@ -624,7 +630,6 @@ class ApiHomeScreen extends React.Component<Props, ApiHomeScreenState> {
</Link>
</ApiCard>
</StyledContainer>
{/* Imported APIs section start */}
{/* <StyledContainer>
<p className="sectionHeadings">{"Imported APIs"}</p>
@ -664,12 +669,14 @@ class ApiHomeScreen extends React.Component<Props, ApiHomeScreenState> {
style={{ overflow: showSearchResults ? "hidden" : "auto" }}
className="t--apiHomePage"
>
{isSwitchingCategory ? (
{isSwitchingCategory || !enableRapidAPI ? (
<>
{ApiHomepageTopSection}
<PageLoadingContainer>
<Spinner size={30} />
</PageLoadingContainer>
{enableRapidAPI && isSwitchingCategory && (
<PageLoadingContainer>
<Spinner size={30} />
</PageLoadingContainer>
)}
</>
) : (
<>

View File

@ -44,9 +44,8 @@ import {
CREATE_PASSWORD_INVALID_TOKEN,
CREATE_PASSWORD_RESET_SUCCESS,
CREATE_PASSWORD_RESET_SUCCESS_LOGIN_LINK,
PRIVACY_POLICY_LINK,
TERMS_AND_CONDITIONS_LINK,
} from "constants/messages";
import { TncPPLinks } from "./SignUp";
const validate = (values: CreatePasswordFormValues) => {
const errors: CreatePasswordFormValues = {};
@ -176,8 +175,7 @@ export const CreatePassword = (props: CreatePasswordProps) => {
{CREATE_PASSWORD_LOGIN_LINK_TEXT}
</AuthCardNavLink>
<AuthCardFooter>
<Link to="#">{PRIVACY_POLICY_LINK}</Link>
<Link to="#">{TERMS_AND_CONDITIONS_LINK}</Link>
<TncPPLinks></TncPPLinks>
</AuthCardFooter>
</AuthCardContainer>
);

View File

@ -7,7 +7,6 @@ import {
LOGIN_FORM_EMAIL_FIELD_NAME,
LOGIN_FORM_PASSWORD_FIELD_NAME,
} from "constants/forms";
import { getAppsmithConfigs } from "configs";
import { FORGOT_PASSWORD_URL, SIGN_UP_URL } from "constants/routes";
import { LOGIN_SUBMIT_PATH } from "constants/ApiConstants";
import {
@ -25,8 +24,6 @@ import {
LOGIN_PAGE_FORGOT_PASSWORD_TEXT,
LOGIN_PAGE_SIGN_UP_LINK_TEXT,
LOGIN_PAGE_INVALID_CREDS_ERROR,
PRIVACY_POLICY_LINK,
TERMS_AND_CONDITIONS_LINK,
LOGIN_PAGE_INVALID_CREDS_FORGOT_PASSWORD_LINK,
FORM_VALIDATION_PASSWORD_RULE,
} from "constants/messages";
@ -49,6 +46,9 @@ import {
AuthCardBody,
} from "./StyledComponents";
import AnalyticsUtil from "utils/AnalyticsUtil";
import { getAppsmithConfigs } from "configs";
import { TncPPLinks } from "./SignUp";
const { enableGithubOAuth, enableGoogleOAuth } = getAppsmithConfigs();
const validate = (values: LoginFormValues) => {
const errors: LoginFormValues = {};
@ -73,6 +73,10 @@ type LoginFormProps = { emailValue: string } & InjectedFormProps<
{ emailValue: string }
>;
const SocialLoginList: string[] = [];
if (enableGithubOAuth) SocialLoginList.push(SocialLoginTypes.GITHUB);
if (enableGoogleOAuth) SocialLoginList.push(SocialLoginTypes.GOOGLE);
export const Login = (props: LoginFormProps) => {
const { error, valid } = props;
const location = useLocation();
@ -88,8 +92,6 @@ export const Login = (props: LoginFormProps) => {
forgotPasswordURL += `?email=${props.emailValue}`;
}
const { baseUrl, apiUrl } = getAppsmithConfigs();
return (
<AuthCardContainer>
{showError && (
@ -110,10 +112,7 @@ export const Login = (props: LoginFormProps) => {
<h5>{LOGIN_PAGE_SUBTITLE}</h5>
</AuthCardHeader>
<AuthCardBody>
<SpacedSubmitForm
method="POST"
action={baseUrl + apiUrl + "v1/" + LOGIN_SUBMIT_PATH}
>
<SpacedSubmitForm method="POST" action={"/api/v1/" + LOGIN_SUBMIT_PATH}>
<FormGroup
intent={error ? "danger" : "none"}
label={LOGIN_PAGE_EMAIL_INPUT_LABEL}
@ -152,18 +151,14 @@ export const Login = (props: LoginFormProps) => {
/>
</FormActions>
</SpacedSubmitForm>
<Divider />
<ThirdPartyAuth
type={"SIGNIN"}
logins={[SocialLoginTypes.GOOGLE, SocialLoginTypes.GITHUB]}
/>
{SocialLoginList.length > 0 && <Divider />}
<ThirdPartyAuth type={"SIGNIN"} logins={SocialLoginList} />
</AuthCardBody>
<AuthCardNavLink to={SIGN_UP_URL}>
{LOGIN_PAGE_SIGN_UP_LINK_TEXT}
</AuthCardNavLink>
<AuthCardFooter>
<Link to="#">{PRIVACY_POLICY_LINK}</Link>
<Link to="#">{TERMS_AND_CONDITIONS_LINK}</Link>
<TncPPLinks></TncPPLinks>
</AuthCardFooter>
</AuthCardContainer>
);

View File

@ -17,7 +17,6 @@ import Button from "components/editorComponents/Button";
import FormGroup from "components/editorComponents/form/FormGroup";
import StyledForm from "components/editorComponents/Form";
import { isEmptyString, isStrongPassword } from "utils/formhelpers";
import { ResetPasswordFormValues, resetPasswordSubmitHandler } from "./helpers";
import {
AuthCardHeader,
@ -43,9 +42,8 @@ import {
RESET_PASSWORD_INVALID_TOKEN,
RESET_PASSWORD_RESET_SUCCESS,
RESET_PASSWORD_RESET_SUCCESS_LOGIN_LINK,
PRIVACY_POLICY_LINK,
TERMS_AND_CONDITIONS_LINK,
} from "constants/messages";
import { TncPPLinks } from "./SignUp";
const validate = (values: ResetPasswordFormValues) => {
const errors: ResetPasswordFormValues = {};
@ -183,8 +181,7 @@ export const ResetPassword = (props: ResetPasswordProps) => {
<Icon icon="arrow-right" intent="primary" />
</AuthCardNavLink>
<AuthCardFooter>
<Link to="#">{PRIVACY_POLICY_LINK}</Link>
<Link to="#">{TERMS_AND_CONDITIONS_LINK}</Link>
<TncPPLinks></TncPPLinks>
</AuthCardFooter>
</AuthCardContainer>
);

View File

@ -43,6 +43,30 @@ import { isEmail, isStrongPassword, isEmptyString } from "utils/formhelpers";
import { signupFormSubmitHandler, SignupFormValues } from "./helpers";
import AnalyticsUtil from "utils/AnalyticsUtil";
import { getAppsmithConfigs } from "configs";
const {
enableGithubOAuth,
enableGoogleOAuth,
enableTNCPP,
} = getAppsmithConfigs();
const SocialLoginList: string[] = [];
if (enableGithubOAuth) SocialLoginList.push(SocialLoginTypes.GITHUB);
if (enableGoogleOAuth) SocialLoginList.push(SocialLoginTypes.GOOGLE);
export const TncPPLinks = () => {
if (!enableTNCPP) return null;
return (
<>
<Link target="_blank" to="/privacy-policy.html">
{PRIVACY_POLICY_LINK}
</Link>
<Link target="_blank" to="/terms-and-conditions.html">
{TERMS_AND_CONDITIONS_LINK}
</Link>
</>
);
};
const validate = (values: SignupFormValues) => {
const errors: SignupFormValues = {};
if (!values.password || isEmptyString(values.password)) {
@ -128,20 +152,15 @@ export const SignUp = (props: InjectedFormProps<SignupFormValues>) => {
/>
</FormActions>
</SpacedForm>
<Divider />
<ThirdPartyAuth
logins={[SocialLoginTypes.GOOGLE, SocialLoginTypes.GITHUB]}
type={"SIGNUP"}
/>
{SocialLoginList.length > 0 && <Divider />}
<ThirdPartyAuth type={"SIGNUP"} logins={SocialLoginList} />
</AuthCardBody>
<AuthCardFooter>
<TncPPLinks></TncPPLinks>
</AuthCardFooter>
<AuthCardNavLink to={AUTH_LOGIN_URL}>
{SIGNUP_PAGE_LOGIN_LINK_TEXT}
</AuthCardNavLink>
<AuthCardFooter>
<Link to="#">{PRIVACY_POLICY_LINK}</Link>
<Link to="#">{TERMS_AND_CONDITIONS_LINK}</Link>
</AuthCardFooter>
</AuthCardContainer>
);
};

View File

@ -30,19 +30,18 @@ export const appInitializer = () => {
const appsmithConfigs = getAppsmithConfigs();
FeatureFlag.initialize(appsmithConfigs.featureFlag);
if (appsmithConfigs.sentry.enabled && appsmithConfigs.sentry.config) {
Sentry.init(appsmithConfigs.sentry.config);
if (appsmithConfigs.sentry.enabled) {
Sentry.init({ dsn: appsmithConfigs.sentry.apiKey });
}
if (appsmithConfigs.hotjar.enabled && appsmithConfigs.hotjar.config) {
const { id, sv } = appsmithConfigs.hotjar.config;
if (appsmithConfigs.hotjar.enabled) {
const { id, sv } = appsmithConfigs.hotjar;
AnalyticsUtil.initializeHotjar(id, sv);
}
if (appsmithConfigs.segment.enabled) {
AnalyticsUtil.initializeSegment(appsmithConfigs.segment.key);
AnalyticsUtil.initializeSegment(appsmithConfigs.segment.apiKey);
}
log.setLevel(getEnvLogLevel(appsmithConfigs.logLevel));
// setConfigFeatureFlags(appsmithConfigs.featureFlags);
const textFont = new FontFaceObserver("DM Sans");
textFont

View File

@ -4,29 +4,31 @@ const optimizelySDK = require("@optimizely/optimizely-sdk");
class FeatureFlag {
static isInitialized = false;
static remote = undefined;
static initialize(featureFlagConfig: FeatureFlagConfig) {
Object.keys(featureFlagConfig.default).forEach((flag: any) => {
// This is required because otherwise it will reset the values
// every time the application is loaded. We need the application to load
// remote values the second time.
if (localStorage.getItem(flag) === null) {
localStorage.setItem(
flag,
featureFlagConfig.default[flag as FeatureFlagsEnum].toString(),
);
}
});
if (featureFlagConfig.remoteConfig) {
FeatureFlag.remote = optimizelySDK.createInstance({
sdkKey: featureFlagConfig.remoteConfig.optimizely,
datafileOptions: {
autoUpdate: true,
updateInterval: 600000, // 10 minutes in milliseconds
urlTemplate: window.location.origin + "/f/datafiles/%s.json",
},
static initialize(featureFlagConfig?: FeatureFlagConfig) {
if (featureFlagConfig) {
Object.keys(featureFlagConfig.default).forEach((flag: any) => {
// This is required because otherwise it will reset the values
// every time the application is loaded. We need the application to load
// remote values the second time.
if (localStorage.getItem(flag) === null) {
localStorage.setItem(
flag,
featureFlagConfig.default[flag as FeatureFlagsEnum].toString(),
);
}
});
(FeatureFlag.remote as any).onReady().then(onInit);
if (featureFlagConfig.remoteConfig) {
FeatureFlag.remote = optimizelySDK.createInstance({
sdkKey: featureFlagConfig.remoteConfig.optimizely,
datafileOptions: {
autoUpdate: true,
updateInterval: 600000, // 10 minutes in milliseconds
urlTemplate: window.location.origin + "/f/datafiles/%s.json",
},
});
(FeatureFlag.remote as any).onReady().then(onInit);
}
}
}

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import { useState } from "react";
export function useLocalStorage(key: string, initialValue: string) {
// State to store our value

View File

@ -1,7 +1,6 @@
import React, { lazy, Suspense } from "react";
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
// import ChartComponent from "components/designSystems/appsmith/ChartComponent";
import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
import Skeleton from "components/utils/Skeleton";

View File

@ -6,7 +6,26 @@ import { WidgetPropertyValidationType } from "utils/ValidationFactory";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
import { EventType } from "constants/ActionConstants";
import { TriggerPropertiesMap } from "utils/WidgetFactory";
import { getAppsmithConfigs } from "configs";
import styled from "styled-components";
const { google } = getAppsmithConfigs();
const DisabledContainer = styled.div`
background-color: white;
height: 100%;
text-align: center;
display: flex;
flex-direction: column;
h1 {
margin-top: 15%;
margin-bottom: 10%;
color: #7c7c7c;
}
p {
color: #0a0b0e;
}
`;
class MapWidget extends BaseWidget<MapWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
@ -116,26 +135,46 @@ class MapWidget extends BaseWidget<MapWidgetProps, WidgetState> {
getPageView() {
return (
<MapComponent
widgetId={this.props.widgetId}
isVisible={this.props.isVisible}
zoomLevel={this.props.zoomLevel}
allowZoom={this.props.allowZoom}
center={this.props.center || this.props.mapCenter}
enableCreateMarker
selectedMarker={this.props.selectedMarker}
updateCenter={this.updateCenter}
isDisabled={this.props.isDisabled}
enableSearch={this.props.enableSearch}
enablePickLocation={this.props.enablePickLocation}
saveMarker={this.onCreateMarker}
updateMarker={this.updateMarker}
selectMarker={this.onMarkerClick}
markers={this.props.markers || []}
disableDrag={() => {
this.disableDrag(false);
}}
/>
<>
{!google.enabled && (
<DisabledContainer>
<h1>{"Map Widget disabled"}</h1>
<p>
{"Map widget requires a Google Maps "}
<a
target="_blank"
rel="noopener noreferrer"
href="https://developers.google.com/maps/documentation/javascript/get-api-key"
>
API Key
</a>
</p>
<p>{"Refer our Docs to configure API Keys"}</p>
</DisabledContainer>
)}
{google.enabled && (
<MapComponent
widgetId={this.props.widgetId}
isVisible={this.props.isVisible}
zoomLevel={this.props.zoomLevel}
allowZoom={this.props.allowZoom}
center={this.props.center || this.props.mapCenter}
enableCreateMarker
selectedMarker={this.props.selectedMarker}
updateCenter={this.updateCenter}
isDisabled={this.props.isDisabled}
enableSearch={this.props.enableSearch}
enablePickLocation={this.props.enablePickLocation}
saveMarker={this.onCreateMarker}
updateMarker={this.updateMarker}
selectMarker={this.onMarkerClick}
markers={this.props.markers || []}
disableDrag={() => {
this.disableDrag(false);
}}
/>
)}
</>
);
}

View File

@ -11,6 +11,12 @@ if ! docker_loc="$(type -p "docker")" || [[ -z $docker_loc ]]; then
exit
fi
if ! envsubst_loc="$(type -p "envsubst")" || [[ -z $envsubst_loc ]]; then
echo "Could not find envsubst: If you're on a mac; brew install gettext"
exit
fi
KEY_FILE=./docker/_wildcard.appsmith.com-key.pem
CERT_FILE=./docker/_wildcard.appsmith.com.pem
if ! test -f "$KEY_FILE" || ! test -f "$CERT_FILE"; then
@ -26,13 +32,26 @@ if ! test -f "$KEY_FILE" || ! test -f "$CERT_FILE"; then
exit
fi
ENV_FILE=../../.env
if ! test -f "$ENV_FILE"; then
echo "
Please populate the .env at the root of the project and run again
Or add the environment variables defined in .env.example to the environment
-- to enable features
"
else
export $(grep -v '^[[:space:]]*#' ${ENV_FILE} | xargs)
fi
unameOut="$(uname -s)"
vars_to_substitute="$(printf '\$%s,' $(grep -o "^APPSMITH_[A-Z0-9_]\+" ../../.env | xargs))"
case "${unameOut}" in
Linux*) machine=Linux
echo "
Starting nginx for Linux...
"
sudo docker run --network host --name wildcard-nginx -d -p 80:80 -p 443:443 -v `pwd`/docker/nginx-linux.conf:/etc/nginx/conf.d/app.conf -v `pwd`/docker/_wildcard.appsmith.com.pem:/etc/certificate/dev.appsmith.com.pem -v `pwd`/docker/_wildcard.appsmith.com-key.pem:/etc/certificate/dev.appsmith.com-key.pem nginx:latest \
cat ./docker/templates/nginx-linux.conf.template | envsubst ${vars_to_substitute} | sed -e 's|\${\(APPSMITH_[A-Z0-9_]*\)}||g' > ./docker/nginx.conf &&
sudo docker run --network host --name wildcard-nginx -d -p 80:80 -p 443:443 -v `pwd`/docker/nginx.conf:/etc/nginx/conf.d/app.conf -v `pwd`/docker/_wildcard.appsmith.com.pem:/etc/certificate/dev.appsmith.com.pem -v `pwd`/docker/_wildcard.appsmith.com-key.pem:/etc/certificate/dev.appsmith.com-key.pem nginx:latest \
&& echo "
nginx is listening on port 443 and forwarding to port 3000
visit https://dev.appsmith.com
@ -42,7 +61,8 @@ case "${unameOut}" in
echo "
Starting nginx for MacOS...
"
docker run --name wildcard-nginx -d -p 80:80 -p 443:443 -v `pwd`/docker/nginx-mac.conf:/etc/nginx/conf.d/app.conf -v `pwd`/docker/_wildcard.appsmith.com.pem:/etc/certificate/dev.appsmith.com.pem -v `pwd`/docker/_wildcard.appsmith.com-key.pem:/etc/certificate/dev.appsmith.com-key.pem nginx:latest \
cat ./docker/templates/nginx-mac.conf.template | envsubst ${vars_to_substitute} | sed -e 's|\${\(APPSMITH_[A-Z0-9_]*\)}||g' > ./docker/nginx.conf &&
docker run --name wildcard-nginx -d -p 80:80 -p 443:443 -v `pwd`/docker/nginx.conf:/etc/nginx/conf.d/app.conf -v `pwd`/docker/_wildcard.appsmith.com.pem:/etc/certificate/dev.appsmith.com.pem -v `pwd`/docker/_wildcard.appsmith.com-key.pem:/etc/certificate/dev.appsmith.com-key.pem nginx:latest \
&& echo "
nginx is listening on port 443 and forwarding to port 3000
visit https://dev.appsmith.com