diff --git a/app/controllers/apps_controller.rb b/app/controllers/apps_controller.rb index 328196ff28..53316db7c6 100644 --- a/app/controllers/apps_controller.rb +++ b/app/controllers/apps_controller.rb @@ -49,6 +49,12 @@ class AppsController < ApplicationController end end + def destroy + app = App.find params[:id] + app.update(current_version: nil) + app.destroy + end + def slugs @app = App.find_by(slug: params[:slug]) diff --git a/app/controllers/organization_users_controller.rb b/app/controllers/organization_users_controller.rb index ba81ece6c5..4b50277a2e 100644 --- a/app/controllers/organization_users_controller.rb +++ b/app/controllers/organization_users_controller.rb @@ -14,23 +14,27 @@ class OrganizationUsersController < ApplicationController password = SecureRandom.uuid org = @current_user.organization - user = User.create( - first_name: first_name, - last_name: last_name, - email: email, - password: password, - password_confirmation: password, - organization: org, - invitation_token: SecureRandom.uuid - ) + if User.find_by(email: email).present? + render json: { message: "Email address is already taken" }, status: :unprocessable_entity + else + user = User.create( + first_name: first_name, + last_name: last_name, + email: email, + password: password, + password_confirmation: password, + organization: org, + invitation_token: SecureRandom.uuid + ) - org_user = OrganizationUser.new( - role: role, - user: user, - organization: org - ) + org_user = OrganizationUser.new( + role: role, + user: user, + organization: org + ) - UserMailer.with(user: user, sender: @current_user).invitation_email.deliver if org_user.save + UserMailer.with(user: user, sender: @current_user).invitation_email.deliver if org_user.save + end end def change_role diff --git a/app/models/app.rb b/app/models/app.rb index 2de962af53..9ed37e4118 100644 --- a/app/models/app.rb +++ b/app/models/app.rb @@ -3,8 +3,10 @@ class App < ApplicationRecord belongs_to :organization has_many :data_queries, dependent: :destroy + has_many :data_sources, dependent: :destroy has_many :app_users, dependent: :destroy has_many :app_versions, dependent: :destroy + has_many :folder_apps, dependent: :destroy belongs_to :current_version, class_name: "AppVersion", optional: true belongs_to :user, optional: true diff --git a/app/services/elasticsearch_query_service.rb b/app/services/elasticsearch_query_service.rb index e6ce06b701..40c39e0814 100644 --- a/app/services/elasticsearch_query_service.rb +++ b/app/services/elasticsearch_query_service.rb @@ -48,7 +48,7 @@ class ElasticsearchQueryService if operation == 'search' index = options['index'] - query = JSON.parse(options[:query]) + query = JSON.parse(options['query']) data = connection.search(index: index, body: query) end diff --git a/app/services/googlesheets_query_service.rb b/app/services/googlesheets_query_service.rb index 2b21234ee0..342802ef3c 100644 --- a/app/services/googlesheets_query_service.rb +++ b/app/services/googlesheets_query_service.rb @@ -41,6 +41,23 @@ class GooglesheetsQueryService end error = result.code != 200 + data = result + end + + if operation === 'delete_row' + spreadsheet_id = options['spreadsheet_id'] + sheet = options['sheet'] + row_index = options['row_index'].to_i + + result = delete_row_from_sheet(spreadsheet_id, sheet, row_index, access_token) + + if result.code === 401 + access_token = refresh_access_token + result = delete_row_from_sheet(spreadsheet_id, sheet, row_index, access_token) + end + + data = result + error = result.code != 200 end if operation === 'read' @@ -123,6 +140,30 @@ class GooglesheetsQueryService 'application/json', "Authorization": "Bearer #{access_token}" }) end + def delete_row_from_sheet(spreadsheet_id, sheet, row_index, access_token) + data = { + "requests": [ + { + "deleteDimension": { + "range": { + "sheetId": sheet, + "dimension": "ROWS", + "startIndex": row_index - 1, + "endIndex": row_index + } + } + } + ] + }.to_json + + result = HTTParty.post( + "https://sheets.googleapis.com/v4/spreadsheets/#{spreadsheet_id}:batchUpdate", + body: data, + headers: { "Content-Type": 'application/json', + "Authorization": "Bearer #{access_token}" } + ) + end + def get_spreadsheet_info(spreadsheet_id, access_token) result = HTTParty.get("https://sheets.googleapis.com/v4/spreadsheets/#{spreadsheet_id}", diff --git a/config/application.rb b/config/application.rb index cb784188b9..621ad3193f 100644 --- a/config/application.rb +++ b/config/application.rb @@ -19,7 +19,7 @@ require 'rails/test_unit/railtie' # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) -TOOLJET_VERSION = '0.5.11' +TOOLJET_VERSION = '0.5.12' module ToolJet class Application < Rails::Application diff --git a/config/routes.rb b/config/routes.rb index 99463cfc57..89ae0988a3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,5 @@ Rails.application.routes.draw do - resources :apps, only: %i[index create show update] do + resources :apps, only: %i[index create show update destroy] do resources :versions, only: %i[index create update] get '/users', to: 'apps#users' diff --git a/cypress/integration/auth.spec.js b/cypress/integration/auth.spec.js index 7ba3103c65..0c26bfa092 100644 --- a/cypress/integration/auth.spec.js +++ b/cypress/integration/auth.spec.js @@ -12,14 +12,14 @@ describe('User login', () => { it('should display invalid email or password error', () => { cy.login('fake_email', 'abcdefg'); - cy.checkToastMessage('toast-login-auth-error', 'Invalid email or password') + cy.checkToastMessage('toast-login-auth-error', 'Invalid email or password'); }); it('should take user to the forgot password page', () => { cy.visit('/forgot-password'); cy.get('.card-title') .should('have.text', 'Forgot Password'); - }) + }); it('should take user to the signup page', () => { cy.visit('/signup'); @@ -34,4 +34,22 @@ describe('User login', () => { cy.get('.page-title') .should('have.text', 'All applications'); }) + + it('should display error if email is not found for "Forgot password"', () => { + cy.visit('/forgot-password'); + cy.get('[data-testid="emailField"]').type('abc@def.com'); + cy.get('[data-testid="submitButton"').click(); + cy.checkToastMessage('toast-forgot-password-email-error', 'Email address is not associated with a ToolJet cloud account.'); + }); + + it('should send reset password confirmation code to email', () => { + cy.intercept('POST', '/password/forgot').as('forgotPasswordConfirmationCode'); + + cy.visit('/forgot-password'); + cy.get('[data-testid="emailField"]').type('dev@tooljet.io'); + cy.get('[data-testid="submitButton"').click(); + + cy.wait('@forgotPasswordConfirmationCode').its('response.statusCode').should('eq', 200); + cy.checkToastMessage('toast-forgot-password-confirmation-code', 'We\'ve sent the confirmation code to your email address'); + }); }) \ No newline at end of file diff --git a/cypress/integration/dashboard.spec.js b/cypress/integration/dashboard.spec.js new file mode 100644 index 0000000000..75797cd4fd --- /dev/null +++ b/cypress/integration/dashboard.spec.js @@ -0,0 +1,57 @@ +describe('Dashboard', () => { + // we can use these values to log in + const email = 'dev@tooljet.io'; + const password = 'password'; + + beforeEach(() => { + cy.login(email, password); + }) + + it('site header is visible with nav items', () => { + cy.get('.navbar') + .find('.navbar-nav') + .should('be.visible'); + }); + + it('Users tab should navigate to Users page', () => { + cy.get('.navbar') + .find('.navbar-nav') + .find('li').not('.active') + .click(); + cy.location('pathname').should('equal', '/users'); + cy.get('.page-title').should('have.text', 'Users & Permissions'); + cy.get('[data-testid="usersTable"]').should('be.visible'); + }) + + it('Apps tab should navigate to Apps page', () => { + cy.get('.navbar') + .find('.navbar-nav') + .find('li.active') + .click(); + cy.location('pathname').should('equal', '/'); + cy.get('.page-title').should('have.text', 'All applications'); + cy.get('[data-testid="appsTable"]').should('be.visible'); + }) + + it('should show User avatar and logout the user when user clicks logout', () => { + cy.get('[data-testid="userAvatarHeader"]').should('be.visible'); + // TODO - Add functionality to detect when user hovers over the avatar, + // Issues with hover functionality and hide/show of dom elements + }) + + it('Application folders list is visible', () => { + cy.get('[data-testid="applicationFoldersList"]') + .should('be.visible'); + }); + + it('Count bubble for "All applications should equal number of rows in table', () => { + cy.get('[data-testid="allApplicationsCount"]').then(($countBubble) => { + cy.get('[data-testid="appsTable"]') + .wait(500) + .find("tr") + .then((row) => { + expect(Number($countBubble.text())).to.equal(row.length) + }); + }); + }); +}) diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 3a9397b05f..490de79b28 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -7,4 +7,4 @@ Cypress.Commands.add('login', (email, password) => { Cypress.Commands.add('checkToastMessage', (toastId, message) => { cy.get(`[id=${toastId}]`).should('contain', message); -}); \ No newline at end of file +}); diff --git a/db/migrate/20210630165919_add_index_to_organization_users.rb b/db/migrate/20210630165919_add_index_to_organization_users.rb new file mode 100644 index 0000000000..357b154ac3 --- /dev/null +++ b/db/migrate/20210630165919_add_index_to_organization_users.rb @@ -0,0 +1,5 @@ +class AddIndexToOrganizationUsers < ActiveRecord::Migration[6.1] + def change + add_index :organization_users, [:organization_id, :user_id], unique: true, if_not_exists: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 5ffd80a70d..28b0030bb7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_06_19_124759) do +ActiveRecord::Schema.define(version: 2021_06_30_165919) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" @@ -142,6 +142,7 @@ ActiveRecord::Schema.define(version: 2021_06_19_124759) do t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false t.string "status", default: "invited" + t.index ["organization_id", "user_id"], name: "index_organization_users_on_organization_id_and_user_id", unique: true t.index ["organization_id"], name: "index_organization_users_on_organization_id" t.index ["user_id"], name: "index_organization_users_on_user_id" end diff --git a/deploy/ec2/.env b/deploy/ec2/.env index 46f6a92945..bbbb7b5b63 100644 --- a/deploy/ec2/.env +++ b/deploy/ec2/.env @@ -5,3 +5,4 @@ PG_DB=tooljet_prod PG_USER= PG_HOST= PG_PASS= +RAILS_LOG_TO_STDOUT=true diff --git a/deploy/ec2/nginx.conf b/deploy/ec2/nginx.conf index 09e6953c21..f928bd85b6 100644 --- a/deploy/ec2/nginx.conf +++ b/deploy/ec2/nginx.conf @@ -58,7 +58,7 @@ http location / { root /home/ubuntu/app/frontend/build; - index index.html; + try_files $uri $uri/ /index.html; } location /_backend_ @@ -84,7 +84,7 @@ http location / { root /home/ubuntu/app/frontend/build; - index index.html; + try_files $uri $uri/ /index.html; } location /_backend_ diff --git a/deploy/ec2/setup_app b/deploy/ec2/setup_app index bb65144e53..19b4275b2c 100755 --- a/deploy/ec2/setup_app +++ b/deploy/ec2/setup_app @@ -35,7 +35,7 @@ def build_fe backend_url = "#{ENV.fetch("TOOLJET_HOST")}/_backend_" front_end_working_dir = "/home/ubuntu/app/frontend" Dir.chdir front_end_working_dir - system("npm install") + system("npm install --only=production") system("NODE_ENV=production TOOLJET_SERVER_URL=#{backend_url} npm run-script build") end diff --git a/deploy/ec2/tool_jet_ubuntu_bionic.pkr.hcl b/deploy/ec2/tool_jet_ubuntu_bionic.pkr.hcl index bc207e27d0..7546b577bf 100644 --- a/deploy/ec2/tool_jet_ubuntu_bionic.pkr.hcl +++ b/deploy/ec2/tool_jet_ubuntu_bionic.pkr.hcl @@ -8,9 +8,9 @@ packer { } source "amazon-ebs" "ubuntu" { - ami_name = "tooljet_latest_ubuntu_bionic" - instance_type = "t2.medium" - region = "us-west-2" + ami_name = "${var.ami_name}" + instance_type = "${var.instance_type}" + region = "${var.ami_region}" source_ami_filter { filters = { name = "ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*" diff --git a/deploy/ec2/variables.pkr.hcl b/deploy/ec2/variables.pkr.hcl new file mode 100644 index 0000000000..62abcd585e --- /dev/null +++ b/deploy/ec2/variables.pkr.hcl @@ -0,0 +1,14 @@ + +variable "ami_name" { + type = string +} + +variable "instance_type" { + type = string + default = "t2.medium" +} + +variable "ami_region" { + type = string + default = "us-west-2" +} diff --git a/docker/entrypoints/server.sh b/docker/entrypoints/server.sh old mode 100644 new mode 100755 index ae3d784dac..8ab5c0ac6f --- a/docker/entrypoints/server.sh +++ b/docker/entrypoints/server.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh set -e bundle check || bundle install rake db:create diff --git a/docker/server.Dockerfile b/docker/server.Dockerfile index 5425eac8ba..af31628094 100644 --- a/docker/server.Dockerfile +++ b/docker/server.Dockerfile @@ -15,4 +15,4 @@ ENV RAILS_ENV=production COPY . ./ RUN ["chmod", "755", "docker/entrypoints/server.sh"] -ENTRYPOINT ["docker/entrypoints/server.sh"] +ENTRYPOINT ["./docker/entrypoints/server.sh"] diff --git a/docs/docs/contributing-guide/setup/Mac OS.md b/docs/docs/contributing-guide/setup/Mac OS.md index 28283440b6..eae77909ca 100644 --- a/docs/docs/contributing-guide/setup/Mac OS.md +++ b/docs/docs/contributing-guide/setup/Mac OS.md @@ -32,9 +32,13 @@ Follow these steps to setup and run ToolJet on Mac OS. Open terminal and run the gem install bundler:2.1.4 ``` - ### Install Node.js + ### Install Node.js ( version: v14.9.0 ) ```bash - $ brew install node + $ brew install nvm + $ export NVM_DIR=~/.nvm + $ source $(brew --prefix nvm)/nvm.sh + $ nvm install 14.9.0 + $ nvm use 14.9.0 ``` @@ -56,13 +60,17 @@ Follow these steps to setup and run ToolJet on Mac OS. Open terminal and run the ``` 3. ## Populate the keys in the env file. - Run `openssl rand -hex 64` to create secure secrets and use them as the values for `LOCKBOX_MASTER_KEY` and `SECRET_KEY_BASE`. + :::info + `SECRET_KEY_BASE` requires a 64 byte key. (If you have `openssl` installed, run `openssl rand -hex 64` to create a 64 byte secure random key) + + `LOCKBOX_MASTER_KEY` requires a 32 byte key. (Run `openssl rand -hex 32` to create a 32 byte secure random key) + ::: Example: ```bash $ cat .env TOOLJET_HOST=http://localhost:8082 - LOCKBOX_MASTER_KEY=c92bcc7f112ffbdd131d1fb6c5005e372b8802f85f6c4586e5a88f57a541382841c8c99e5701b84862e448dd5db846f705321a41bd48a0fed1b58b9596a3877f + LOCKBOX_MASTER_KEY=1d291a926ddfd221205a23adb4cc1db66cb9fcaf28d97c8c1950e3538e3b9281 SECRET_KEY_BASE=4229d5774cfe7f60e75d6b3bf3a1dbb054a696b6d21b6d5de7b73291899797a222265e12c0a8e8d844f83ebacdf9a67ec42584edf1c2b23e1e7813f8a3339041 ``` @@ -105,8 +113,13 @@ Follow these steps to setup and run ToolJet on Mac OS. Open terminal and run the ```ruby OrganizationUser.create(user: User.first, organization: Organization.first, role: 'admin', status: 'active') ``` +8. ## Install webpack + ```bash + $ npm install --save-dev webpack + $ npm install --save-dev webpack-cli + ``` -8. ## Running the React frontend ( Client ) +9. ## Running the React frontend ( Client ) ```bash $ cd ./frontend && npm start ``` diff --git a/docs/docs/contributing-guide/setup/docker.md b/docs/docs/contributing-guide/setup/docker.md index 34028f8b39..831686b734 100644 --- a/docs/docs/contributing-guide/setup/docker.md +++ b/docs/docs/contributing-guide/setup/docker.md @@ -74,6 +74,45 @@ We recommend: $ docker-compose stop ``` +## Making changes to the codebase + +If you make any changes to the codebase/pull the latest changes from upstream, the tooljet server container would hot reload the application without you doing anything. + +Caveat: + +1. If the changes include database migrations or new gem additions in the Gemfile, you would need to restart the ToolJet server container by running `docker-compose restart server`. + +2. If you need to add a new binary or system libary to the container itself, you would need to add those dependencies in `docker/server.Dockerfile.dev` and then rebuild the ToolJet server image. You can do that by running `docker-compose build server`. Once that completes you can start everything normally with `docker-compose up`. + +Example: +Let's say you need to install the `imagemagick` binary in your ToolJet server's container. You'd then need to make sure that `apt` installs `imagemagick` while building the image. The Dockerfile at `docker/server.Dockerfile.dev` for the server would then look something like this: +``` +FROM ruby:2.7.3-buster + +#Notice the newly added imagemagick package +RUN apt update && apt install -y \ + build-essential \ + postgresql \ + freetds-dev \ + imagemagick + + +RUN mkdir -p /app +WORKDIR /app + +COPY Gemfile Gemfile.lock ./ +RUN gem install bundler && bundle install --jobs 20 --retry 5 + +ENV RAILS_ENV=development + +COPY . ./ + +RUN ["chmod", "755", "docker/entrypoints/server.sh"] + +``` +Once you've updated the Dockerfile, rebuild the image by running `docker-compose build server`. After building the new image, start the services by running `docker-compose up`. + + ## Running Rails tests To run all the tests diff --git a/docs/docs/contributing-guide/setup/ubuntu.md b/docs/docs/contributing-guide/setup/ubuntu.md index d22fd38ea2..13a9ae5a54 100644 --- a/docs/docs/contributing-guide/setup/ubuntu.md +++ b/docs/docs/contributing-guide/setup/ubuntu.md @@ -42,13 +42,17 @@ Follow these steps to setup and run ToolJet on Ubuntu. Open terminal and run the 3. ## Populate the keys in the env file. - Run `openssl rand -hex 64` to create secure secrets and use them as the values for `LOCKBOX_MASTER_KEY` and `SECRET_KEY_BASE`. + :::info + `SECRET_KEY_BASE` requires a 64 byte key. (If you have `openssl` installed, run `openssl rand -hex 64` to create a 64 byte secure random key) + + `LOCKBOX_MASTER_KEY` requires a 32 byte key. (Run `openssl rand -hex 32` to create a 32 byte secure random key) + ::: Example: ```bash $ cat .env TOOLJET_HOST=http://localhost:8082 - LOCKBOX_MASTER_KEY=c92bcc7f112ffbdd131d1fb6c5005e372b8802f85f6c4586e5a88f57a541382841c8c99e5701b84862e448dd5db846f705321a41bd48a0fed1b58b9596a3877f + LOCKBOX_MASTER_KEY=1d291a926ddfd221205a23adb4cc1db66cb9fcaf28d97c8c1950e3538e3b9281 SECRET_KEY_BASE=4229d5774cfe7f60e75d6b3bf3a1dbb054a696b6d21b6d5de7b73291899797a222265e12c0a8e8d844f83ebacdf9a67ec42584edf1c2b23e1e7813f8a3339041 ``` diff --git a/docs/docs/data-sources/graphql.md b/docs/docs/data-sources/graphql.md index 2a06d40b87..755fc2498b 100644 --- a/docs/docs/data-sources/graphql.md +++ b/docs/docs/data-sources/graphql.md @@ -5,17 +5,17 @@ sidebar_position: 3 # GraphQL -ToolJet can connect to GraphQL endpoints. We currently support queries and mutations. +ToolJet can connect to GraphQL endpoints to execute queries and mutations. ## Connection -To add a new GraphQL datasource, click on the '+' button on data sources panel at the left-bottom corner of the app editor. Select GraphQL from the modal that pops up. +To add a new GraphQL datasource, click the `+` button on data sources panel at the bottom-left corner of the app builder and then select GraphQL from the modal that pops up. ToolJet requires the following to connect to a GraphQL datasource. -- **URL** +- URL of the GraphQL endpoint -Following optional parameters are also supported: +The following optional parameters are also supported: | Type | Description | | ----------- | ----------- | @@ -24,14 +24,14 @@ Following optional parameters are also supported: -ToolJet - GraphQL connection +ToolJet - GraphQL connection Click on the 'Save' button to save the datasource. ## Querying GraphQL -Click on '+' button of the query manager at the bottom panel of the editor and select the GraphQL endpoint added in the previous step as the datasource. +Click on `+` button of the query manager at the bottom panel of the editor and select the GraphQL endpoint added in the previous step as the datasource. -ToolJet - GraphQL connection +ToolJet - GraphQL connection Click on the 'run' button to run the query. NOTE: Query should be saved before running. diff --git a/docs/docs/deployment/ec2.md b/docs/docs/deployment/ec2.md index efc24f2506..19786acb90 100644 --- a/docs/docs/deployment/ec2.md +++ b/docs/docs/deployment/ec2.md @@ -16,7 +16,7 @@ Follow the steps below to deploy ToolJet on AWS EC2 instances. 3. Under the `Images` section, click on the `AMIs` button. -4. Now, from the AMI search page, select the search type as "Public Images" and input `AMI Name : tooljet_latest_ubuntu_bionic` in the search bar. +4. Now, from the AMI search page, select the search type as "Public Images" and input `AMI Name : tooljet_v0.5.11.ubuntu_bionic` in the search bar. 5. Select ToolJet's AMI and bootup an EC2 instance. @@ -60,7 +60,7 @@ Follow the steps below to deploy ToolJet on AWS EC2 instances. Please make sure that `TOOLJET_HOST` starts with either `http://` or `https://` ::: -9. Once you've configured the `.env` file, run `./setup_app.rb`. This script will install all the dependencies of ToolJet and then will start the required services. +9. Once you've configured the `.env` file, run `./setup_app`. This script will install all the dependencies of ToolJet and then will start the required services. 10. If you've set a custom domain for `TOOLJET_HOST`, add a `A record` entry in your DNS settings to point to the IP address of the EC2 instance. diff --git a/docs/docs/deployment/env-vars.md b/docs/docs/deployment/env-vars.md index 078af9f515..c9c3764cb2 100644 --- a/docs/docs/deployment/env-vars.md +++ b/docs/docs/deployment/env-vars.md @@ -28,7 +28,20 @@ ToolJet server uses PostgreSQL as the database. | PG_PASS | password | #### Lockbox configuration ( required ) -ToolJet server uses lockbox to encrypt datasource credentials. You should set the environment variable `LOCKBOX_MASTER_KEY`. +ToolJet server uses lockbox to encrypt datasource credentials. You should set the environment variable `LOCKBOX_MASTER_KEY` with a 32 byte hexadecimal string. + + +#### Application Secret ( required ) +ToolJet server uses a secure 64 byte hexadecimal string to encrypt session cookies. You should set the environment variable `SECRET_KEY_BASE`. + + +:::tip +If you have `openssl` installed, you can run the following commands to generate the the value for `LOCKBOX_MASTER_KEY` and `SECRET_KEY_BASE`. + +For `LOCKBOX_MASTER_KEY` use `openssl rand -hex 32` +For `SECRET_KEY_BASE` use `openssl rand -hex 64` +::: + #### Disabling signups ( optional ) diff --git a/docs/docs/deployment/kubernetes.md b/docs/docs/deployment/kubernetes.md index 5f4743af7b..576f3b4373 100644 --- a/docs/docs/deployment/kubernetes.md +++ b/docs/docs/deployment/kubernetes.md @@ -12,12 +12,12 @@ Follow the steps below to deploy ToolJet server on a Kubernetes cluster. 1. Setup a PostgreSQL database. -2. Create a Kubernetes secret with name `server`. For the minimal setup, ToolJet requires pg_host, pg_db, pg_user, pg_password, secret_key_base & lockbox_key keys in the secret. ( Read [environment variables reference](/docs/deployment/env-vars) ) +2. Create a Kubernetes secret with name `server`. For the minimal setup, ToolJet requires `pg_host`, `pg_db`, `pg_user`, `pg_password`, `secret_key_base` & `lockbox_key` keys in the secret. ( Read [environment variables reference](/docs/deployment/env-vars) ) 3. Create a Kubernetes deployment ```bash -$ kubectl apply -f https://github.com/ToolJet/ToolJet/blob/main/deploy/kubernetes/server-deployment.yaml +$ kubectl apply -f https://raw.githubusercontent.com/ToolJet/ToolJet/main/deploy/kubernetes/server-deployment.yaml ``` :::info @@ -30,15 +30,7 @@ The file given above is just a template and might not suit production environmen $ kubectl get pods ``` -You should be able to see that the `tooljet-server` pod has been created. - -```bash -$ kubectl port-forward 3000:3000 -``` - -Use this command to forward the port 3000 of server on the pod to the port 3000 of your local machine. - -5. You can setup load balancers or Kubernetes services to publish the Kubernetes deployment that you've created. This step varies with cloud providers. +5. Create a Kubernetes services to publish the Kubernetes deployment that you've created. This step varies with cloud providers. We have a [template](https://raw.githubusercontent.com/ToolJet/ToolJet/main/deploy/kubernetes/server-service.yaml) for exposing the ToolJet server as a service using an AWS loadbalancer. Examples: Application load balancing on Amazon EKS: https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html GKE Ingress for HTTP(S) Load Balancing: https://cloud.google.com/kubernetes-engine/docs/concepts/ingress diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 2539a8d3d1..c8e386060f 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -24,7 +24,7 @@ Here is a video explaining how to build a Redis GUI using ToolJet in 3 minutes: These resources will help you to quickly build and deploy apps using ToolJet: -- **[Setup](/docs/setup/architecture)** - Learn how to setup ToolJet locally using docker. +- **[Setup](/docs/deployment/architecture)** - Learn how to setup ToolJet locally using docker. - **[Basic Tutorial](/docs/tutorial/creating-app)** - Learn how to build simple UI and connect to data sources. - **[Deploy](/docs/contributing-guide/setup/docker)** - Learn how to deploy ToolJet on Heroku, Kubernetes, etc diff --git a/docs/static/img/datasource-reference/graphql/add-source.gif b/docs/static/img/datasource-reference/graphql/add-source.gif new file mode 100644 index 0000000000..a22c124677 Binary files /dev/null and b/docs/static/img/datasource-reference/graphql/add-source.gif differ diff --git a/frontend/src/App/App.jsx b/frontend/src/App/App.jsx index 00db582b37..bcbe3509ea 100644 --- a/frontend/src/App/App.jsx +++ b/frontend/src/App/App.jsx @@ -55,12 +55,12 @@ class App extends React.Component { return (
- {updateAvailable &&