mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
merge base
This commit is contained in:
commit
3f201e9a28
227 changed files with 5733 additions and 2493 deletions
68
.github/workflows/cypress-appbuilder.yml
vendored
68
.github/workflows/cypress-appbuilder.yml
vendored
|
|
@ -13,16 +13,18 @@ jobs:
|
||||||
Cypress-App-Builder:
|
Cypress-App-Builder:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
if: |
|
if: |
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-ce-app-builder') ||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ce') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-ee-app-builder') ||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ee') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-cypress')
|
contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
|
||||||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce')
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
edition: >-
|
edition: >-
|
||||||
${{
|
${{
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-ce-app-builder') && fromJson('["ce"]') ||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ce') && fromJson('["ce"]') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-ee-app-builder') && fromJson('["ee"]') ||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce') && fromJson('["ce"]') ||
|
||||||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ee') && fromJson('["ee"]') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') ||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') ||
|
||||||
fromJson('[]')
|
fromJson('[]')
|
||||||
}}
|
}}
|
||||||
|
|
@ -158,35 +160,35 @@ jobs:
|
||||||
name: screenshots-appbuilder-${{ matrix.edition }}
|
name: screenshots-appbuilder-${{ matrix.edition }}
|
||||||
path: cypress-tests/cypress/screenshots
|
path: cypress-tests/cypress/screenshots
|
||||||
|
|
||||||
Cypress-App-builder-Subpath:
|
# Cypress-App-builder-Subpath:
|
||||||
runs-on: ubuntu-22.04
|
# runs-on: ubuntu-22.04
|
||||||
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
|
# if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-subpath')
|
# contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-subpath')
|
||||||
|
|
||||||
steps:
|
# steps:
|
||||||
- name: Checkout
|
# - name: Checkout
|
||||||
uses: actions/checkout@v3
|
# uses: actions/checkout@v3
|
||||||
with:
|
# with:
|
||||||
ref: ${{ github.event.pull_request.head.ref }}
|
# ref: ${{ github.event.pull_request.head.ref }}
|
||||||
|
|
||||||
- name: Create Cypress environment file
|
# - name: Create Cypress environment file
|
||||||
id: create-json
|
# id: create-json
|
||||||
uses: jsdaniell/create-json@1.1.2
|
# uses: jsdaniell/create-json@1.1.2
|
||||||
with:
|
# with:
|
||||||
name: "cypress.env.json"
|
# name: "cypress.env.json"
|
||||||
json: ${{ secrets.CYPRESS_SECRETS }}
|
# json: ${{ secrets.CYPRESS_SECRETS }}
|
||||||
dir: "./cypress-tests"
|
# dir: "./cypress-tests"
|
||||||
|
|
||||||
- name: App Builder subpath
|
# - name: App Builder subpath
|
||||||
uses: cypress-io/github-action@v5
|
# uses: cypress-io/github-action@v5
|
||||||
with:
|
# with:
|
||||||
working-directory: ./cypress-tests
|
# working-directory: ./cypress-tests
|
||||||
config: "baseUrl=http://localhost:80/apps/tooljet/"
|
# config: "baseUrl=http://localhost:80/apps/tooljet/"
|
||||||
config-file: cypress-app-builder.config.js
|
# config-file: cypress-app-builder.config.js
|
||||||
|
|
||||||
- name: Capture Screenshots
|
# - name: Capture Screenshots
|
||||||
uses: actions/upload-artifact@v4
|
# uses: actions/upload-artifact@v4
|
||||||
if: always()
|
# if: always()
|
||||||
with:
|
# with:
|
||||||
name: screenshots
|
# name: screenshots
|
||||||
path: cypress-tests/cypress/screenshots
|
# path: cypress-tests/cypress/screenshots
|
||||||
|
|
|
||||||
15
.github/workflows/cypress-marketplace.yml
vendored
15
.github/workflows/cypress-marketplace.yml
vendored
|
|
@ -15,16 +15,18 @@ jobs:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
|
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-marketplace') ||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ce') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-marketplace')
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ee') ||
|
||||||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce')
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
edition: >-
|
edition: >-
|
||||||
${{
|
${{
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') ||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-marketplace') && fromJson('["ce"]') ||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce') && fromJson('["ce"]') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-marketplace') && fromJson('["ee"]') ||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ce') && fromJson('["ce"]') ||
|
||||||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ee') && fromJson('["ee"]') ||
|
||||||
fromJson('[]')
|
fromJson('[]')
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
@ -159,13 +161,12 @@ jobs:
|
||||||
"password": "password"
|
"password": "password"
|
||||||
}'
|
}'
|
||||||
|
|
||||||
|
|
||||||
- name: Create Cypress environment file
|
- name: Create Cypress environment file
|
||||||
id: create-json
|
id: create-json
|
||||||
uses: jsdaniell/create-json@1.1.2
|
uses: jsdaniell/create-json@1.1.2
|
||||||
with:
|
with:
|
||||||
name: "cypress.env.json"
|
name: "cypress.env.json"
|
||||||
json: ${{ secrets.CYPRESS_SECRETS }}
|
json: ${{ secrets.CYPRESS_SECRETS_MARKETPLACE }}
|
||||||
dir: "./cypress-tests"
|
dir: "./cypress-tests"
|
||||||
|
|
||||||
- name: Marketplace
|
- name: Marketplace
|
||||||
|
|
@ -186,7 +187,7 @@ jobs:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
|
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-subpath')
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-subpath')
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|
|
||||||
11
.github/workflows/cypress-platform.yml
vendored
11
.github/workflows/cypress-platform.yml
vendored
|
|
@ -13,15 +13,18 @@ jobs:
|
||||||
Cypress-Platform:
|
Cypress-Platform:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
|
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-platform') ||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ce') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-platform')
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ee') ||
|
||||||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce')
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
edition: >-
|
edition: >-
|
||||||
${{
|
${{
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') ||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-platform') && fromJson('["ce"]') ||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce') && fromJson('["ce"]') ||
|
||||||
contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-platform') && fromJson('["ee"]') ||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ce') && fromJson('["ce"]') ||
|
||||||
|
contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ee') && fromJson('["ee"]') ||
|
||||||
fromJson('[]')
|
fromJson('[]')
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
|
||||||
173
.github/workflows/render-preview-deploy.yml
vendored
173
.github/workflows/render-preview-deploy.yml
vendored
|
|
@ -80,7 +80,7 @@ jobs:
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "PG_USER",
|
"key": "PG_USER",
|
||||||
"value": "tooljet"
|
"value": "postgres"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "PG_PASS",
|
"key": "PG_PASS",
|
||||||
|
|
@ -100,7 +100,7 @@ jobs:
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "TOOLJET_DB_USER",
|
"key": "TOOLJET_DB_USER",
|
||||||
"value": "tooljet"
|
"value": "postgres"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "TOOLJET_DB_PASS",
|
"key": "TOOLJET_DB_PASS",
|
||||||
|
|
@ -116,7 +116,7 @@ jobs:
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "PGRST_DB_URI",
|
"key": "PGRST_DB_URI",
|
||||||
"value": "postgres://tooljet:postgres@localhost/${{ env.PR_NUMBER }}-ce-tjdb"
|
"value": "postgres://postgres:postgres@localhost/${{ env.PR_NUMBER }}-ce-tjdb"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "PGRST_HOST",
|
"key": "PGRST_HOST",
|
||||||
|
|
@ -168,7 +168,11 @@ jobs:
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"serviceDetails": {
|
"serviceDetails": {
|
||||||
"disk": null,
|
"disk": {
|
||||||
|
"name": "tooljet-ce-pr-${{ env.PR_NUMBER }}-postgresql",
|
||||||
|
"mountPath": "/var/lib/postgresql/13/main",
|
||||||
|
"sizeGB": 10
|
||||||
|
},
|
||||||
"env": "docker",
|
"env": "docker",
|
||||||
"envSpecificDetails": {
|
"envSpecificDetails": {
|
||||||
"dockerCommand": "",
|
"dockerCommand": "",
|
||||||
|
|
@ -279,35 +283,35 @@ jobs:
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: Install PostgreSQL client
|
# - name: Install PostgreSQL client
|
||||||
run: |
|
# run: |
|
||||||
sudo apt update
|
# sudo apt update
|
||||||
sudo apt install postgresql-client -y
|
# sudo apt install postgresql-client -y
|
||||||
|
|
||||||
- name: Wait after installing PostgreSQL
|
# - name: Wait after installing PostgreSQL
|
||||||
run: sleep 25
|
# run: sleep 25
|
||||||
|
|
||||||
- name: Drop PostgreSQL PR databases
|
# - name: Drop PostgreSQL PR databases
|
||||||
env:
|
# env:
|
||||||
PGHOST: ${{ secrets.RENDER_DS_PG_HOST }}
|
# PGHOST: ${{ secrets.RENDER_DS_PG_HOST }}
|
||||||
PGPORT: 5432
|
# PGPORT: 5432
|
||||||
PGUSER: ${{ secrets.RENDER_DS_PG_USER }}
|
# PGUSER: ${{ secrets.RENDER_DS_PG_USER }}
|
||||||
PGDATABASE: ${{ env.PR_NUMBER }}-ce
|
# PGDATABASE: ${{ env.PR_NUMBER }}-ce
|
||||||
PGTJBDATABASE: ${{ env.PR_NUMBER }}-ce-tjdb
|
# PGTJBDATABASE: ${{ env.PR_NUMBER }}-ce-tjdb
|
||||||
run: |
|
# run: |
|
||||||
if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGDATABASE; then
|
# if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGDATABASE; then
|
||||||
echo "Database $PGDATABASE exists, deleting..."
|
# echo "Database $PGDATABASE exists, deleting..."
|
||||||
PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGDATABASE\" ;"
|
# PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGDATABASE\" ;"
|
||||||
else
|
# else
|
||||||
echo "Database $PGDATABASE does not exist."
|
# echo "Database $PGDATABASE does not exist."
|
||||||
fi
|
# fi
|
||||||
|
|
||||||
if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGTJBDATABASE; then
|
# if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGTJBDATABASE; then
|
||||||
echo "Database $PGTJBDATABASE exists, deleting..."
|
# echo "Database $PGTJBDATABASE exists, deleting..."
|
||||||
PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGTJBDATABASE\" ;"
|
# PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGTJBDATABASE\" ;"
|
||||||
else
|
# else
|
||||||
echo "Database $PGTJBDATABASE does not exist."
|
# echo "Database $PGTJBDATABASE does not exist."
|
||||||
fi
|
# fi
|
||||||
|
|
||||||
suspend-ce-review-app:
|
suspend-ce-review-app:
|
||||||
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'suspend-ce-review-app' }}
|
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'suspend-ce-review-app' }}
|
||||||
|
|
@ -317,7 +321,7 @@ jobs:
|
||||||
- name: Suspend service
|
- name: Suspend service
|
||||||
run: |
|
run: |
|
||||||
export SERVICE_ID=$(curl --request GET \
|
export SERVICE_ID=$(curl --request GET \
|
||||||
--url 'https://api.render.com/v1/services?name=ToolJet%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \
|
--url 'https://api.render.com/v1/services?name=ToolJet%20CE%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \
|
||||||
--header 'accept: application/json' \
|
--header 'accept: application/json' \
|
||||||
--header 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \
|
--header 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \
|
||||||
jq -r '.[0].service.id')
|
jq -r '.[0].service.id')
|
||||||
|
|
@ -349,7 +353,7 @@ jobs:
|
||||||
- name: Resume service
|
- name: Resume service
|
||||||
run: |
|
run: |
|
||||||
export SERVICE_ID=$(curl --request GET \
|
export SERVICE_ID=$(curl --request GET \
|
||||||
--url 'https://api.render.com/v1/services?name=ToolJet%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \
|
--url 'https://api.render.com/v1/services?name=ToolJet%20CE%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \
|
||||||
--header 'accept: application/json' \
|
--header 'accept: application/json' \
|
||||||
--header 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \
|
--header 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \
|
||||||
jq -r '.[0].service.id')
|
jq -r '.[0].service.id')
|
||||||
|
|
@ -389,6 +393,39 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
|
- name: Sync repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Check if Forked Repository
|
||||||
|
id: check_repo
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]]; then
|
||||||
|
echo "is_fork=true" >> $GITHUB_ENV
|
||||||
|
echo "FORKED_OWNER=${{ github.event.pull_request.head.repo.owner.login }}" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "is_fork=false" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Set Repository URL
|
||||||
|
run: |
|
||||||
|
if [[ "$is_fork" == "true" ]]; then
|
||||||
|
echo "REPO_URL=https://github.com/${FORKED_OWNER}/ToolJet" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "REPO_URL=https://github.com/ToolJet/ToolJet" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Fetch and Checkout Forked Branch
|
||||||
|
if: env.is_fork == 'true'
|
||||||
|
run: |
|
||||||
|
git fetch origin pull/${{ github.event.number }}/head:${{ env.BRANCH_NAME }}
|
||||||
|
git checkout ${{ env.BRANCH_NAME }}
|
||||||
|
|
||||||
|
- name: Checkout Default Branch
|
||||||
|
if: env.is_fork == 'false'
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
|
||||||
- name: Creating deployment for Enterprise Edition
|
- name: Creating deployment for Enterprise Edition
|
||||||
id: create-ee-deployment
|
id: create-ee-deployment
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -404,7 +441,7 @@ jobs:
|
||||||
"name": "ToolJet EE PR #${{ env.PR_NUMBER }}",
|
"name": "ToolJet EE PR #${{ env.PR_NUMBER }}",
|
||||||
"notifyOnFail": "default",
|
"notifyOnFail": "default",
|
||||||
"ownerId": "tea-caeo4bj19n072h3dddc0",
|
"ownerId": "tea-caeo4bj19n072h3dddc0",
|
||||||
"repo": "https://github.com/ToolJet/ToolJet",
|
"repo": "'"$REPO_URL"'",
|
||||||
"slug": "tooljet-ee-pr-${{ env.PR_NUMBER }}",
|
"slug": "tooljet-ee-pr-${{ env.PR_NUMBER }}",
|
||||||
"suspended": "not_suspended",
|
"suspended": "not_suspended",
|
||||||
"suspenders": [],
|
"suspenders": [],
|
||||||
|
|
@ -420,7 +457,7 @@ jobs:
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "PG_USER",
|
"key": "PG_USER",
|
||||||
"value": "tooljet"
|
"value": "postgres"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "PG_PASS",
|
"key": "PG_PASS",
|
||||||
|
|
@ -440,7 +477,7 @@ jobs:
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "TOOLJET_DB_USER",
|
"key": "TOOLJET_DB_USER",
|
||||||
"value": "tooljet"
|
"value": "postgres"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "TOOLJET_DB_PASS",
|
"key": "TOOLJET_DB_PASS",
|
||||||
|
|
@ -456,7 +493,7 @@ jobs:
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "PGRST_DB_URI",
|
"key": "PGRST_DB_URI",
|
||||||
"value": "postgres://tooljet:postgres@localhost/${{ env.PR_NUMBER }}-ee-tjdb"
|
"value": "postgres://postgres:postgres@localhost/${{ env.PR_NUMBER }}-ee-tjdb"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "PGRST_HOST",
|
"key": "PGRST_HOST",
|
||||||
|
|
@ -536,7 +573,11 @@ jobs:
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"serviceDetails": {
|
"serviceDetails": {
|
||||||
"disk": null,
|
"disk": {
|
||||||
|
"name": "tooljet-ee-pr-${{ env.PR_NUMBER }}-postgresql",
|
||||||
|
"mountPath": "/var/lib/postgresql/13/main",
|
||||||
|
"sizeGB": 10
|
||||||
|
},
|
||||||
"env": "docker",
|
"env": "docker",
|
||||||
"envSpecificDetails": {
|
"envSpecificDetails": {
|
||||||
"dockerCommand": "",
|
"dockerCommand": "",
|
||||||
|
|
@ -549,7 +590,7 @@ jobs:
|
||||||
"port": 80,
|
"port": 80,
|
||||||
"protocol": "TCP"
|
"protocol": "TCP"
|
||||||
}],
|
}],
|
||||||
"plan": "starter",
|
"plan": "standard",
|
||||||
"pullRequestPreviewsEnabled": "no",
|
"pullRequestPreviewsEnabled": "no",
|
||||||
"region": "oregon",
|
"region": "oregon",
|
||||||
"url": "https://tooljet-ee-pr-${{ env.PR_NUMBER }}.onrender.com"
|
"url": "https://tooljet-ee-pr-${{ env.PR_NUMBER }}.onrender.com"
|
||||||
|
|
@ -647,35 +688,35 @@ jobs:
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: Install PostgreSQL client
|
# - name: Install PostgreSQL client
|
||||||
run: |
|
# run: |
|
||||||
sudo apt update
|
# sudo apt update
|
||||||
sudo apt install postgresql-client -y
|
# sudo apt install postgresql-client -y
|
||||||
|
|
||||||
- name: Wait after installing PostgreSQL
|
# - name: Wait after installing PostgreSQL
|
||||||
run: sleep 25
|
# run: sleep 25
|
||||||
|
|
||||||
- name: Drop PostgreSQL PR databases
|
# - name: Drop PostgreSQL PR databases
|
||||||
env:
|
# env:
|
||||||
PGHOST: ${{ secrets.RENDER_DS_PG_HOST }}
|
# PGHOST: ${{ secrets.RENDER_DS_PG_HOST }}
|
||||||
PGPORT: 5432
|
# PGPORT: 5432
|
||||||
PGUSER: ${{ secrets.RENDER_DS_PG_USER }}
|
# PGUSER: ${{ secrets.RENDER_DS_PG_USER }}
|
||||||
PGDATABASE: ${{ env.PR_NUMBER }}-ee
|
# PGDATABASE: ${{ env.PR_NUMBER }}-ee
|
||||||
PGTJBDATABASE: ${{ env.PR_NUMBER }}-ee-tjdb
|
# PGTJBDATABASE: ${{ env.PR_NUMBER }}-ee-tjdb
|
||||||
run: |
|
# run: |
|
||||||
if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGDATABASE; then
|
# if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGDATABASE; then
|
||||||
echo "Database $PGDATABASE exists, deleting..."
|
# echo "Database $PGDATABASE exists, deleting..."
|
||||||
PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGDATABASE\" ;"
|
# PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGDATABASE\" ;"
|
||||||
else
|
# else
|
||||||
echo "Database $PGDATABASE does not exist."
|
# echo "Database $PGDATABASE does not exist."
|
||||||
fi
|
# fi
|
||||||
|
|
||||||
if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGTJBDATABASE; then
|
# if PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -lqt | cut -d \| -f 1 | grep -qw $PGTJBDATABASE; then
|
||||||
echo "Database $PGTJBDATABASE exists, deleting..."
|
# echo "Database $PGTJBDATABASE exists, deleting..."
|
||||||
PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGTJBDATABASE\" ;"
|
# PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGTJBDATABASE\" ;"
|
||||||
else
|
# else
|
||||||
echo "Database $PGTJBDATABASE does not exist."
|
# echo "Database $PGTJBDATABASE does not exist."
|
||||||
fi
|
# fi
|
||||||
|
|
||||||
suspend-ee-review-app:
|
suspend-ee-review-app:
|
||||||
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'suspend-ee-review-app' }}
|
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'suspend-ee-review-app' }}
|
||||||
|
|
@ -685,7 +726,7 @@ jobs:
|
||||||
- name: Suspend service
|
- name: Suspend service
|
||||||
run: |
|
run: |
|
||||||
export SERVICE_ID=$(curl --request GET \
|
export SERVICE_ID=$(curl --request GET \
|
||||||
--url 'https://api.render.com/v1/services?name=ToolJet%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \
|
--url 'https://api.render.com/v1/services?name=ToolJet%20EE%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \
|
||||||
--header 'accept: application/json' \
|
--header 'accept: application/json' \
|
||||||
--header 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \
|
--header 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \
|
||||||
jq -r '.[0].service.id')
|
jq -r '.[0].service.id')
|
||||||
|
|
@ -717,7 +758,7 @@ jobs:
|
||||||
- name: Resume service
|
- name: Resume service
|
||||||
run: |
|
run: |
|
||||||
export SERVICE_ID=$(curl --request GET \
|
export SERVICE_ID=$(curl --request GET \
|
||||||
--url 'https://api.render.com/v1/services?name=ToolJet%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \
|
--url 'https://api.render.com/v1/services?name=ToolJet%20EE%20PR%20%23${{ env.PR_NUMBER }}&limit=1' \
|
||||||
--header 'accept: application/json' \
|
--header 'accept: application/json' \
|
||||||
--header 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \
|
--header 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \
|
||||||
jq -r '.[0].service.id')
|
jq -r '.[0].service.id')
|
||||||
|
|
|
||||||
2
.version
2
.version
|
|
@ -1 +1 @@
|
||||||
3.11.0
|
3.12.1
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,11 @@ module.exports = defineConfig({
|
||||||
chromeWebSecurity: false,
|
chromeWebSecurity: false,
|
||||||
trashAssetsBeforeRuns: true,
|
trashAssetsBeforeRuns: true,
|
||||||
e2e: {
|
e2e: {
|
||||||
setupNodeEvents(on, config) {
|
setupNodeEvents (on, config) {
|
||||||
config.baseUrl = environment.baseUrl;
|
config.baseUrl = environment.baseUrl;
|
||||||
|
|
||||||
on("task", {
|
on("task", {
|
||||||
readPdf(pathToPdf) {
|
readPdf (pathToPdf) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const pdfPath = path.resolve(pathToPdf);
|
const pdfPath = path.resolve(pathToPdf);
|
||||||
let dataBuffer = fs.readFileSync(pdfPath);
|
let dataBuffer = fs.readFileSync(pdfPath);
|
||||||
|
|
@ -55,7 +55,7 @@ module.exports = defineConfig({
|
||||||
});
|
});
|
||||||
|
|
||||||
on("task", {
|
on("task", {
|
||||||
readXlsx(filePath) {
|
readXlsx (filePath) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
let dataBuffer = fs.readFileSync(filePath);
|
let dataBuffer = fs.readFileSync(filePath);
|
||||||
|
|
@ -69,7 +69,7 @@ module.exports = defineConfig({
|
||||||
});
|
});
|
||||||
|
|
||||||
on("task", {
|
on("task", {
|
||||||
deleteFolder(folderName) {
|
deleteFolder (folderName) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
rmdir(folderName, { maxRetries: 10, recursive: true }, (err) => {
|
rmdir(folderName, { maxRetries: 10, recursive: true }, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
@ -83,7 +83,7 @@ module.exports = defineConfig({
|
||||||
});
|
});
|
||||||
|
|
||||||
on("task", {
|
on("task", {
|
||||||
dbConnection({ dbconfig, sql }) {
|
dbConnection ({ dbconfig, sql }) {
|
||||||
const client = new pg.Pool(dbconfig);
|
const client = new pg.Pool(dbconfig);
|
||||||
return client.query(sql);
|
return client.query(sql);
|
||||||
},
|
},
|
||||||
|
|
@ -97,9 +97,9 @@ module.exports = defineConfig({
|
||||||
baseUrl: environment.baseUrl,
|
baseUrl: environment.baseUrl,
|
||||||
configFile: environment.configFile,
|
configFile: environment.configFile,
|
||||||
specPattern: [
|
specPattern: [
|
||||||
"cypress/e2e/happyPath/platform/ceTestcases/userFlow/firstUserOnboarding.cy.js",
|
"cypress/e2e/happyPath/platform/firstUser/firstUserOnboarding.cy.js",
|
||||||
"cypress/e2e/happyPath/platform/commonTestcases/workspace/dashboard.cy.js",
|
"cypress/e2e/happyPath/platform/ceTestcases/apps/appSlug.cy.js",
|
||||||
"cypress/e2e/happyPath/platform/ceTestcases/!(userFlow)/**/*.cy.js",
|
"cypress/e2e/happyPath/platform/ceTestcases/**/!(*appSlug).cy.js",
|
||||||
"cypress/e2e/happyPath/platform/commonTestcases/**/*.cy.js",
|
"cypress/e2e/happyPath/platform/commonTestcases/**/*.cy.js",
|
||||||
],
|
],
|
||||||
numTestsKeptInMemory: 1,
|
numTestsKeptInMemory: 1,
|
||||||
|
|
|
||||||
|
|
@ -689,7 +689,7 @@ Cypress.Commands.add(
|
||||||
name: dataSourceName,
|
name: dataSourceName,
|
||||||
options: [
|
options: [
|
||||||
{ key: "connection_type", value: "manual", encrypted: false },
|
{ key: "connection_type", value: "manual", encrypted: false },
|
||||||
{ key: "host", value: "35.238.9.114" },
|
{ key: "host", value: "9.234.17.31" },
|
||||||
{ key: "port", value: 5432 },
|
{ key: "port", value: 5432 },
|
||||||
{ key: "database", value: "student" },
|
{ key: "database", value: "student" },
|
||||||
{ key: "username", value: "postgres" },
|
{ key: "username", value: "postgres" },
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { passwordInputText } from "Texts/passwordInput";
|
||||||
import { importSelectors } from "Selectors/exportImport";
|
import { importSelectors } from "Selectors/exportImport";
|
||||||
import { importText } from "Texts/exportImport";
|
import { importText } from "Texts/exportImport";
|
||||||
import { onboardingSelectors } from "Selectors/onboarding";
|
import { onboardingSelectors } from "Selectors/onboarding";
|
||||||
|
import { selectAppCardOption } from "Support/utils/common";
|
||||||
|
|
||||||
const API_ENDPOINT =
|
const API_ENDPOINT =
|
||||||
Cypress.env("environment") === "Community"
|
Cypress.env("environment") === "Community"
|
||||||
|
|
@ -160,13 +161,15 @@ Cypress.Commands.add(
|
||||||
|
|
||||||
Cypress.Commands.add("deleteApp", (appName) => {
|
Cypress.Commands.add("deleteApp", (appName) => {
|
||||||
cy.intercept("DELETE", "/api/apps/*").as("appDeleted");
|
cy.intercept("DELETE", "/api/apps/*").as("appDeleted");
|
||||||
cy.get(commonSelectors.appCard(appName))
|
selectAppCardOption(
|
||||||
.realHover()
|
appName,
|
||||||
.find(commonSelectors.appCardOptionsButton)
|
commonSelectors.appCardOptions(commonText.deleteAppOption)
|
||||||
.realHover()
|
);
|
||||||
.click();
|
|
||||||
cy.get(commonSelectors.deleteAppOption).click();
|
|
||||||
cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click();
|
cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click();
|
||||||
|
cy.verifyToastMessage(
|
||||||
|
commonSelectors.toastMessage,
|
||||||
|
commonText.appDeletedToast
|
||||||
|
);
|
||||||
cy.wait("@appDeleted");
|
cy.wait("@appDeleted");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -394,39 +397,37 @@ Cypress.Commands.add("getPosition", (componentName) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add("defaultWorkspaceLogin", () => {
|
Cypress.Commands.add("defaultWorkspaceLogin", () => {
|
||||||
cy.apiLogin();
|
cy.task("dbConnection", {
|
||||||
|
dbconfig: Cypress.env("app_db"),
|
||||||
|
sql: `
|
||||||
|
SELECT id FROM organizations WHERE name = 'My workspace';`,
|
||||||
|
}).then((resp) => {
|
||||||
|
const workspaceId = resp.rows[0].id;
|
||||||
|
|
||||||
// cy.intercept("GET", API_ENDPOINT).as("library_apps");
|
cy.apiLogin(
|
||||||
cy.visit("/my-workspace");
|
"dev@tooljet.io",
|
||||||
cy.wait(2000)
|
"password",
|
||||||
cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
|
workspaceId,
|
||||||
// cy.wait("@library_apps");
|
"/my-workspace"
|
||||||
|
).then(() => {
|
||||||
|
cy.visit("/");
|
||||||
|
cy.wait(2000);
|
||||||
|
cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add(
|
Cypress.Commands.add("visitSlug", ({ actualUrl }) => {
|
||||||
"visitSlug",
|
cy.visit(actualUrl);
|
||||||
({
|
cy.wait(1000);
|
||||||
actualUrl,
|
|
||||||
errorUrls = [
|
cy.url().then((currentUrl) => {
|
||||||
`${Cypress.config("baseUrl")}/error/unknown`,
|
if (currentUrl !== actualUrl) {
|
||||||
`${Cypress.config("baseUrl")}/error/restricted`,
|
cy.visit(actualUrl);
|
||||||
],
|
cy.wait(1000);
|
||||||
}) => {
|
|
||||||
if (!actualUrl) {
|
|
||||||
throw new Error("actualUrl is required for visitSlug command.");
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
cy.visit(actualUrl);
|
});
|
||||||
|
|
||||||
cy.url().then((url) => {
|
|
||||||
if (errorUrls.includes(url)) {
|
|
||||||
cy.log(`Navigation resulted in error URL: ${url}. Retrying...`);
|
|
||||||
cy.visit(actualUrl);
|
|
||||||
cy.wait(1000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
Cypress.Commands.add("releaseApp", () => {
|
Cypress.Commands.add("releaseApp", () => {
|
||||||
|
|
@ -513,13 +514,58 @@ Cypress.Commands.overwrite(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Cypress.Commands.add("installMarketplacePlugin", (pluginName) => {
|
||||||
|
const MARKETPLACE_URL = `${Cypress.config("baseUrl")}/integrations/marketplace`;
|
||||||
|
|
||||||
|
cy.visit(MARKETPLACE_URL);
|
||||||
|
cy.wait(1000);
|
||||||
|
|
||||||
|
cy.get('[data-cy="-list-item"]').eq(0).click();
|
||||||
|
cy.wait(1000);
|
||||||
|
|
||||||
|
cy.get("body").then(($body) => {
|
||||||
|
if ($body.find(".plugins-card").length === 0) {
|
||||||
|
cy.log("No plugins found, proceeding to install...");
|
||||||
|
installPlugin(pluginName);
|
||||||
|
} else {
|
||||||
|
cy.get(".plugins-card").then(($cards) => {
|
||||||
|
const isInstalled = $cards.toArray().some((card) => {
|
||||||
|
return (
|
||||||
|
Cypress.$(card)
|
||||||
|
.find(".font-weight-medium.text-capitalize")
|
||||||
|
.text()
|
||||||
|
.trim() === pluginName
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isInstalled) {
|
||||||
|
cy.log(`${pluginName} is already installed. Skipping installation.`);
|
||||||
|
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||||
|
} else {
|
||||||
|
installPlugin(pluginName);
|
||||||
|
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function installPlugin (pluginName) {
|
||||||
|
cy.get('[data-cy="-list-item"]').eq(1).click();
|
||||||
|
cy.wait(1000);
|
||||||
|
|
||||||
|
cy.contains(".plugins-card", pluginName).within(() => {
|
||||||
|
cy.get(".marketplace-install").click();
|
||||||
|
cy.wait(1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Cypress.Commands.add("verifyElement", (selector, text, eqValue) => {
|
Cypress.Commands.add("verifyElement", (selector, text, eqValue) => {
|
||||||
const element =
|
const element =
|
||||||
eqValue !== undefined ? cy.get(selector).eq(eqValue) : cy.get(selector);
|
eqValue !== undefined ? cy.get(selector).eq(eqValue) : cy.get(selector);
|
||||||
element.should("be.visible").and("have.text", text);
|
element.should("be.visible").and("have.text", text);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Cypress.Commands.add("getAppId", (appName) => {
|
Cypress.Commands.add("getAppId", (appName) => {
|
||||||
cy.task("dbConnection", {
|
cy.task("dbConnection", {
|
||||||
dbconfig: Cypress.env("app_db"),
|
dbconfig: Cypress.env("app_db"),
|
||||||
|
|
@ -529,3 +575,33 @@ Cypress.Commands.add("getAppId", (appName) => {
|
||||||
return appId;
|
return appId;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Cypress.Commands.add("uninstallMarketplacePlugin", (pluginName) => {
|
||||||
|
const MARKETPLACE_URL = `${Cypress.config("baseUrl")}/integrations/marketplace`;
|
||||||
|
|
||||||
|
cy.visit(MARKETPLACE_URL);
|
||||||
|
cy.wait(1000);
|
||||||
|
|
||||||
|
cy.get('[data-cy="-list-item"]').eq(0).click();
|
||||||
|
cy.wait(1000);
|
||||||
|
|
||||||
|
cy.get(".plugins-card").each(($card) => {
|
||||||
|
cy.wrap($card)
|
||||||
|
.find(".font-weight-medium.text-capitalize")
|
||||||
|
.invoke("text")
|
||||||
|
.then((text) => {
|
||||||
|
if (text.trim() === pluginName) {
|
||||||
|
cy.wrap($card).find(".link-primary").contains("Remove").click();
|
||||||
|
cy.wait(1000);
|
||||||
|
|
||||||
|
cy.get('[data-cy="delete-plugin-title"]').should("be.visible");
|
||||||
|
cy.get('[data-cy="yes-button"]').click();
|
||||||
|
cy.wait(2000);
|
||||||
|
|
||||||
|
cy.log(`${pluginName} has been successfully uninstalled.`);
|
||||||
|
} else {
|
||||||
|
cy.log(`${pluginName} is not installed. Skipping uninstallation.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ export const commonSelectors = {
|
||||||
toastMessage: ".go3958317564",
|
toastMessage: ".go3958317564",
|
||||||
oldToastMessage: ".go318386747",
|
oldToastMessage: ".go318386747",
|
||||||
appSlugAccept: '[data-cy="app-slug-accepted-label"]',
|
appSlugAccept: '[data-cy="app-slug-accepted-label"]',
|
||||||
newToastMessage: '.drawer-container > [style="position: fixed; z-index: 9999; inset: 16px; pointer-events: none;"] > .go4109123758 > .go2072408551 > .go3958317564',
|
newToastMessage:
|
||||||
|
'.drawer-container > [style="position: fixed; z-index: 9999; inset: 16px; pointer-events: none;"] > .go4109123758 > .go2072408551 > .go3958317564',
|
||||||
toastCloseButton: '[data-cy="toast-close-button"]',
|
toastCloseButton: '[data-cy="toast-close-button"]',
|
||||||
editButton: "[data-cy=edit-button]",
|
editButton: "[data-cy=edit-button]",
|
||||||
workspaceConstantNameInput: '[data-cy="name-input-field"]',
|
workspaceConstantNameInput: '[data-cy="name-input-field"]',
|
||||||
|
|
@ -18,7 +19,7 @@ export const commonSelectors = {
|
||||||
appCardOptionsButton: "[data-cy=app-card-menu-icon]",
|
appCardOptionsButton: "[data-cy=app-card-menu-icon]",
|
||||||
autoSave: "[data-cy=autosave-indicator]",
|
autoSave: "[data-cy=autosave-indicator]",
|
||||||
nameInputFieldd: "[data-cy=name-input-field]",
|
nameInputFieldd: "[data-cy=name-input-field]",
|
||||||
valueInputFieldd: '[data-cy=value-input-field]',
|
valueInputFieldd: "[data-cy=value-input-field]",
|
||||||
skipButton: ".driver-close-btn",
|
skipButton: ".driver-close-btn",
|
||||||
skipInstallationModal: "[data-cy=skip-button]",
|
skipInstallationModal: "[data-cy=skip-button]",
|
||||||
homePageLogo: "[data-cy=home-page-logo]",
|
homePageLogo: "[data-cy=home-page-logo]",
|
||||||
|
|
@ -395,7 +396,7 @@ export const commonWidgetSelector = {
|
||||||
modalCloseButton: '[data-cy="modal-close-button"]',
|
modalCloseButton: '[data-cy="modal-close-button"]',
|
||||||
iframeLinkLabel: '[data-cy="iframe-link-label"]',
|
iframeLinkLabel: '[data-cy="iframe-link-label"]',
|
||||||
ifameLinkCopyButton: '[data-cy="iframe-link-copy-button"]',
|
ifameLinkCopyButton: '[data-cy="iframe-link-copy-button"]',
|
||||||
appSlugLabel: '[data-cy="input-field-label"]',
|
appSlugLabel: '[data-cy="unique-app-slug-field-label"]',
|
||||||
appSlugInput: '[data-cy="app-slug-input-field"]',
|
appSlugInput: '[data-cy="app-slug-input-field"]',
|
||||||
appSlugInfoLabel: '[data-cy="helper-text"]',
|
appSlugInfoLabel: '[data-cy="helper-text"]',
|
||||||
appLinkLabel: '[data-cy="app-link-label"]',
|
appLinkLabel: '[data-cy="app-link-label"]',
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export const restAPISelector = {
|
||||||
return `[data-cy="${cyParamName(header)}-delete-button-${cyParamName(index)}"]`;
|
return `[data-cy="${cyParamName(header)}-delete-button-${cyParamName(index)}"]`;
|
||||||
},
|
},
|
||||||
addMoreButton: (header) => {
|
addMoreButton: (header) => {
|
||||||
return `[data-cy="${cyParamName(header)}-add-more-button"]`;
|
return `[data-cy="${cyParamName(header)}-add-button"]`;
|
||||||
},
|
},
|
||||||
dropdownLabel: (label) => {
|
dropdownLabel: (label) => {
|
||||||
return `[data-cy="${cyParamName(label)}-dropdown-label"]`;
|
return `[data-cy="${cyParamName(label)}-dropdown-label"]`;
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ export const postgreSqlText = {
|
||||||
|
|
||||||
allDataSources: () => {
|
allDataSources: () => {
|
||||||
return Cypress.env("marketplace_action")
|
return Cypress.env("marketplace_action")
|
||||||
? "All data sources (44)"
|
? "All data sources (45)"
|
||||||
: "All data sources (45)";
|
: "All data sources (43)";
|
||||||
},
|
},
|
||||||
commonlyUsed: "Commonly used (5)",
|
commonlyUsed: "Commonly used (5)",
|
||||||
allDatabase: () => {
|
allDatabase: () => {
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,7 @@ export const editVersionText = {
|
||||||
|
|
||||||
export const deleteVersionText = {
|
export const deleteVersionText = {
|
||||||
deleteModalText: (text) => {
|
deleteModalText: (text) => {
|
||||||
// return `Are you sure you want to delete this version - ${cyParamName(
|
return `Are you sure you want to delete this version - ${cyParamName(
|
||||||
// text
|
|
||||||
// )}?`;
|
|
||||||
|
|
||||||
return `Deleting a version will permanently remove it from all environments.Are you sure you want to delete this version - ${cyParamName(
|
|
||||||
text
|
text
|
||||||
)}?`;
|
)}?`;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import {
|
||||||
addSupportCSAData,
|
addSupportCSAData,
|
||||||
} from "Support/utils/events";
|
} from "Support/utils/events";
|
||||||
|
|
||||||
describe("Editor- Test Button widget", () => {
|
describe("Editor- Test Button widget ", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.apiCreateApp(`${fake.companyName}-button-App`);
|
cy.apiCreateApp(`${fake.companyName}-button-App`);
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ describe("Add all Data sources to app", () => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify global data source page", () => {
|
it.skip("Should verify global data source page", () => {
|
||||||
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
|
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
|
||||||
cy.visit(`${data.workspaceSlug}`);
|
cy.visit(`${data.workspaceSlug}`);
|
||||||
|
|
||||||
|
|
@ -87,7 +87,7 @@ describe("Add all Data sources to app", () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should add all data sources in data source page", () => {
|
it.skip("Should add all data sources in data source page", () => {
|
||||||
cy.visit(`${data.workspaceSlug}`);
|
cy.visit(`${data.workspaceSlug}`);
|
||||||
|
|
||||||
dataSources.forEach((dsName) => {
|
dataSources.forEach((dsName) => {
|
||||||
|
|
@ -109,7 +109,7 @@ describe("Add all Data sources to app", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should add all data sources in the app", () => {
|
it.skip("Should add all data sources in the app", () => {
|
||||||
cy.visit(`${data.workspaceSlug}`);
|
cy.visit(`${data.workspaceSlug}`);
|
||||||
cy.get(commonSelectors.dashboardIcon).click();
|
cy.get(commonSelectors.dashboardIcon).click();
|
||||||
cy.get(commonSelectors.appCreateButton).click();
|
cy.get(commonSelectors.appCreateButton).click();
|
||||||
|
|
@ -135,7 +135,7 @@ describe("Add all Data sources to app", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should install all makretplace plugins and add them into the app", () => {
|
it.skip("Should install all makretplace plugins and add them into the app", () => {
|
||||||
cy.visit(`${data.workspaceSlug}`);
|
cy.visit(`${data.workspaceSlug}`);
|
||||||
const dataSourcesMarketplace = [
|
const dataSourcesMarketplace = [
|
||||||
"Plivo",
|
"Plivo",
|
||||||
|
|
@ -189,12 +189,15 @@ describe("Add all Data sources to app", () => {
|
||||||
cy.wrap(dataSourcesMarketplace).each((dsName) => {
|
cy.wrap(dataSourcesMarketplace).each((dsName) => {
|
||||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||||
selectAndAddDataSource("databases", dsName, dsName);
|
selectAndAddDataSource("databases", dsName, dsName);
|
||||||
cy.wait(500);
|
cy.wait(1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get(commonSelectors.dashboardIcon).click();
|
cy.get(commonSelectors.dashboardIcon).should("be.visible").click();
|
||||||
cy.get(commonSelectors.appCreateButton).click();
|
cy.get(commonSelectors.appCreateButton).should("be.visible").click();
|
||||||
cy.get(commonSelectors.appNameInput).click().type(data.dsNamefake1);
|
cy.get(commonSelectors.appNameInput)
|
||||||
|
.should("be.visible")
|
||||||
|
.click()
|
||||||
|
.type(data.dsNamefake1);
|
||||||
cy.get(commonSelectors.createAppButton).click();
|
cy.get(commonSelectors.createAppButton).click();
|
||||||
cy.skipWalkthrough();
|
cy.skipWalkthrough();
|
||||||
|
|
||||||
|
|
@ -203,7 +206,7 @@ describe("Add all Data sources to app", () => {
|
||||||
cy.get(".css-4e90k9").type(
|
cy.get(".css-4e90k9").type(
|
||||||
`cypress-${cyParamName(dsName)}-${cyParamName(dsName)}`
|
`cypress-${cyParamName(dsName)}-${cyParamName(dsName)}`
|
||||||
);
|
);
|
||||||
cy.wait(500);
|
cy.wait(1000);
|
||||||
|
|
||||||
cy.contains(
|
cy.contains(
|
||||||
`[id*="react-select-"]`,
|
`[id*="react-select-"]`,
|
||||||
|
|
@ -212,7 +215,7 @@ describe("Add all Data sources to app", () => {
|
||||||
.should("be.visible")
|
.should("be.visible")
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
cy.wait(500);
|
cy.wait(1000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,14 @@ import {
|
||||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||||
|
|
||||||
const data = {};
|
const data = {};
|
||||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
|
||||||
data.dsName1 = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
data.queryName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
|
|
||||||
describe("Data source Airtable", () => {
|
describe("Data source Airtable", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
|
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on connection AirTable form", () => {
|
it("Should verify elements on connection AirTable form", () => {
|
||||||
|
|
@ -199,7 +200,7 @@ describe("Data source Airtable", () => {
|
||||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||||
cy.get(".css-4e90k9").type(`${data.dsName}`);
|
cy.get(".css-4e90k9").type(`${data.dsName}`);
|
||||||
cy.contains(`[id*="react-select-"]`, data.dsName).click();
|
cy.contains(`[id*="react-select-"]`, data.dsName).click();
|
||||||
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName1);
|
cy.get('[data-cy="query-rename-input"]').clear().type(data.queryName);
|
||||||
|
|
||||||
cy.get(airTableSelector.operationSelectDropdown)
|
cy.get(airTableSelector.operationSelectDropdown)
|
||||||
.click()
|
.click()
|
||||||
|
|
@ -225,7 +226,7 @@ describe("Data source Airtable", () => {
|
||||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||||
cy.verifyToastMessage(
|
cy.verifyToastMessage(
|
||||||
commonSelectors.toastMessage,
|
commonSelectors.toastMessage,
|
||||||
`Query (${data.dsName1}) completed.`
|
`Query (${data.queryName}) completed.`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Verify Delete record operation
|
// Verify Delete record operation
|
||||||
|
|
@ -277,7 +278,7 @@ describe("Data source Airtable", () => {
|
||||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||||
cy.verifyToastMessage(
|
cy.verifyToastMessage(
|
||||||
commonSelectors.toastMessage,
|
commonSelectors.toastMessage,
|
||||||
`Query (${data.dsName1}) completed.`
|
`Query (${data.queryName}) completed.`
|
||||||
);
|
);
|
||||||
deleteAppandDatasourceAfterExecution(
|
deleteAppandDatasourceAfterExecution(
|
||||||
data.dsName,
|
data.dsName,
|
||||||
|
|
@ -20,15 +20,15 @@ import {
|
||||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||||
|
|
||||||
const data = {};
|
const data = {};
|
||||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
|
||||||
|
|
||||||
describe("Data source amazon athena", () => {
|
describe("Data source amazon athena", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
|
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on amazon athena connection form", () => {
|
it.skip("Should verify elements on amazon athena connection form", () => {
|
||||||
const Accesskey = Cypress.env("amazonathena_accessKey");
|
const Accesskey = Cypress.env("amazonathena_accessKey");
|
||||||
const Secretkey = Cypress.env("amazonathena_secretKey");
|
const Secretkey = Cypress.env("amazonathena_secretKey");
|
||||||
const DbName = Cypress.env("amazonathena_DbName");
|
const DbName = Cypress.env("amazonathena_DbName");
|
||||||
|
|
@ -97,7 +97,7 @@ describe("Data source amazon athena", () => {
|
||||||
deleteDatasource(`cypress-${data.dsName}-Amazon-Athena`);
|
deleteDatasource(`cypress-${data.dsName}-Amazon-Athena`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify the functionality of amazon athena connection form.", () => {
|
it.skip("Should verify the functionality of amazon athena connection form.", () => {
|
||||||
const Accesskey = Cypress.env("amazonathena_accessKey");
|
const Accesskey = Cypress.env("amazonathena_accessKey");
|
||||||
const Secretkey = Cypress.env("amazonathena_secretKey");
|
const Secretkey = Cypress.env("amazonathena_secretKey");
|
||||||
const DbName = Cypress.env("amazonathena_DbName");
|
const DbName = Cypress.env("amazonathena_DbName");
|
||||||
|
|
@ -134,7 +134,7 @@ describe("Data source amazon athena", () => {
|
||||||
deleteDatasource(`cypress-${data.dsName}-amazon-Athena`);
|
deleteDatasource(`cypress-${data.dsName}-amazon-Athena`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should able to run the query with valid conection", () => {
|
it.skip("Should able to run the query with valid conection", () => {
|
||||||
const Accesskey = Cypress.env("amazonathena_accessKey");
|
const Accesskey = Cypress.env("amazonathena_accessKey");
|
||||||
const Secretkey = Cypress.env("amazonathena_secretKey");
|
const Secretkey = Cypress.env("amazonathena_secretKey");
|
||||||
const DbName = Cypress.env("amazonathena_DbName");
|
const DbName = Cypress.env("amazonathena_DbName");
|
||||||
|
|
@ -188,11 +188,13 @@ describe("Data source amazon athena", () => {
|
||||||
cy.get(".css-4e90k9").type(`${data.dsName}`);
|
cy.get(".css-4e90k9").type(`${data.dsName}`);
|
||||||
cy.contains(`[id*="react-select-"]`, data.dsName).click();
|
cy.contains(`[id*="react-select-"]`, data.dsName).click();
|
||||||
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
|
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
|
||||||
|
cy.get(`[data-cy="list-query-${data.dsName}"]`).should("be.visible");
|
||||||
cy.get('[data-cy="query-input-field"]').clearAndTypeOnCodeMirror(
|
cy.get('[data-cy="query-input-field"]').clearAndTypeOnCodeMirror(
|
||||||
"SHOW DATABASES;"
|
"SHOW DATABASES;"
|
||||||
);
|
);
|
||||||
|
cy.get(
|
||||||
|
'[data-cy="query-input-field"] >>> .cm-editor >> .cm-content > .cm-line'
|
||||||
|
).should("have.text", "SHOW DATABASES;");
|
||||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||||
cy.verifyToastMessage(
|
cy.verifyToastMessage(
|
||||||
commonSelectors.toastMessage,
|
commonSelectors.toastMessage,
|
||||||
|
|
@ -20,15 +20,15 @@ import {
|
||||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||||
|
|
||||||
const data = {};
|
const data = {};
|
||||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
|
||||||
|
|
||||||
describe("Data source amazon ses", () => {
|
describe("Data source amazon ses", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
|
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on amazonses connection form", () => {
|
it.skip("Should verify elements on amazonses connection form", () => {
|
||||||
const Accesskey = Cypress.env("amazonSes_accessKey");
|
const Accesskey = Cypress.env("amazonSes_accessKey");
|
||||||
const Secretkey = Cypress.env("amazonSes_secretKey");
|
const Secretkey = Cypress.env("amazonSes_secretKey");
|
||||||
|
|
||||||
|
|
@ -80,7 +80,7 @@ describe("Data source amazon ses", () => {
|
||||||
deleteDatasource(`cypress-${data.dsName}-Amazon-ses`);
|
deleteDatasource(`cypress-${data.dsName}-Amazon-ses`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify the functionality of amazonses connection form.", () => {
|
it.skip("Should verify the functionality of amazonses connection form.", () => {
|
||||||
selectAndAddDataSource("databases", amazonSesText.AmazonSES, data.dsName);
|
selectAndAddDataSource("databases", amazonSesText.AmazonSES, data.dsName);
|
||||||
|
|
||||||
cy.get(".react-select__dropdown-indicator").eq(1).click();
|
cy.get(".react-select__dropdown-indicator").eq(1).click();
|
||||||
|
|
@ -112,7 +112,7 @@ describe("Data source amazon ses", () => {
|
||||||
deleteDatasource(`cypress-${data.dsName}-amazon-ses`);
|
deleteDatasource(`cypress-${data.dsName}-amazon-ses`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should able to run the query with valid conection", () => {
|
it.skip("Should able to run the query with valid conection", () => {
|
||||||
const email = "adish" + "@" + "tooljet.com";
|
const email = "adish" + "@" + "tooljet.com";
|
||||||
selectAndAddDataSource("databases", amazonSesText.AmazonSES, data.dsName);
|
selectAndAddDataSource("databases", amazonSesText.AmazonSES, data.dsName);
|
||||||
|
|
||||||
|
|
@ -20,15 +20,15 @@ import {
|
||||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||||
|
|
||||||
const data = {};
|
const data = {};
|
||||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
|
||||||
|
|
||||||
describe("Data source AppWrite", () => {
|
describe("Data source AppWrite", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
|
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on appwrite connection form", () => {
|
it.skip("Should verify elements on appwrite connection form", () => {
|
||||||
const Host = Cypress.env("appwrite_host");
|
const Host = Cypress.env("appwrite_host");
|
||||||
const ProjectID = Cypress.env("appwrite_projectID");
|
const ProjectID = Cypress.env("appwrite_projectID");
|
||||||
const DatabaseID = Cypress.env("appwrite_databaseID");
|
const DatabaseID = Cypress.env("appwrite_databaseID");
|
||||||
|
|
@ -100,7 +100,7 @@ describe("Data source AppWrite", () => {
|
||||||
deleteDatasource(`cypress-${data.dsName}-Appwrite`);
|
deleteDatasource(`cypress-${data.dsName}-Appwrite`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify the functionality of appwrite connection form.", () => {
|
it.skip("Should verify the functionality of appwrite connection form.", () => {
|
||||||
const Host = Cypress.env("appwrite_host");
|
const Host = Cypress.env("appwrite_host");
|
||||||
const ProjectID = Cypress.env("appwrite_projectID");
|
const ProjectID = Cypress.env("appwrite_projectID");
|
||||||
const DatabaseID = Cypress.env("appwrite_databaseID");
|
const DatabaseID = Cypress.env("appwrite_databaseID");
|
||||||
|
|
@ -150,7 +150,7 @@ describe("Data source AppWrite", () => {
|
||||||
deleteDatasource(`cypress-${data.dsName}-Appwrite`);
|
deleteDatasource(`cypress-${data.dsName}-Appwrite`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should be able to run the query with a valid connection", () => {
|
it.skip("Should be able to run the query with a valid connection", () => {
|
||||||
const Host = Cypress.env("appwrite_host");
|
const Host = Cypress.env("appwrite_host");
|
||||||
const ProjectID = Cypress.env("appwrite_projectID");
|
const ProjectID = Cypress.env("appwrite_projectID");
|
||||||
const DatabaseID = Cypress.env("appwrite_databaseID");
|
const DatabaseID = Cypress.env("appwrite_databaseID");
|
||||||
|
|
@ -20,15 +20,15 @@ import {
|
||||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||||
|
|
||||||
const data = {};
|
const data = {};
|
||||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
|
||||||
|
|
||||||
describe("Data source AWS Lambda", () => {
|
describe("Data source AWS Lambda", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
|
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on AWS Lambda connection form", () => {
|
it.skip("Should verify elements on AWS Lambda connection form", () => {
|
||||||
const Accesskey = Cypress.env("awslamda_access");
|
const Accesskey = Cypress.env("awslamda_access");
|
||||||
const Secretkey = Cypress.env("awslamda_secret");
|
const Secretkey = Cypress.env("awslamda_secret");
|
||||||
|
|
||||||
|
|
@ -80,9 +80,10 @@ describe("Data source AWS Lambda", () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
deleteDatasource(`cypress-${data.dsName}-aws-lambda`);
|
deleteDatasource(`cypress-${data.dsName}-aws-lambda`);
|
||||||
|
cy.uninstallMarketplacePlugin("AWS Lambda");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify the functionality of AWS Lambda connection form", () => {
|
it.skip("Should verify the functionality of AWS Lambda connection form", () => {
|
||||||
const Accesskey = Cypress.env("awslamda_access");
|
const Accesskey = Cypress.env("awslamda_access");
|
||||||
const Secretkey = Cypress.env("awslamda_secret");
|
const Secretkey = Cypress.env("awslamda_secret");
|
||||||
|
|
||||||
|
|
@ -113,9 +114,10 @@ describe("Data source AWS Lambda", () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
deleteDatasource(`cypress-${data.dsName}-aws-lambda`);
|
deleteDatasource(`cypress-${data.dsName}-aws-lambda`);
|
||||||
|
cy.uninstallMarketplacePlugin("AWS Lambda");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should able to run the query with valid conection", () => {
|
it.skip("Should able to run the query with valid conection", () => {
|
||||||
const Accesskey = Cypress.env("awslamda_access");
|
const Accesskey = Cypress.env("awslamda_access");
|
||||||
const Secretkey = Cypress.env("awslamda_secret");
|
const Secretkey = Cypress.env("awslamda_secret");
|
||||||
|
|
||||||
|
|
@ -21,15 +21,15 @@ import {
|
||||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||||
|
|
||||||
const data = {};
|
const data = {};
|
||||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
|
||||||
|
|
||||||
describe("Data source AWS Textract", () => {
|
describe("Data source AWS Textract", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
|
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on AWS Textract connection form", () => {
|
it.skip("Should verify elements on AWS Textract connection form", () => {
|
||||||
const Accesskey = Cypress.env("awstextract_access");
|
const Accesskey = Cypress.env("awstextract_access");
|
||||||
const Secretkey = Cypress.env("awstextract_secret");
|
const Secretkey = Cypress.env("awstextract_secret");
|
||||||
|
|
||||||
|
|
@ -87,7 +87,7 @@ describe("Data source AWS Textract", () => {
|
||||||
deleteDatasource(`cypress-${data.dsName}-aws-textract`);
|
deleteDatasource(`cypress-${data.dsName}-aws-textract`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify functionality of AWS Textract connection form", () => {
|
it.skip("Should verify functionality of AWS Textract connection form", () => {
|
||||||
const Accesskey = Cypress.env("awstextract_access");
|
const Accesskey = Cypress.env("awstextract_access");
|
||||||
const Secretkey = Cypress.env("awstextract_secret");
|
const Secretkey = Cypress.env("awstextract_secret");
|
||||||
|
|
||||||
|
|
@ -122,9 +122,10 @@ describe("Data source AWS Textract", () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
deleteDatasource(`cypress-${data.dsName}-aws-textract`);
|
deleteDatasource(`cypress-${data.dsName}-aws-textract`);
|
||||||
|
cy.uninstallMarketplacePlugin("AWS Textract");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should able to run the query with valid conection", () => {
|
it.skip("Should able to run the query with valid conection", () => {
|
||||||
const Accesskey = Cypress.env("awstextract_access");
|
const Accesskey = Cypress.env("awstextract_access");
|
||||||
const Secretkey = Cypress.env("awstextract_secret");
|
const Secretkey = Cypress.env("awstextract_secret");
|
||||||
|
|
||||||
|
|
@ -17,8 +17,8 @@ data.customText = fake.randomSentence;
|
||||||
|
|
||||||
describe("Data source Azure Blob Storage", () => {
|
describe("Data source Azure Blob Storage", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
|
||||||
|
|
@ -20,15 +20,15 @@ import {
|
||||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||||
|
|
||||||
const data = {};
|
const data = {};
|
||||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
|
||||||
|
|
||||||
describe("Data source baserow", () => {
|
describe("Data source baserow", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
|
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on baserow connection form", () => {
|
it.skip("Should verify elements on baserow connection form", () => {
|
||||||
const Apikey = Cypress.env("baserow_apikey");
|
const Apikey = Cypress.env("baserow_apikey");
|
||||||
|
|
||||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||||
|
|
@ -78,7 +78,7 @@ describe("Data source baserow", () => {
|
||||||
deleteDatasource(`cypress-${data.dsName}-baserow`);
|
deleteDatasource(`cypress-${data.dsName}-baserow`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify the functionality of baserow connection form.", () => {
|
it.skip("Should verify the functionality of baserow connection form.", () => {
|
||||||
const Apikey = Cypress.env("baserow_apikey");
|
const Apikey = Cypress.env("baserow_apikey");
|
||||||
|
|
||||||
selectAndAddDataSource("databases", baseRowText.baserow, data.dsName);
|
selectAndAddDataSource("databases", baseRowText.baserow, data.dsName);
|
||||||
|
|
@ -103,7 +103,7 @@ describe("Data source baserow", () => {
|
||||||
deleteDatasource(`cypress-${data.dsName}-baserow`);
|
deleteDatasource(`cypress-${data.dsName}-baserow`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should be able to run the query with a valid connection", () => {
|
it.skip("Should be able to run the query with a valid connection", () => {
|
||||||
const baserowTableID = Cypress.env("baserow_tableid");
|
const baserowTableID = Cypress.env("baserow_tableid");
|
||||||
const baserowRowID = Cypress.env("baserow_rowid");
|
const baserowRowID = Cypress.env("baserow_rowid");
|
||||||
const Apikey = Cypress.env("baserow_apikey");
|
const Apikey = Cypress.env("baserow_apikey");
|
||||||
|
|
@ -16,8 +16,8 @@ const data = {};
|
||||||
|
|
||||||
describe("Data source BigQuery", () => {
|
describe("Data source BigQuery", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
@ -19,8 +19,8 @@ const data = {};
|
||||||
|
|
||||||
describe("Data sources", () => {
|
describe("Data sources", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ const data = {};
|
||||||
|
|
||||||
describe("Data sources", () => {
|
describe("Data sources", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ const data = {};
|
||||||
|
|
||||||
describe("Data sources", () => {
|
describe("Data sources", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ const data = {};
|
||||||
|
|
||||||
describe("Data source DynamoDB", () => {
|
describe("Data source DynamoDB", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,12 @@ import {
|
||||||
const data = {};
|
const data = {};
|
||||||
describe("Data source Elasticsearch", () => {
|
describe("Data source Elasticsearch", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.lastName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
|
||||||
|
data.dataSourceName = fake.lastName
|
||||||
|
.toLowerCase()
|
||||||
|
.replaceAll("[^A-Za-z]", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on Elasticsearch connection form", () => {
|
it("Should verify elements on Elasticsearch connection form", () => {
|
||||||
|
|
@ -123,14 +126,14 @@ describe("Data source Elasticsearch", () => {
|
||||||
"have.text",
|
"have.text",
|
||||||
elasticsearchText.errorConnectionRefused
|
elasticsearchText.errorConnectionRefused
|
||||||
);
|
);
|
||||||
deleteDatasource(`cypress-${data.lastName}-elasticsearch`);
|
deleteDatasource(`cypress-${data.dataSourceName}-elasticsearch`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify the functionality of Elasticsearch connection form.", () => {
|
it("Should verify the functionality of Elasticsearch connection form.", () => {
|
||||||
selectAndAddDataSource(
|
selectAndAddDataSource(
|
||||||
"databases",
|
"databases",
|
||||||
elasticsearchText.elasticSearch,
|
elasticsearchText.elasticSearch,
|
||||||
data.lastName
|
data.dataSourceName
|
||||||
);
|
);
|
||||||
|
|
||||||
fillDataSourceTextField(
|
fillDataSourceTextField(
|
||||||
|
|
@ -210,12 +213,12 @@ describe("Data source Elasticsearch", () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
cy.get(
|
cy.get(
|
||||||
`[data-cy="cypress-${data.lastName}-elasticsearch-button"]`
|
`[data-cy="cypress-${data.dataSourceName}-elasticsearch-button"]`
|
||||||
).verifyVisibleElement(
|
).verifyVisibleElement(
|
||||||
"have.text",
|
"have.text",
|
||||||
`cypress-${data.lastName}-elasticsearch`
|
`cypress-${data.dataSourceName}-elasticsearch`
|
||||||
);
|
);
|
||||||
|
|
||||||
deleteDatasource(`cypress-${data.lastName}-elasticsearch`);
|
deleteDatasource(`cypress-${data.dataSourceName}-elasticsearch`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ const data = {};
|
||||||
|
|
||||||
describe("Data source Firestore", () => {
|
describe("Data source Firestore", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,12 @@ import {
|
||||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||||
|
|
||||||
const data = {};
|
const data = {};
|
||||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
|
||||||
|
|
||||||
describe("Data source GraphQL", () => {
|
describe("Data source GraphQL", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
|
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on GraphQL connection form", () => {
|
it("Should verify elements on GraphQL connection form", () => {
|
||||||
|
|
@ -20,13 +20,13 @@ import {
|
||||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||||
|
|
||||||
const data = {};
|
const data = {};
|
||||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
|
||||||
data.dsName1 = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
data.dsName1 = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
|
|
||||||
describe("Data source HarperDB", () => {
|
describe("Data source HarperDB", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
|
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on HarperDB connection form", () => {
|
it("Should verify elements on HarperDB connection form", () => {
|
||||||
|
|
@ -102,6 +102,7 @@ describe("Data source HarperDB", () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
deleteDatasource(`cypress-${data.dsName}-HarperDB`);
|
deleteDatasource(`cypress-${data.dsName}-HarperDB`);
|
||||||
|
cy.uninstallMarketplacePlugin("HarperDB");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify functionality of HarperDB connection form", () => {
|
it("Should verify functionality of HarperDB connection form", () => {
|
||||||
|
|
@ -156,9 +157,10 @@ describe("Data source HarperDB", () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
deleteDatasource(`cypress-${data.dsName}-HarperDB`);
|
deleteDatasource(`cypress-${data.dsName}-HarperDB`);
|
||||||
|
cy.uninstallMarketplacePlugin("HarperDB");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should be able to run the query with a valid connection", () => {
|
it.skip("Should be able to run the query with a valid connection", () => {
|
||||||
const Host = Cypress.env("harperdb_host");
|
const Host = Cypress.env("harperdb_host");
|
||||||
const Port = Cypress.env("harperdb_port");
|
const Port = Cypress.env("harperdb_port");
|
||||||
const Username = Cypress.env("harperdb_username");
|
const Username = Cypress.env("harperdb_username");
|
||||||
|
|
@ -23,8 +23,8 @@ const data = {};
|
||||||
|
|
||||||
describe("Data sources", () => {
|
describe("Data sources", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ const data = {};
|
||||||
|
|
||||||
describe("Data sources", () => {
|
describe("Data sources", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,12 @@ import {
|
||||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||||
|
|
||||||
const data = {};
|
const data = {};
|
||||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
|
||||||
|
|
||||||
describe("Data source minio", () => {
|
describe("Data source minio", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
|
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on minio connection form", () => {
|
it("Should verify elements on minio connection form", () => {
|
||||||
|
|
@ -157,7 +157,7 @@ describe("Data source minio", () => {
|
||||||
deleteDatasource(`cypress-${data.dsName}-minio`);
|
deleteDatasource(`cypress-${data.dsName}-minio`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should be able to run the query with a valid connection", () => {
|
it.skip("Should be able to run the query with a valid connection", () => {
|
||||||
const Host = Cypress.env("minio_host");
|
const Host = Cypress.env("minio_host");
|
||||||
const Port = Cypress.env("minio_port");
|
const Port = Cypress.env("minio_port");
|
||||||
const AccessKey = Cypress.env("minio_accesskey");
|
const AccessKey = Cypress.env("minio_accesskey");
|
||||||
|
|
@ -27,8 +27,8 @@ const data = {};
|
||||||
|
|
||||||
describe("Data source MongoDB", () => {
|
describe("Data source MongoDB", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
@ -133,7 +133,7 @@ describe("Data source MongoDB", () => {
|
||||||
"have.text",
|
"have.text",
|
||||||
mongoDbText.errorConnectionRefused
|
mongoDbText.errorConnectionRefused
|
||||||
);
|
);
|
||||||
cy.get('[data-cy="query-select-dropdown"]').type(
|
cy.get('[data-cy="connection-type-select-dropdown"]').type(
|
||||||
mongoDbText.optionConnectUsingConnectionString
|
mongoDbText.optionConnectUsingConnectionString
|
||||||
);
|
);
|
||||||
cy.get('[data-cy="label-connection-string"]').verifyVisibleElement(
|
cy.get('[data-cy="label-connection-string"]').verifyVisibleElement(
|
||||||
|
|
@ -26,8 +26,8 @@ const data = {};
|
||||||
|
|
||||||
describe("Data sources MySql", () => {
|
describe("Data sources MySql", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
@ -15,7 +15,7 @@ import {
|
||||||
|
|
||||||
describe("Data sources", () => {
|
describe("Data sources", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
// cy.createApp();
|
// cy.createApp();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,14 @@ const data = {};
|
||||||
|
|
||||||
describe("Data sources", () => {
|
describe("Data sources", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on connection form", () => {
|
it.skip("Should verify elements on connection form", () => {
|
||||||
cy.log(process.env.NODE_ENV);
|
cy.log(process.env.NODE_ENV);
|
||||||
cy.log(postgreSqlText.allDatabase());
|
cy.log(postgreSqlText.allDatabase());
|
||||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||||
|
|
@ -140,7 +140,7 @@ describe("Data sources", () => {
|
||||||
deleteDatasource(`cypress-${data.dataSourceName}-postgresql`);
|
deleteDatasource(`cypress-${data.dataSourceName}-postgresql`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify the functionality of PostgreSQL connection form.", () => {
|
it.skip("Should verify the functionality of PostgreSQL connection form.", () => {
|
||||||
selectAndAddDataSource(
|
selectAndAddDataSource(
|
||||||
"databases",
|
"databases",
|
||||||
postgreSqlText.postgreSQL,
|
postgreSqlText.postgreSQL,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
describe("Data source Redis", () => {
|
describe("Data source Redis", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on connection Redis form", () => {
|
it("Should verify elements on connection Redis form", () => {
|
||||||
|
|
@ -215,7 +215,7 @@ describe("Data source Redis", () => {
|
||||||
deleteDatasource(`cypress-${data.dsName}-redis`);
|
deleteDatasource(`cypress-${data.dsName}-redis`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should able to run the query with valid conection", () => {
|
it.skip("Should able to run the query with valid conection", () => {
|
||||||
selectAndAddDataSource("databases", redisText.redis, data.dsName);
|
selectAndAddDataSource("databases", redisText.redis, data.dsName);
|
||||||
|
|
||||||
fillDataSourceTextField(
|
fillDataSourceTextField(
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ const clientAuthenticationDropdown =
|
||||||
describe("Data source Rest API", () => {
|
describe("Data source Rest API", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
@ -332,7 +332,6 @@ describe("Data source Rest API", () => {
|
||||||
deleteDatasource(`cypress-${data.dataSourceName}-restapi`);
|
deleteDatasource(`cypress-${data.dataSourceName}-restapi`);
|
||||||
});
|
});
|
||||||
it("Should verify basic connection for Rest API", () => {
|
it("Should verify basic connection for Rest API", () => {
|
||||||
const storedId = Cypress.env("storedId");
|
|
||||||
cy.apiCreateGDS(
|
cy.apiCreateGDS(
|
||||||
`${Cypress.env("server_host")}/api/data-sources`,
|
`${Cypress.env("server_host")}/api/data-sources`,
|
||||||
`cypress-${data.dataSourceName}-restapi`,
|
`cypress-${data.dataSourceName}-restapi`,
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ const data = {};
|
||||||
|
|
||||||
describe("Data sources", () => {
|
describe("Data sources", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ const data = {};
|
||||||
describe("Data sources AWS S3", () => {
|
describe("Data sources AWS S3", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import {
|
||||||
|
|
||||||
describe("Data sources", () => {
|
describe("Data sources", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
// cy.createApp();
|
// cy.createApp();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ const data = {};
|
||||||
|
|
||||||
describe("Data source SMTP", () => {
|
describe("Data source SMTP", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ import {
|
||||||
const data = {};
|
const data = {};
|
||||||
describe("Data sources", () => {
|
describe("Data sources", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ const data = {};
|
||||||
|
|
||||||
describe("Data sources", () => {
|
describe("Data sources", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
@ -21,15 +21,15 @@ import { dataSourceSelector } from "../../../../../constants/selectors/dataSourc
|
||||||
import { pluginSelectors } from "Selectors/plugins";
|
import { pluginSelectors } from "Selectors/plugins";
|
||||||
|
|
||||||
const data = {};
|
const data = {};
|
||||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
|
||||||
|
|
||||||
describe("Data source Twilio", () => {
|
describe("Data source Twilio", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.defaultWorkspaceLogin();
|
cy.visit("/");
|
||||||
|
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify elements on Twilio connection form", () => {
|
it.skip("Should verify elements on Twilio connection form", () => {
|
||||||
const AuthToken = Cypress.env("twilio_auth_token");
|
const AuthToken = Cypress.env("twilio_auth_token");
|
||||||
const AccountSID = Cypress.env("twilio_account_SID");
|
const AccountSID = Cypress.env("twilio_account_SID");
|
||||||
const MessageSID = Cypress.env("twilio_messaging_service_SID");
|
const MessageSID = Cypress.env("twilio_messaging_service_SID");
|
||||||
|
|
@ -89,7 +89,7 @@ describe("Data source Twilio", () => {
|
||||||
deleteDatasource(`cypress-${data.dsName}-twilio`);
|
deleteDatasource(`cypress-${data.dsName}-twilio`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should verify functionality of Twilio connection form", () => {
|
it.skip("Should verify functionality of Twilio connection form", () => {
|
||||||
const AuthToken = Cypress.env("twilio_auth_token");
|
const AuthToken = Cypress.env("twilio_auth_token");
|
||||||
const AccountSID = Cypress.env("twilio_account_SID");
|
const AccountSID = Cypress.env("twilio_account_SID");
|
||||||
const MessageSID = Cypress.env("twilio_messaging_service_SID");
|
const MessageSID = Cypress.env("twilio_messaging_service_SID");
|
||||||
|
|
@ -128,7 +128,7 @@ describe("Data source Twilio", () => {
|
||||||
deleteDatasource(`cypress-${data.dsName}-twilio`);
|
deleteDatasource(`cypress-${data.dsName}-twilio`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should be able to run the query with a valid connection", () => {
|
it.skip("Should be able to run the query with a valid connection", () => {
|
||||||
const AuthToken = Cypress.env("twilio_auth_token");
|
const AuthToken = Cypress.env("twilio_auth_token");
|
||||||
const AccountSID = Cypress.env("twilio_account_SID");
|
const AccountSID = Cypress.env("twilio_account_SID");
|
||||||
const MessageSID = Cypress.env("twilio_messaging_service_SID");
|
const MessageSID = Cypress.env("twilio_messaging_service_SID");
|
||||||
|
|
@ -20,7 +20,7 @@ const data = {};
|
||||||
|
|
||||||
describe("Data sources", () => {
|
describe("Data sources", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.appUILogin();
|
cy.apiLogin();
|
||||||
data.dataSourceName = fake.lastName
|
data.dataSourceName = fake.lastName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll("[^A-Za-z]", "");
|
.replaceAll("[^A-Za-z]", "");
|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,7 @@ describe("App Export", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Verify the elements of export dialog box", () => {
|
it("Verify the elements of export dialog box", () => {
|
||||||
cy.window({ log: false }).then((win) => {
|
cy.skipWalkthrough()
|
||||||
win.localStorage.setItem("walkthroughCompleted", "true");
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.visit(`${data.workspaceSlug}`);
|
cy.visit(`${data.workspaceSlug}`);
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ describe("App Import Functionality", () => {
|
||||||
cy.apiLogin();
|
cy.apiLogin();
|
||||||
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
|
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
|
||||||
cy.apiLogout();
|
cy.apiLogout();
|
||||||
|
cy.skipWalkthrough()
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should verify app import functionality", () => {
|
it("should verify app import functionality", () => {
|
||||||
|
|
@ -100,12 +101,13 @@ describe("App Import Functionality", () => {
|
||||||
.and("have.text", importText.appImportedToastMessage);
|
.and("have.text", importText.appImportedToastMessage);
|
||||||
|
|
||||||
// Verify imported app
|
// Verify imported app
|
||||||
cy.get(".driver-close-btn").click();
|
cy.get(commonSelectors.toastCloseButton).click();
|
||||||
cy.wait(500);
|
cy.wait(500);
|
||||||
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
|
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
|
||||||
"contain.value",
|
"contain.value",
|
||||||
"three-versions"
|
"three-versions"
|
||||||
);
|
);
|
||||||
|
cy.get(appVersionSelectors.currentVersionField("v3")).should("be.visible");
|
||||||
|
|
||||||
// Configure app
|
// Configure app
|
||||||
cy.skipEditorPopover();
|
cy.skipEditorPopover();
|
||||||
|
|
|
||||||
|
|
@ -27,17 +27,21 @@ describe("App Slug", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Verify app slug cases in global settings", () => {
|
it("Verify app slug cases in global settings", () => {
|
||||||
cy.apiLogin();
|
|
||||||
const workspaceId = Cypress.env("workspaceId");
|
const workspaceId = Cypress.env("workspaceId");
|
||||||
const appId = Cypress.env("appId");
|
const appId = Cypress.env("appId");
|
||||||
|
const appUrl = `${host}/${Cypress.env("workspaceId")}/apps/${Cypress.env("appId")}/`;
|
||||||
|
|
||||||
cy.visit("/my-workspace");
|
cy.apiLogin();
|
||||||
cy.wait(1000);
|
cy.skipWalkthrough();
|
||||||
|
|
||||||
cy.window({ log: false }).then((win) => {
|
cy.visit(appUrl);
|
||||||
win.localStorage.setItem("walkthroughCompleted", "true");
|
cy.url().then((url) => {
|
||||||
|
if (url !== appUrl) {
|
||||||
|
cy.visit(appUrl);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
cy.visit(`/${Cypress.env("workspaceId")}/apps/${Cypress.env("appId")}/`);
|
cy.url().should("eq", appUrl);
|
||||||
|
|
||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
|
|
||||||
cy.get(commonSelectors.leftSideBarSettingsButton).click();
|
cy.get(commonSelectors.leftSideBarSettingsButton).click();
|
||||||
|
|
|
||||||
|
|
@ -78,11 +78,11 @@ describe("Private and Public apps", {
|
||||||
|
|
||||||
// Test private access
|
// Test private access
|
||||||
logout();
|
logout();
|
||||||
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
|
||||||
|
|
||||||
cy.visitSlug({
|
cy.visitSlug({
|
||||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
||||||
cy.wait(2000);
|
cy.wait(2000);
|
||||||
cy.appUILogin();
|
cy.appUILogin();
|
||||||
|
|
@ -116,6 +116,9 @@ describe("Private and Public apps", {
|
||||||
|
|
||||||
inviteUserToWorkspace(data.firstName, data.email);
|
inviteUserToWorkspace(data.firstName, data.email);
|
||||||
logout();
|
logout();
|
||||||
|
cy.visit("/");
|
||||||
|
cy.wait(2000);
|
||||||
|
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
||||||
|
|
||||||
// Test private access
|
// Test private access
|
||||||
cy.visitSlug({
|
cy.visitSlug({
|
||||||
|
|
@ -141,6 +144,8 @@ describe("Private and Public apps", {
|
||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
cy.apiMakeAppPublic();
|
cy.apiMakeAppPublic();
|
||||||
logout();
|
logout();
|
||||||
|
cy.wait(1000);
|
||||||
|
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
||||||
|
|
||||||
cy.visitSlug({
|
cy.visitSlug({
|
||||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||||
|
|
@ -177,6 +182,9 @@ describe("Private and Public apps", {
|
||||||
cy.apiMakeAppPublic();
|
cy.apiMakeAppPublic();
|
||||||
logout();
|
logout();
|
||||||
|
|
||||||
|
cy.wait(1000);
|
||||||
|
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
||||||
|
|
||||||
cy.visitSlug({
|
cy.visitSlug({
|
||||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||||
});
|
});
|
||||||
|
|
@ -229,6 +237,8 @@ describe("Private and Public apps", {
|
||||||
|
|
||||||
cy.get('[data-cy="viewer-page-logo"]').click();
|
cy.get('[data-cy="viewer-page-logo"]').click();
|
||||||
logout();
|
logout();
|
||||||
|
cy.wait(1000);
|
||||||
|
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
||||||
|
|
||||||
// Setup new workspace and app
|
// Setup new workspace and app
|
||||||
cy.defaultWorkspaceLogin();
|
cy.defaultWorkspaceLogin();
|
||||||
|
|
@ -123,7 +123,7 @@ describe("App Version", () => {
|
||||||
releasedVersionAndVerify("v2");
|
releasedVersionAndVerify("v2");
|
||||||
});
|
});
|
||||||
|
|
||||||
it.only("should verify version management with components and queries", () => {
|
it("should verify version management with components and queries", () => {
|
||||||
// Initial setup with component and datasource
|
// Initial setup with component and datasource
|
||||||
cy.apiAddComponentToApp(
|
cy.apiAddComponentToApp(
|
||||||
data.appName,
|
data.appName,
|
||||||
|
|
@ -80,8 +80,8 @@ describe("Workspace constants", () => {
|
||||||
addNewconstants("restapiHeaderKey", "customHeader");
|
addNewconstants("restapiHeaderKey", "customHeader");
|
||||||
addNewconstants("restapiHeaderValue", "key=value");
|
addNewconstants("restapiHeaderValue", "key=value");
|
||||||
addNewconstants("deleteConst", "deleteconst");
|
addNewconstants("deleteConst", "deleteconst");
|
||||||
addNewconstants("gconst", "236");
|
addNewconstants("gconst", "108");
|
||||||
addNewconstants("gconstUrl", "http://34.66.166.236:4000/");
|
addNewconstants("gconstUrl", "http://20.29.40.108:4000/");
|
||||||
addNewconstants("gconstEndpoint", "production");
|
addNewconstants("gconstEndpoint", "production");
|
||||||
|
|
||||||
// create secret constants
|
// create secret constants
|
||||||
|
|
@ -118,6 +118,7 @@ describe("Workspace constants", () => {
|
||||||
|
|
||||||
//Verify all static and datasource queries output in components
|
//Verify all static and datasource queries output in components
|
||||||
for (let i = 3; i <= 16; i++) {
|
for (let i = 3; i <= 16; i++) {
|
||||||
|
cy.log("Verifying textinput" + i);
|
||||||
cy.get(commonWidgetSelector.draggableWidget(`textinput${i}`))
|
cy.get(commonWidgetSelector.draggableWidget(`textinput${i}`))
|
||||||
.verifyVisibleElement("have.value", "Production environment testing");
|
.verifyVisibleElement("have.value", "Production environment testing");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,164 @@ describe("dashboard", () => {
|
||||||
cy.visit(`${data.workspaceSlug}`);
|
cy.visit(`${data.workspaceSlug}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// it("Should verify app card elements and app card operations", () => {
|
||||||
|
// const customLayout = {
|
||||||
|
// desktop: { top: 100, left: 20 },
|
||||||
|
// mobile: { width: 8, height: 50 },
|
||||||
|
// };
|
||||||
|
|
||||||
|
// cy.apiCreateApp(data.appName);
|
||||||
|
// cy.visit(`${data.workspaceSlug}`);
|
||||||
|
|
||||||
|
// cy.wait(2000);
|
||||||
|
// cy.get(commonSelectors.appCreationDetails).should("be.visible");
|
||||||
|
// cy.get(commonSelectors.appCard(data.appName)).should("be.visible");
|
||||||
|
// cy.get(commonSelectors.appTitle(data.appName)).verifyVisibleElement(
|
||||||
|
// "have.text",
|
||||||
|
// data.appName
|
||||||
|
// );
|
||||||
|
|
||||||
|
// viewAppCardOptions(data.appName);
|
||||||
|
// cy.get(
|
||||||
|
// commonSelectors.appCardOptions(commonText.changeIconOption)
|
||||||
|
// ).verifyVisibleElement("have.text", commonText.changeIconOption);
|
||||||
|
// cy.get(
|
||||||
|
// commonSelectors.appCardOptions(commonText.addToFolderOption)
|
||||||
|
// ).verifyVisibleElement("have.text", commonText.addToFolderOption);
|
||||||
|
// cy.get(
|
||||||
|
// commonSelectors.appCardOptions(commonText.cloneAppOption)
|
||||||
|
// ).verifyVisibleElement("have.text", commonText.cloneAppOption);
|
||||||
|
// cy.get(
|
||||||
|
// commonSelectors.appCardOptions(commonText.exportAppOption)
|
||||||
|
// ).verifyVisibleElement("have.text", commonText.exportAppOption);
|
||||||
|
// cy.get(
|
||||||
|
// commonSelectors.appCardOptions(commonText.deleteAppOption)
|
||||||
|
// ).verifyVisibleElement("have.text", commonText.deleteAppOption);
|
||||||
|
|
||||||
|
// modifyAndVerifyAppCardIcon(data.appName);
|
||||||
|
// createFolder(data.folderName);
|
||||||
|
|
||||||
|
// viewAppCardOptions(data.appName);
|
||||||
|
// cy.get(
|
||||||
|
// commonSelectors.appCardOptions(commonText.addToFolderOption)
|
||||||
|
// ).click();
|
||||||
|
// verifyModal(
|
||||||
|
// dashboardText.addToFolderTitle,
|
||||||
|
// dashboardText.addToFolderButton,
|
||||||
|
// dashboardSelector.selectFolder
|
||||||
|
// );
|
||||||
|
// cy.get(dashboardSelector.moveAppText).verifyVisibleElement(
|
||||||
|
// "have.text",
|
||||||
|
// dashboardText.moveAppText(data.appName)
|
||||||
|
// );
|
||||||
|
|
||||||
|
// cy.get(dashboardSelector.selectFolder).click();
|
||||||
|
// cy.get(commonSelectors.folderList).contains(data.folderName).click();
|
||||||
|
// cy.get(dashboardSelector.addToFolderButton).click();
|
||||||
|
// cy.verifyToastMessage(
|
||||||
|
// commonSelectors.toastMessage,
|
||||||
|
// commonText.AddedToFolderToast,
|
||||||
|
// false
|
||||||
|
// );
|
||||||
|
|
||||||
|
// cy.get(dashboardSelector.folderName(data.folderName)).verifyVisibleElement(
|
||||||
|
// "have.text",
|
||||||
|
// dashboardText.folderName(`${data.folderName} (1)`)
|
||||||
|
// );
|
||||||
|
|
||||||
|
// cy.get(dashboardSelector.folderName(data.folderName)).click();
|
||||||
|
// cy.get(commonSelectors.appCard(data.appName))
|
||||||
|
// .contains(data.appName)
|
||||||
|
// .should("be.visible");
|
||||||
|
|
||||||
|
// viewAppCardOptions(data.appName);
|
||||||
|
|
||||||
|
// cy.get(commonSelectors.appCardOptions(commonText.removeFromFolderOption))
|
||||||
|
// .verifyVisibleElement("have.text", commonText.removeFromFolderOption)
|
||||||
|
// .click();
|
||||||
|
// verifyConfirmationModal(commonText.appRemovedFromFolderMessage);
|
||||||
|
|
||||||
|
// cancelModal(commonText.cancelButton);
|
||||||
|
|
||||||
|
// viewAppCardOptions(data.appName);
|
||||||
|
// cy.get(
|
||||||
|
// commonSelectors.appCardOptions(commonText.removeFromFolderOption)
|
||||||
|
// ).click();
|
||||||
|
// cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click();
|
||||||
|
// cy.verifyToastMessage(
|
||||||
|
// commonSelectors.toastMessage,
|
||||||
|
// commonText.appRemovedFromFolderTaost,
|
||||||
|
// false
|
||||||
|
// );
|
||||||
|
// cy.get(commonSelectors.modalComponent).should("not.exist");
|
||||||
|
// cy.get(commonSelectors.empytyFolderImage).should("be.visible");
|
||||||
|
// cy.get(commonSelectors.emptyFolderText).verifyVisibleElement(
|
||||||
|
// "have.text",
|
||||||
|
// commonText.emptyFolderText
|
||||||
|
// );
|
||||||
|
// cy.get(commonSelectors.allApplicationsLink).click();
|
||||||
|
// deleteFolder(data.folderName);
|
||||||
|
|
||||||
|
// cy.get(commonSelectors.allApplicationsLink).click();
|
||||||
|
|
||||||
|
// cy.wait(1000);
|
||||||
|
// viewAppCardOptions(data.appName);
|
||||||
|
// cy.wait(2000);
|
||||||
|
// cy.get(commonSelectors.appCardOptions(commonText.exportAppOption)).click();
|
||||||
|
// cy.get(commonSelectors.exportAllButton).click();
|
||||||
|
|
||||||
|
// cy.exec("ls ./cypress/downloads/").then((result) => {
|
||||||
|
// const downloadedAppExportFileName = result.stdout.split("\n")[0];
|
||||||
|
// expect(downloadedAppExportFileName).to.contain.string("app");
|
||||||
|
// });
|
||||||
|
|
||||||
|
// viewAppCardOptions(data.appName);
|
||||||
|
// cy.get(commonSelectors.appCardOptions(commonText.cloneAppOption)).click();
|
||||||
|
// cy.get('[data-cy="clone-app"]').click();
|
||||||
|
// cy.get(".go3958317564")
|
||||||
|
// .should("be.visible")
|
||||||
|
// .and("have.text", dashboardText.appClonedToast);
|
||||||
|
// cy.wait(3000);
|
||||||
|
|
||||||
|
// cy.renameApp(data.cloneAppName);
|
||||||
|
// cy.apiAddComponentToApp(data.cloneAppName, "button", 25, 25);
|
||||||
|
// cy.backToApps();
|
||||||
|
// cy.wait("@appLibrary");
|
||||||
|
// cy.wait(1000);
|
||||||
|
|
||||||
|
// cy.get(commonSelectors.appCard(data.cloneAppName)).should("be.visible");
|
||||||
|
|
||||||
|
// cy.wait(1000);
|
||||||
|
|
||||||
|
// viewAppCardOptions(data.cloneAppName);
|
||||||
|
// cy.get(commonSelectors.deleteAppOption).click();
|
||||||
|
// cy.get(commonSelectors.modalMessage).verifyVisibleElement(
|
||||||
|
// "have.text",
|
||||||
|
// commonText.deleteAppModalMessage(data.cloneAppName)
|
||||||
|
// );
|
||||||
|
// cy.get(
|
||||||
|
// commonSelectors.buttonSelector(commonText.cancelButton)
|
||||||
|
// ).verifyVisibleElement("have.text", commonText.cancelButton);
|
||||||
|
// cy.get(
|
||||||
|
// commonSelectors.buttonSelector(commonText.modalYesButton)
|
||||||
|
// ).verifyVisibleElement("have.text", commonText.modalYesButton);
|
||||||
|
// cancelModal(commonText.cancelButton);
|
||||||
|
|
||||||
|
// viewAppCardOptions(data.cloneAppName);
|
||||||
|
// cy.get(commonSelectors.deleteAppOption).click();
|
||||||
|
// cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click();
|
||||||
|
// cy.verifyToastMessage(
|
||||||
|
// commonSelectors.toastMessage,
|
||||||
|
// commonText.appDeletedToast,
|
||||||
|
// false
|
||||||
|
// );
|
||||||
|
// verifyAppDelete(data.cloneAppName);
|
||||||
|
// cy.wait("@appLibrary");
|
||||||
|
|
||||||
|
// cy.deleteApp(data.appName);
|
||||||
|
// verifyAppDelete(data.appName);
|
||||||
|
// });
|
||||||
|
|
||||||
it("should verify the elements on empty dashboard", () => {
|
it("should verify the elements on empty dashboard", () => {
|
||||||
cy.intercept("GET", "/api/metadata", {
|
cy.intercept("GET", "/api/metadata", {
|
||||||
body: {
|
body: {
|
||||||
|
|
@ -171,181 +329,6 @@ describe("dashboard", () => {
|
||||||
verifyTooltip(dashboardSelector.modeToggle, "Mode");
|
verifyTooltip(dashboardSelector.modeToggle, "Mode");
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip("Should verify app card elements and app card operations", () => {
|
|
||||||
const customLayout = {
|
|
||||||
desktop: { top: 100, left: 20 },
|
|
||||||
mobile: { width: 8, height: 50 },
|
|
||||||
};
|
|
||||||
|
|
||||||
cy.apiCreateApp(data.appName);
|
|
||||||
cy.openApp();
|
|
||||||
cy.apiAddComponentToApp(data.appName, "text1", customLayout);
|
|
||||||
|
|
||||||
cy.backToApps();
|
|
||||||
|
|
||||||
cy.wait(500);
|
|
||||||
cy.get(commonSelectors.appCard(data.appName))
|
|
||||||
.parent()
|
|
||||||
.within(() => {
|
|
||||||
cy.get(commonSelectors.appCard(data.appName)).should("be.visible");
|
|
||||||
cy.get(commonSelectors.appTitle(data.appName)).verifyVisibleElement(
|
|
||||||
"have.text",
|
|
||||||
data.appName
|
|
||||||
);
|
|
||||||
cy.get(commonSelectors.appCreationDetails).should("be.visible");
|
|
||||||
|
|
||||||
//Add the edited details
|
|
||||||
});
|
|
||||||
|
|
||||||
viewAppCardOptions(data.appName);
|
|
||||||
cy.get(
|
|
||||||
commonSelectors.appCardOptions(commonText.changeIconOption)
|
|
||||||
).verifyVisibleElement("have.text", commonText.changeIconOption);
|
|
||||||
cy.get(
|
|
||||||
commonSelectors.appCardOptions(commonText.addToFolderOption)
|
|
||||||
).verifyVisibleElement("have.text", commonText.addToFolderOption);
|
|
||||||
cy.get(
|
|
||||||
commonSelectors.appCardOptions(commonText.cloneAppOption)
|
|
||||||
).verifyVisibleElement("have.text", commonText.cloneAppOption);
|
|
||||||
cy.get(
|
|
||||||
commonSelectors.appCardOptions(commonText.exportAppOption)
|
|
||||||
).verifyVisibleElement("have.text", commonText.exportAppOption);
|
|
||||||
cy.get(
|
|
||||||
commonSelectors.appCardOptions(commonText.deleteAppOption)
|
|
||||||
).verifyVisibleElement("have.text", commonText.deleteAppOption);
|
|
||||||
|
|
||||||
modifyAndVerifyAppCardIcon(data.appName);
|
|
||||||
createFolder(data.folderName);
|
|
||||||
|
|
||||||
viewAppCardOptions(data.appName);
|
|
||||||
cy.get(
|
|
||||||
commonSelectors.appCardOptions(commonText.addToFolderOption)
|
|
||||||
).click();
|
|
||||||
verifyModal(
|
|
||||||
dashboardText.addToFolderTitle,
|
|
||||||
dashboardText.addToFolderButton,
|
|
||||||
dashboardSelector.selectFolder
|
|
||||||
);
|
|
||||||
cy.get(dashboardSelector.moveAppText).verifyVisibleElement(
|
|
||||||
"have.text",
|
|
||||||
dashboardText.moveAppText(data.appName)
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(dashboardSelector.selectFolder).click();
|
|
||||||
cy.get(commonSelectors.folderList).contains(data.folderName).click();
|
|
||||||
cy.get(dashboardSelector.addToFolderButton).click();
|
|
||||||
cy.verifyToastMessage(
|
|
||||||
commonSelectors.toastMessage,
|
|
||||||
commonText.AddedToFolderToast
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(dashboardSelector.folderName(data.folderName)).verifyVisibleElement(
|
|
||||||
"have.text",
|
|
||||||
dashboardText.folderName(`${data.folderName} (1)`)
|
|
||||||
);
|
|
||||||
|
|
||||||
cy.get(dashboardSelector.folderName(data.folderName)).click();
|
|
||||||
cy.get(commonSelectors.appCard(data.appName))
|
|
||||||
.contains(data.appName)
|
|
||||||
.should("be.visible");
|
|
||||||
|
|
||||||
cy.wait(2000);
|
|
||||||
viewAppCardOptions(data.appName);
|
|
||||||
|
|
||||||
cy.get(commonSelectors.appCardOptions(commonText.removeFromFolderOption))
|
|
||||||
.verifyVisibleElement("have.text", commonText.removeFromFolderOption)
|
|
||||||
.click();
|
|
||||||
verifyConfirmationModal(commonText.appRemovedFromFolderMessage);
|
|
||||||
|
|
||||||
cancelModal(commonText.cancelButton);
|
|
||||||
|
|
||||||
cy.wait(3000);
|
|
||||||
viewAppCardOptions(data.appName);
|
|
||||||
cy.get(
|
|
||||||
commonSelectors.appCardOptions(commonText.removeFromFolderOption)
|
|
||||||
).click();
|
|
||||||
cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click();
|
|
||||||
cy.verifyToastMessage(
|
|
||||||
commonSelectors.toastMessage,
|
|
||||||
commonText.appRemovedFromFolderTaost
|
|
||||||
);
|
|
||||||
cy.get(commonSelectors.modalComponent).should("not.exist");
|
|
||||||
cy.get(commonSelectors.empytyFolderImage).should("be.visible");
|
|
||||||
cy.get(commonSelectors.emptyFolderText).verifyVisibleElement(
|
|
||||||
"have.text",
|
|
||||||
commonText.emptyFolderText
|
|
||||||
);
|
|
||||||
cy.get(commonSelectors.allApplicationsLink).click();
|
|
||||||
deleteFolder(data.folderName);
|
|
||||||
|
|
||||||
cy.get(commonSelectors.allApplicationsLink).click();
|
|
||||||
|
|
||||||
cy.wait(3000);
|
|
||||||
viewAppCardOptions(data.appName);
|
|
||||||
cy.get(commonSelectors.appCardOptions(commonText.cloneAppOption)).click();
|
|
||||||
cy.get('[data-cy="clone-app"]').click();
|
|
||||||
cy.get(".go3958317564")
|
|
||||||
.should("be.visible")
|
|
||||||
.and("have.text", dashboardText.appClonedToast);
|
|
||||||
cy.wait(3000);
|
|
||||||
cy.renameApp(data.cloneAppName);
|
|
||||||
cy.apiAddComponentToApp(data.cloneAppName, "button", 25, 25);
|
|
||||||
cy.backToApps();
|
|
||||||
cy.wait("@appLibrary");
|
|
||||||
cy.wait(1000);
|
|
||||||
cy.reloadAppForTheElement(data.cloneAppName);
|
|
||||||
|
|
||||||
cy.get(commonSelectors.appCard(data.cloneAppName)).should("be.visible");
|
|
||||||
|
|
||||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
|
||||||
cy.get(commonSelectors.dashboardIcon).click();
|
|
||||||
cy.wait(3000);
|
|
||||||
cy.reloadAppForTheElement(data.cloneAppName);
|
|
||||||
viewAppCardOptions(data.cloneAppName);
|
|
||||||
cy.get(commonSelectors.appCardOptions(commonText.exportAppOption)).click();
|
|
||||||
cy.get(commonSelectors.exportAllButton).click();
|
|
||||||
|
|
||||||
cy.exec("ls ./cypress/downloads/").then((result) => {
|
|
||||||
const downloadedAppExportFileName = result.stdout.split("\n")[0];
|
|
||||||
expect(downloadedAppExportFileName).to.contain.string("app");
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.wait(3000);
|
|
||||||
cy.reloadAppForTheElement(data.cloneAppName);
|
|
||||||
viewAppCardOptions(data.cloneAppName);
|
|
||||||
cy.get(commonSelectors.deleteAppOption).click();
|
|
||||||
cy.get(commonSelectors.modalMessage).verifyVisibleElement(
|
|
||||||
"have.text",
|
|
||||||
commonText.deleteAppModalMessage(data.cloneAppName)
|
|
||||||
);
|
|
||||||
cy.get(
|
|
||||||
commonSelectors.buttonSelector(commonText.cancelButton)
|
|
||||||
).verifyVisibleElement("have.text", commonText.cancelButton);
|
|
||||||
cy.get(
|
|
||||||
commonSelectors.buttonSelector(commonText.modalYesButton)
|
|
||||||
).verifyVisibleElement("have.text", commonText.modalYesButton);
|
|
||||||
cancelModal(commonText.cancelButton);
|
|
||||||
|
|
||||||
cy.wait(3000);
|
|
||||||
cy.reloadAppForTheElement(data.cloneAppName);
|
|
||||||
viewAppCardOptions(data.cloneAppName);
|
|
||||||
cy.get(commonSelectors.deleteAppOption).click();
|
|
||||||
cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click();
|
|
||||||
cy.verifyToastMessage(
|
|
||||||
commonSelectors.toastMessage,
|
|
||||||
commonText.appDeletedToast
|
|
||||||
);
|
|
||||||
verifyAppDelete(data.cloneAppName);
|
|
||||||
cy.wait("@appLibrary");
|
|
||||||
|
|
||||||
cy.deleteApp(data.appName);
|
|
||||||
cy.verifyToastMessage(
|
|
||||||
commonSelectors.toastMessage,
|
|
||||||
commonText.appDeletedToast
|
|
||||||
);
|
|
||||||
verifyAppDelete(data.appName);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should verify the app CRUD operation", () => {
|
it("Should verify the app CRUD operation", () => {
|
||||||
const customLayout = {
|
const customLayout = {
|
||||||
desktop: { top: 100, left: 20 },
|
desktop: { top: 100, left: 20 },
|
||||||
|
|
@ -369,10 +352,7 @@ describe("dashboard", () => {
|
||||||
cy.wait("@appLibrary");
|
cy.wait("@appLibrary");
|
||||||
|
|
||||||
cy.deleteApp(data.appName);
|
cy.deleteApp(data.appName);
|
||||||
cy.verifyToastMessage(
|
|
||||||
commonSelectors.toastMessage,
|
|
||||||
commonText.appDeletedToast
|
|
||||||
);
|
|
||||||
verifyAppDelete(data.appName);
|
verifyAppDelete(data.appName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -493,10 +473,7 @@ describe("dashboard", () => {
|
||||||
|
|
||||||
cy.get(commonSelectors.allApplicationsLink).click();
|
cy.get(commonSelectors.allApplicationsLink).click();
|
||||||
cy.deleteApp(data.appName);
|
cy.deleteApp(data.appName);
|
||||||
cy.verifyToastMessage(
|
|
||||||
commonSelectors.toastMessage,
|
|
||||||
commonText.appDeletedToast
|
|
||||||
);
|
|
||||||
verifyAppDelete(data.appName);
|
verifyAppDelete(data.appName);
|
||||||
logout();
|
logout();
|
||||||
});
|
});
|
||||||
|
|
@ -78,14 +78,16 @@ describe("Manage Groups", () => {
|
||||||
cy.createApp(data.appName);
|
cy.createApp(data.appName);
|
||||||
cy.verifyToastMessage(
|
cy.verifyToastMessage(
|
||||||
commonSelectors.toastMessage,
|
commonSelectors.toastMessage,
|
||||||
commonText.appCreatedToast
|
commonText.appCreatedToast,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
cy.backToApps();
|
cy.backToApps();
|
||||||
|
|
||||||
cy.deleteApp(data.appName);
|
cy.deleteApp(data.appName);
|
||||||
cy.verifyToastMessage(
|
cy.verifyToastMessage(
|
||||||
commonSelectors.toastMessage,
|
commonSelectors.toastMessage,
|
||||||
commonText.appDeletedToast
|
commonText.appDeletedToast,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
// Folder operations
|
// Folder operations
|
||||||
|
|
@ -115,7 +117,8 @@ describe("Manage Groups", () => {
|
||||||
cy.get(commonSelectors.cloneAppButton).click();
|
cy.get(commonSelectors.cloneAppButton).click();
|
||||||
cy.verifyToastMessage(
|
cy.verifyToastMessage(
|
||||||
commonSelectors.toastMessage,
|
commonSelectors.toastMessage,
|
||||||
dashboardText.appClonedToast
|
dashboardText.appClonedToast,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
// cy.get(commonSelectors.cancelButton).click();
|
// cy.get(commonSelectors.cancelButton).click();
|
||||||
cy.apiLogout();
|
cy.apiLogout();
|
||||||
|
|
@ -177,14 +180,16 @@ describe("Manage Groups", () => {
|
||||||
cy.createApp(data.appName);
|
cy.createApp(data.appName);
|
||||||
cy.verifyToastMessage(
|
cy.verifyToastMessage(
|
||||||
commonSelectors.toastMessage,
|
commonSelectors.toastMessage,
|
||||||
commonText.appCreatedToast
|
commonText.appCreatedToast,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
cy.backToApps();
|
cy.backToApps();
|
||||||
|
|
||||||
cy.deleteApp(data.appName);
|
cy.deleteApp(data.appName);
|
||||||
cy.verifyToastMessage(
|
cy.verifyToastMessage(
|
||||||
commonSelectors.toastMessage,
|
commonSelectors.toastMessage,
|
||||||
commonText.appDeletedToast
|
commonText.appDeletedToast,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
// Folder operations
|
// Folder operations
|
||||||
|
|
|
||||||
|
|
@ -204,10 +204,7 @@ describe("Manage Groups", () => {
|
||||||
|
|
||||||
cy.wait(2500);
|
cy.wait(2500);
|
||||||
cy.deleteApp(data.appName);
|
cy.deleteApp(data.appName);
|
||||||
cy.verifyToastMessage(
|
|
||||||
commonSelectors.toastMessage,
|
|
||||||
commonText.appDeletedToast
|
|
||||||
);
|
|
||||||
|
|
||||||
// Folder operations
|
// Folder operations
|
||||||
createFolder(data.folderName);
|
createFolder(data.folderName);
|
||||||
|
|
|
||||||
|
|
@ -2127,7 +2127,7 @@
|
||||||
"encrypted": false
|
"encrypted": false
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
"value": "35.238.9.114",
|
"value": "9.234.17.31",
|
||||||
"encrypted": false
|
"encrypted": false
|
||||||
},
|
},
|
||||||
"port": {
|
"port": {
|
||||||
|
|
|
||||||
|
|
@ -585,7 +585,7 @@
|
||||||
"encrypted": false
|
"encrypted": false
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
"value": "35.238.9.114",
|
"value": "9.234.17.31",
|
||||||
"encrypted": false
|
"encrypted": false
|
||||||
},
|
},
|
||||||
"port": {
|
"port": {
|
||||||
|
|
|
||||||
|
|
@ -1862,7 +1862,7 @@
|
||||||
"encrypted": false
|
"encrypted": false
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
"value": "35.238.9.114",
|
"value": "9.234.17.31",
|
||||||
"encrypted": false
|
"encrypted": false
|
||||||
},
|
},
|
||||||
"port": {
|
"port": {
|
||||||
|
|
|
||||||
|
|
@ -2766,7 +2766,7 @@
|
||||||
"name": "restapiStaticUrlG",
|
"name": "restapiStaticUrlG",
|
||||||
"options": {
|
"options": {
|
||||||
"method": "get",
|
"method": "get",
|
||||||
"url": "http://34.66.166.236:4000/{{constants.gconstEndpoint}}",
|
"url": "http://20.29.40.108:4000/{{constants.gconstEndpoint}}",
|
||||||
"url_params": [
|
"url_params": [
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
|
|
@ -2814,7 +2814,7 @@
|
||||||
"name": "restapiUrlS",
|
"name": "restapiUrlS",
|
||||||
"options": {
|
"options": {
|
||||||
"method": "get",
|
"method": "get",
|
||||||
"url": "http://34.66.166.236:4000/{{secrets.sconstEndpoint}}",
|
"url": "http://20.29.40.108:4000/{{secrets.sconstEndpoint}}",
|
||||||
"url_params": [
|
"url_params": [
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
|
|
@ -2908,7 +2908,7 @@
|
||||||
"name": "restapiUrlGS",
|
"name": "restapiUrlGS",
|
||||||
"options": {
|
"options": {
|
||||||
"method": "get",
|
"method": "get",
|
||||||
"url": "http://34.66.166.{{constants.gconst}}{{secrets.sconst}}/production",
|
"url": "http://20.29.40.{{constants.gconst}}{{secrets.sconst}}/production",
|
||||||
"url_params": [
|
"url_params": [
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
|
|
@ -3419,7 +3419,7 @@
|
||||||
"environmentId": "dab04b8d-7d1a-468a-b219-b2e1d0169d8c",
|
"environmentId": "dab04b8d-7d1a-468a-b219-b2e1d0169d8c",
|
||||||
"options": {
|
"options": {
|
||||||
"url": {
|
"url": {
|
||||||
"value": "http://34.66.166.236:4000/{{constants.gconstEndpoint}}",
|
"value": "http://20.29.40.108:4000/{{constants.gconstEndpoint}}",
|
||||||
"encrypted": false
|
"encrypted": false
|
||||||
},
|
},
|
||||||
"auth_type": {
|
"auth_type": {
|
||||||
|
|
@ -3540,7 +3540,7 @@
|
||||||
"environmentId": "dab04b8d-7d1a-468a-b219-b2e1d0169d8c",
|
"environmentId": "dab04b8d-7d1a-468a-b219-b2e1d0169d8c",
|
||||||
"options": {
|
"options": {
|
||||||
"url": {
|
"url": {
|
||||||
"value": "http://34.66.166.236:4000/{{secrets.sconstEndpoint}}",
|
"value": "http://20.29.40.108:4000/{{secrets.sconstEndpoint}}",
|
||||||
"encrypted": false
|
"encrypted": false
|
||||||
},
|
},
|
||||||
"auth_type": {
|
"auth_type": {
|
||||||
|
|
@ -3782,7 +3782,7 @@
|
||||||
"environmentId": "dab04b8d-7d1a-468a-b219-b2e1d0169d8c",
|
"environmentId": "dab04b8d-7d1a-468a-b219-b2e1d0169d8c",
|
||||||
"options": {
|
"options": {
|
||||||
"url": {
|
"url": {
|
||||||
"value": "http://34.66.166.{{constants.gconst}}{{secrets.sconst}}/production",
|
"value": "http://20.29.40.{{constants.gconst}}{{secrets.sconst}}/production",
|
||||||
"encrypted": false
|
"encrypted": false
|
||||||
},
|
},
|
||||||
"auth_type": {
|
"auth_type": {
|
||||||
|
|
|
||||||
|
|
@ -101,11 +101,14 @@ export const navigateToAppEditor = (appName) => {
|
||||||
|
|
||||||
export const viewAppCardOptions = (appName) => {
|
export const viewAppCardOptions = (appName) => {
|
||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
cy.reloadAppForTheElement(appName);
|
cy.get(commonSelectors.appCard(appName))
|
||||||
|
.realHover()
|
||||||
|
.find(commonSelectors.appCardOptionsButton)
|
||||||
|
.realHover()
|
||||||
cy.contains("div", appName)
|
cy.contains("div", appName)
|
||||||
.parent()
|
.parent()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.get(commonSelectors.appCardOptionsButton).invoke("click");
|
cy.get(commonSelectors.appCardOptionsButton).click();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -185,8 +188,9 @@ export const searchUser = (email) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const selectAppCardOption = (appName, appCardOption) => {
|
export const selectAppCardOption = (appName, appCardOption) => {
|
||||||
|
cy.wait(1000);
|
||||||
viewAppCardOptions(appName);
|
viewAppCardOptions(appName);
|
||||||
cy.get(appCardOption).should("be.visible").click({ force: true });
|
cy.get(appCardOption).should("be.visible").click();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const navigateToDatabase = () => {
|
export const navigateToDatabase = () => {
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,8 @@ export const modifyAndVerifyAppCardIcon = (appName) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const verifyAppDelete = (appName) => {
|
export const verifyAppDelete = (appName) => {
|
||||||
|
cy.get("body").should("exist").and("be.visible");
|
||||||
|
cy.get('[data-cy="dashboard-section-header"]').should("be.visible");
|
||||||
cy.get("body").then(($title) => {
|
cy.get("body").then(($title) => {
|
||||||
if (!$title.text().includes(commonText.introductionMessage)) {
|
if (!$title.text().includes(commonText.introductionMessage)) {
|
||||||
cy.clearAndType(commonSelectors.homePageSearchBar, appName);
|
cy.clearAndType(commonSelectors.homePageSearchBar, appName);
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,8 @@ export const createRestAPIQuery = (
|
||||||
key = "",
|
key = "",
|
||||||
value = "",
|
value = "",
|
||||||
url = "",
|
url = "",
|
||||||
run = true
|
run = true,
|
||||||
|
kind = "restapi"
|
||||||
) => {
|
) => {
|
||||||
cy.getCookie("tj_auth_token").then((cookie) => {
|
cy.getCookie("tj_auth_token").then((cookie) => {
|
||||||
const headers = {
|
const headers = {
|
||||||
|
|
@ -247,7 +248,6 @@ export const createRestAPIQuery = (
|
||||||
Cookie: `tj_auth_token=${cookie.value}`,
|
Cookie: `tj_auth_token=${cookie.value}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
cy.log(Cypress.env("appId"));
|
|
||||||
cy.request({
|
cy.request({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `${Cypress.env("server_host")}/api/apps/${Cypress.env("appId")}`,
|
url: `${Cypress.env("server_host")}/api/apps/${Cypress.env("appId")}`,
|
||||||
|
|
@ -255,13 +255,13 @@ export const createRestAPIQuery = (
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
const editingVersionId = response.body.editing_version.id;
|
const editingVersionId = response.body.editing_version.id;
|
||||||
|
|
||||||
const data_source_id = Cypress.env(`${dsName}-id`);
|
const data_source_id = Cypress.env(kind);
|
||||||
|
|
||||||
const requestBody = {
|
const requestBody = {
|
||||||
app_id: Cypress.env("appId"),
|
app_id: Cypress.env("appId"),
|
||||||
app_version_id: editingVersionId,
|
app_version_id: editingVersionId,
|
||||||
name: queryName,
|
name: queryName,
|
||||||
kind: "restapi",
|
kind: kind,
|
||||||
options: {
|
options: {
|
||||||
method: "get",
|
method: "get",
|
||||||
url: url,
|
url: url,
|
||||||
|
|
|
||||||
|
|
@ -18,79 +18,97 @@ export const createAndRunRestAPIQuery = (
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `${Cypress.env("server_host")}/api/apps/${Cypress.env("appId")}`,
|
url: `${Cypress.env("server_host")}/api/apps/${Cypress.env("appId")}`,
|
||||||
headers,
|
headers,
|
||||||
}).then((response) => {
|
}).then((appResponse) => {
|
||||||
const editingVersionId = response.body.editing_version.id;
|
const currentEnvironmentId = appResponse.body.editorEnvironment.id;
|
||||||
const data_source_id = Cypress.env(`${dsName}-id`);
|
const editingVersionId = appResponse.body.editing_version.id;
|
||||||
const useJsonBody =
|
|
||||||
["POST", "PATCH", "PUT"].includes(method.toUpperCase()) &&
|
|
||||||
jsonBody !== null;
|
|
||||||
|
|
||||||
const queryOptions = {
|
|
||||||
method: method.toLowerCase(),
|
|
||||||
url: url + urlSuffix,
|
|
||||||
url_params: [["", ""]],
|
|
||||||
headers: headersList.length ? headersList : [["", ""]],
|
|
||||||
body: !useJsonBody && bodyList.length ? bodyList : [["", ""]],
|
|
||||||
json_body: useJsonBody ? jsonBody : null,
|
|
||||||
body_toggle: useJsonBody,
|
|
||||||
runOnPageLoad: run,
|
|
||||||
transformationLanguage: "javascript",
|
|
||||||
enableTransformation: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const requestBody = {
|
|
||||||
app_id: Cypress.env("appId"),
|
|
||||||
app_version_id: editingVersionId,
|
|
||||||
name: queryName,
|
|
||||||
kind: "restapi",
|
|
||||||
options: queryOptions,
|
|
||||||
data_source_id,
|
|
||||||
plugin_id: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
cy.request({
|
cy.request({
|
||||||
method: "POST",
|
method: "GET",
|
||||||
url: `${Cypress.env("server_host")}/api/data-queries/data-sources/${data_source_id}/versions/${editingVersionId}`,
|
url: `${Cypress.env("server_host")}/api/data-sources/${Cypress.env("workspaceId")}/environments/${currentEnvironmentId}/versions/${editingVersionId}`,
|
||||||
headers,
|
headers,
|
||||||
body: requestBody,
|
}).then((dsResponse) => {
|
||||||
}).then((createResponse) => {
|
expect(dsResponse.status).to.eq(200);
|
||||||
expect(createResponse.status).to.equal(201);
|
|
||||||
const queryId = createResponse.body.id;
|
|
||||||
cy.log("Query created successfully:", queryId);
|
|
||||||
|
|
||||||
const createdOptions = createResponse.body.options;
|
const dataSource = dsResponse.body.data_sources.find(
|
||||||
expect(createdOptions.method).to.equal(queryOptions.method);
|
(ds) => ds.name === dsName
|
||||||
expect(createdOptions.url).to.equal(queryOptions.url);
|
);
|
||||||
expect(createdOptions.headers).to.deep.equal(queryOptions.headers);
|
|
||||||
|
|
||||||
if (useJsonBody) {
|
if (!dataSource) {
|
||||||
expect(createdOptions.json_body).to.deep.equal(
|
throw new Error(`Data source '${dsName}' not found.`);
|
||||||
queryOptions.json_body
|
|
||||||
);
|
|
||||||
expect(createdOptions.body_toggle).to.equal(true);
|
|
||||||
} else {
|
|
||||||
expect(createdOptions.body).to.deep.equal(queryOptions.body);
|
|
||||||
expect(createdOptions.body_toggle).to.equal(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(createdOptions.runOnPageLoad).to.equal(run);
|
const data_source_id = dataSource.id;
|
||||||
cy.log("Metadata verified successfully");
|
const useJsonBody =
|
||||||
if (run) {
|
["POST", "PATCH", "PUT"].includes(method.toUpperCase()) &&
|
||||||
cy.request({
|
jsonBody !== null;
|
||||||
method: "POST",
|
|
||||||
url: `${Cypress.env("server_host")}/api/data-queries/${queryId}/run`,
|
const queryOptions = {
|
||||||
headers,
|
method: method.toLowerCase(),
|
||||||
}).then((runResponse) => {
|
url: url + urlSuffix,
|
||||||
expect([200, 201]).to.include(runResponse.status);
|
url_params: [["", ""]],
|
||||||
cy.log("Query executed successfully:", runResponse.body);
|
headers: headersList.length ? headersList : [["", ""]],
|
||||||
if (runResponse.body?.data.id) {
|
body: !useJsonBody && bodyList.length ? bodyList : [["", ""]],
|
||||||
cy.writeFile("cypress/fixtures/restAPI/storedId.json", {
|
json_body: useJsonBody ? jsonBody : null,
|
||||||
id: runResponse.body.data.id,
|
body_toggle: useJsonBody,
|
||||||
});
|
runOnPageLoad: run,
|
||||||
cy.log("Stored ID:", runResponse.body.data.id);
|
transformationLanguage: "javascript",
|
||||||
}
|
enableTransformation: false,
|
||||||
});
|
};
|
||||||
}
|
|
||||||
|
const requestBody = {
|
||||||
|
app_id: Cypress.env("appId"),
|
||||||
|
app_version_id: editingVersionId,
|
||||||
|
name: queryName,
|
||||||
|
kind: "restapi",
|
||||||
|
options: queryOptions,
|
||||||
|
data_source_id,
|
||||||
|
plugin_id: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
cy.request({
|
||||||
|
method: "POST",
|
||||||
|
url: `${Cypress.env("server_host")}/api/data-queries/data-sources/${data_source_id}/versions/${editingVersionId}`,
|
||||||
|
headers,
|
||||||
|
body: requestBody,
|
||||||
|
}).then((createResponse) => {
|
||||||
|
expect(createResponse.status).to.equal(201);
|
||||||
|
const queryId = createResponse.body.id;
|
||||||
|
cy.log("Query created successfully:", queryId);
|
||||||
|
|
||||||
|
const createdOptions = createResponse.body.options;
|
||||||
|
expect(createdOptions.method).to.equal(queryOptions.method);
|
||||||
|
expect(createdOptions.url).to.equal(queryOptions.url);
|
||||||
|
expect(createdOptions.headers).to.deep.equal(queryOptions.headers);
|
||||||
|
|
||||||
|
if (useJsonBody) {
|
||||||
|
expect(createdOptions.json_body).to.deep.equal(
|
||||||
|
queryOptions.json_body
|
||||||
|
);
|
||||||
|
expect(createdOptions.body_toggle).to.equal(true);
|
||||||
|
} else {
|
||||||
|
expect(createdOptions.body).to.deep.equal(queryOptions.body);
|
||||||
|
expect(createdOptions.body_toggle).to.equal(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(createdOptions.runOnPageLoad).to.equal(run);
|
||||||
|
cy.log("Metadata verified successfully");
|
||||||
|
if (run) {
|
||||||
|
cy.request({
|
||||||
|
method: "POST",
|
||||||
|
url: `${Cypress.env("server_host")}/api/data-queries/${queryId}/run`,
|
||||||
|
headers,
|
||||||
|
}).then((runResponse) => {
|
||||||
|
expect([200, 201]).to.include(runResponse.status);
|
||||||
|
cy.log("Query executed successfully:", runResponse.body);
|
||||||
|
if (runResponse.body?.data.id) {
|
||||||
|
cy.writeFile("cypress/fixtures/restAPI/storedId.json", {
|
||||||
|
id: runResponse.body.data.id,
|
||||||
|
});
|
||||||
|
cy.log("Stored ID:", runResponse.body.data.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -115,8 +115,8 @@ export const verifyDuplicateVersion = (newVersion = [], version) => {
|
||||||
cy.get(appVersionSelectors.createNewVersionButton).click();
|
cy.get(appVersionSelectors.createNewVersionButton).click();
|
||||||
cy.verifyToastMessage(
|
cy.verifyToastMessage(
|
||||||
commonSelectors.toastMessage,
|
commonSelectors.toastMessage,
|
||||||
// appVersionText.versionNameAlreadyExists
|
appVersionText.versionNameAlreadyExists
|
||||||
"Already exists!"
|
// "Already exists!"
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ COPY --from=postgrest/postgrest:v12.2.0 /bin/postgrest /bin
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||||
RUN apt-get update && apt-get install -y postgresql-client freetds-dev libaio1 wget supervisor
|
RUN apt-get update && apt-get install -y freetds-dev libaio1 wget supervisor
|
||||||
|
|
||||||
# Install Instantclient Basic Light Oracle and Dependencies
|
# Install Instantclient Basic Light Oracle and Dependencies
|
||||||
WORKDIR /opt/oracle
|
WORKDIR /opt/oracle
|
||||||
|
|
@ -54,9 +54,6 @@ ENV LD_LIBRARY_PATH="/opt/oracle/instantclient_11_2:/opt/oracle/instantclient_21
|
||||||
|
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
|
|
||||||
RUN mkdir -p /app /var/log/supervisor
|
|
||||||
COPY /deploy/docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
|
||||||
|
|
||||||
# copy npm scripts
|
# copy npm scripts
|
||||||
COPY --from=builder /app/package.json ./app/package.json
|
COPY --from=builder /app/package.json ./app/package.json
|
||||||
# copy plugins dependencies
|
# copy plugins dependencies
|
||||||
|
|
@ -77,32 +74,64 @@ COPY --from=builder /app/server/dist ./app/server/dist
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install PostgreSQL
|
||||||
USER root
|
USER root
|
||||||
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
|
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
|
||||||
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list
|
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list
|
||||||
RUN echo "deb http://deb.debian.org/debian"
|
|
||||||
RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor
|
RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor
|
||||||
USER postgres
|
|
||||||
RUN service postgresql start && \
|
# Explicitly create PG main directory with correct ownership
|
||||||
psql -c "create role tooljet with login superuser password 'postgres';"
|
RUN mkdir -p /var/lib/postgresql/13/main && \
|
||||||
USER root
|
chown -R postgres:postgres /var/lib/postgresql
|
||||||
|
|
||||||
|
RUN mkdir -p /var/log/supervisor /var/run/postgresql && \
|
||||||
|
chown -R postgres:postgres /var/run/postgresql /var/log/supervisor
|
||||||
|
|
||||||
|
# Remove existing data and create directory with proper ownership
|
||||||
|
RUN rm -rf /var/lib/postgresql/13/main && \
|
||||||
|
mkdir -p /var/lib/postgresql/13/main && \
|
||||||
|
chown -R postgres:postgres /var/lib/postgresql
|
||||||
|
|
||||||
|
# Initialize PostgreSQL
|
||||||
|
RUN su - postgres -c "/usr/lib/postgresql/13/bin/initdb -D /var/lib/postgresql/13/main"
|
||||||
|
|
||||||
|
# Configure Supervisor to manage PostgREST, ToolJet, and Redis
|
||||||
|
RUN echo "[supervisord] \n" \
|
||||||
|
"nodaemon=true \n" \
|
||||||
|
"user=root \n" \
|
||||||
|
"\n" \
|
||||||
|
"[program:postgrest] \n" \
|
||||||
|
"command=/bin/postgrest \n" \
|
||||||
|
"autostart=true \n" \
|
||||||
|
"autorestart=true \n" \
|
||||||
|
"\n" \
|
||||||
|
"[program:tooljet] \n" \
|
||||||
|
"user=root \n" \
|
||||||
|
"command=/bin/bash -c '/app/server/scripts/boot.sh' \n" \
|
||||||
|
"autostart=true \n" \
|
||||||
|
"autorestart=true \n" \
|
||||||
|
"stderr_logfile=/dev/stdout \n" \
|
||||||
|
"stderr_logfile_maxbytes=0 \n" \
|
||||||
|
"stdout_logfile=/dev/stdout \n" \
|
||||||
|
"stdout_logfile_maxbytes=0 \n" | sed 's/ //' > /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
|
||||||
# ENV defaults
|
# ENV defaults
|
||||||
ENV TOOLJET_HOST=http://localhost \
|
ENV TOOLJET_HOST=http://localhost \
|
||||||
|
PORT=80 \
|
||||||
NODE_ENV=production \
|
NODE_ENV=production \
|
||||||
LOCKBOX_MASTER_KEY=replace_with_lockbox_master_key \
|
LOCKBOX_MASTER_KEY=replace_with_lockbox_master_key \
|
||||||
SECRET_KEY_BASE=replace_with_secret_key_base \
|
SECRET_KEY_BASE=replace_with_secret_key_base \
|
||||||
PG_DB=tooljet_production \
|
PG_DB=tooljet_production \
|
||||||
PG_USER=tooljet \
|
PG_USER=postgres \
|
||||||
PG_PASS=postgres \
|
PG_PASS=postgres \
|
||||||
PG_HOST=localhost \
|
PG_HOST=localhost \
|
||||||
ENABLE_TOOLJET_DB=true \
|
ENABLE_TOOLJET_DB=true \
|
||||||
TOOLJET_DB_HOST=localhost \
|
TOOLJET_DB_HOST=localhost \
|
||||||
TOOLJET_DB_USER=tooljet \
|
TOOLJET_DB_USER=postgres \
|
||||||
TOOLJET_DB_PASS=postgres \
|
TOOLJET_DB_PASS=postgres \
|
||||||
TOOLJET_DB=tooljet_db \
|
TOOLJET_DB=tooljet_db \
|
||||||
PGRST_HOST=http://localhost:3000 \
|
PGRST_HOST=http://localhost:3000 \
|
||||||
PGRST_DB_URI=postgres://tooljet:postgres@localhost/tooljet_db \
|
PGRST_DB_URI=postgres://postgres:postgres@localhost/tooljet_db \
|
||||||
PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \
|
PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \
|
||||||
PGRST_DB_PRE_CONFIG=postgrest.pre_config \
|
PGRST_DB_PRE_CONFIG=postgrest.pre_config \
|
||||||
ORM_LOGGING=true \
|
ORM_LOGGING=true \
|
||||||
|
|
@ -110,4 +139,7 @@ ENV TOOLJET_HOST=http://localhost \
|
||||||
HOME=/home/appuser \
|
HOME=/home/appuser \
|
||||||
TERM=xterm
|
TERM=xterm
|
||||||
|
|
||||||
CMD ["/usr/bin/supervisord"]
|
|
||||||
|
RUN chmod +x ./server/scripts/preview.sh
|
||||||
|
# Set the entrypoint
|
||||||
|
ENTRYPOINT ["./server/scripts/preview.sh"]
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ WORKDIR /app
|
||||||
ARG CUSTOM_GITHUB_TOKEN
|
ARG CUSTOM_GITHUB_TOKEN
|
||||||
ARG BRANCH_NAME
|
ARG BRANCH_NAME
|
||||||
|
|
||||||
# Clone and checkout the frontend repository
|
# Clone and checkout the frontend repositorys
|
||||||
RUN git config --global url."https://x-access-token:${CUSTOM_GITHUB_TOKEN}@github.com/".insteadOf "https://github.com/"
|
RUN git config --global url."https://x-access-token:${CUSTOM_GITHUB_TOKEN}@github.com/".insteadOf "https://github.com/"
|
||||||
|
|
||||||
RUN git config --global http.version HTTP/1.1
|
RUN git config --global http.version HTTP/1.1
|
||||||
|
|
@ -66,7 +66,7 @@ COPY --from=postgrest/postgrest:v12.2.0 /bin/postgrest /bin
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENV TOOLJET_EDITION=ee
|
ENV TOOLJET_EDITION=ee
|
||||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||||
RUN apt-get update && apt-get install -y postgresql-client freetds-dev libaio1 wget supervisor
|
RUN apt-get update && apt-get install -y freetds-dev libaio1 wget supervisor
|
||||||
|
|
||||||
# Install Instantclient Basic Light Oracle and Dependencies
|
# Install Instantclient Basic Light Oracle and Dependencies
|
||||||
WORKDIR /opt/oracle
|
WORKDIR /opt/oracle
|
||||||
|
|
@ -82,9 +82,6 @@ ENV LD_LIBRARY_PATH="/opt/oracle/instantclient_11_2:/opt/oracle/instantclient_21
|
||||||
|
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
|
|
||||||
RUN mkdir -p /app /var/log/supervisor
|
|
||||||
COPY /deploy/docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
|
||||||
|
|
||||||
# copy npm scripts
|
# copy npm scripts
|
||||||
COPY --from=builder /app/package.json ./app/package.json
|
COPY --from=builder /app/package.json ./app/package.json
|
||||||
# copy plugins dependencies
|
# copy plugins dependencies
|
||||||
|
|
@ -106,38 +103,73 @@ COPY --from=builder /app/server/dist ./app/server/dist
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# ENV defaults
|
# Install PostgreSQL
|
||||||
USER root
|
USER root
|
||||||
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
|
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
|
||||||
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list
|
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list
|
||||||
RUN echo "deb http://deb.debian.org/debian"
|
RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor --fix-missing
|
||||||
RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor
|
|
||||||
USER postgres
|
|
||||||
RUN service postgresql start && \
|
# Explicitly create PG main directory with correct ownership
|
||||||
psql -c "create role tooljet with login superuser password 'postgres';"
|
RUN mkdir -p /var/lib/postgresql/13/main && \
|
||||||
USER root
|
chown -R postgres:postgres /var/lib/postgresql
|
||||||
|
|
||||||
|
RUN mkdir -p /var/log/supervisor /var/run/postgresql && \
|
||||||
|
chown -R postgres:postgres /var/run/postgresql /var/log/supervisor
|
||||||
|
|
||||||
|
# Remove existing data and create directory with proper ownership
|
||||||
|
RUN rm -rf /var/lib/postgresql/13/main && \
|
||||||
|
mkdir -p /var/lib/postgresql/13/main && \
|
||||||
|
chown -R postgres:postgres /var/lib/postgresql
|
||||||
|
|
||||||
|
# Initialize PostgreSQL
|
||||||
|
RUN su - postgres -c "/usr/lib/postgresql/13/bin/initdb -D /var/lib/postgresql/13/main"
|
||||||
|
|
||||||
|
# Configure Supervisor to manage PostgREST, ToolJet, and Redis
|
||||||
|
RUN echo "[supervisord] \n" \
|
||||||
|
"nodaemon=true \n" \
|
||||||
|
"user=root \n" \
|
||||||
|
"\n" \
|
||||||
|
"[program:postgrest] \n" \
|
||||||
|
"command=/bin/postgrest \n" \
|
||||||
|
"autostart=true \n" \
|
||||||
|
"autorestart=true \n" \
|
||||||
|
"\n" \
|
||||||
|
"[program:tooljet] \n" \
|
||||||
|
"user=root \n" \
|
||||||
|
"command=/bin/bash -c '/app/server/scripts/boot.sh' \n" \
|
||||||
|
"autostart=true \n" \
|
||||||
|
"autorestart=true \n" \
|
||||||
|
"stderr_logfile=/dev/stdout \n" \
|
||||||
|
"stderr_logfile_maxbytes=0 \n" \
|
||||||
|
"stdout_logfile=/dev/stdout \n" \
|
||||||
|
"stdout_logfile_maxbytes=0 \n" | sed 's/ //' > /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
|
||||||
# ENV defaults
|
# ENV defaults
|
||||||
ENV TOOLJET_HOST=http://localhost \
|
ENV TOOLJET_HOST=http://localhost \
|
||||||
|
PORT=80 \
|
||||||
NODE_ENV=production \
|
NODE_ENV=production \
|
||||||
LOCKBOX_MASTER_KEY=replace_with_lockbox_master_key \
|
LOCKBOX_MASTER_KEY=replace_with_lockbox_master_key \
|
||||||
SECRET_KEY_BASE=replace_with_secret_key_base \
|
SECRET_KEY_BASE=replace_with_secret_key_base \
|
||||||
PG_DB=tooljet_production \
|
PG_DB=tooljet_production \
|
||||||
PG_USER=tooljet \
|
PG_USER=postgres \
|
||||||
PG_PASS=postgres \
|
PG_PASS=postgres \
|
||||||
PG_HOST=localhost \
|
PG_HOST=localhost \
|
||||||
ENABLE_TOOLJET_DB=true \
|
ENABLE_TOOLJET_DB=true \
|
||||||
TOOLJET_DB_HOST=localhost \
|
TOOLJET_DB_HOST=localhost \
|
||||||
TOOLJET_DB_USER=tooljet \
|
TOOLJET_DB_USER=postgres \
|
||||||
TOOLJET_DB_PASS=postgres \
|
TOOLJET_DB_PASS=postgres \
|
||||||
TOOLJET_DB=tooljet_db \
|
TOOLJET_DB=tooljet_db \
|
||||||
PGRST_HOST=http://localhost:3000 \
|
PGRST_HOST=http://localhost:3000 \
|
||||||
PGRST_DB_URI=postgres://tooljet:postgres@localhost/tooljet_db \
|
PGRST_DB_URI=postgres://postgres:postgres@localhost/tooljet_db \
|
||||||
PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \
|
PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \
|
||||||
PGRST_DB_PRE_CONFIG=postgrest.pre_config \
|
PGRST_DB_PRE_CONFIG=postgrest.pre_config \
|
||||||
ORM_LOGGING=true \
|
ORM_LOGGING=true \
|
||||||
DEPLOYMENT_PLATFORM=docker:local \
|
DEPLOYMENT_PLATFORM=docker:local \
|
||||||
REDIS_PASS= \
|
HOME=/home/appuser \
|
||||||
TERM=xterm
|
TERM=xterm
|
||||||
|
|
||||||
CMD ["/usr/bin/supervisord"]
|
|
||||||
|
RUN chmod +x ./server/scripts/preview.sh
|
||||||
|
# Set the entrypoint
|
||||||
|
ENTRYPOINT ["./server/scripts/preview.sh"]
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
3.11.0
|
3.12.1
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 518f3334b12a83785fd37dd53b0245d72848211a
|
Subproject commit 1b77a556709211daed8924821383db9dccc95eb5
|
||||||
|
|
@ -58,6 +58,7 @@
|
||||||
"dotenv": "^16.0.3",
|
"dotenv": "^16.0.3",
|
||||||
"draft-js": "^0.11.7",
|
"draft-js": "^0.11.7",
|
||||||
"draft-js-export-html": "^1.4.1",
|
"draft-js-export-html": "^1.4.1",
|
||||||
|
"draft-js-import-html": "^1.4.1",
|
||||||
"driver.js": "^0.9.8",
|
"driver.js": "^0.9.8",
|
||||||
"emoji-mart": "^5.5.2",
|
"emoji-mart": "^5.5.2",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,7 @@ export const getAllChildComponents = (allComponents, parentId) => {
|
||||||
const childTabId = componentParentId.split('-').at(-1);
|
const childTabId = componentParentId.split('-').at(-1);
|
||||||
if (componentParentId === `${parentId}-${childTabId}`) {
|
if (componentParentId === `${parentId}-${childTabId}`) {
|
||||||
childComponent.isParentTabORCalendar = true;
|
childComponent.isParentTabORCalendar = true;
|
||||||
|
childComponent.events = useStore.getState().eventsSlice.getEventsByComponentsId(componentId);
|
||||||
childComponents.push(childComponent);
|
childComponents.push(childComponent);
|
||||||
// Recursively find children of the current child component
|
// Recursively find children of the current child component
|
||||||
const childrenOfChild = getAllChildComponents(allComponents, componentId);
|
const childrenOfChild = getAllChildComponents(allComponents, componentId);
|
||||||
|
|
@ -242,6 +243,7 @@ export const getAllChildComponents = (allComponents, parentId) => {
|
||||||
if (componentParentId === parentId) {
|
if (componentParentId === parentId) {
|
||||||
let childComponent = deepClone(allComponents[componentId]);
|
let childComponent = deepClone(allComponents[componentId]);
|
||||||
childComponent.id = componentId;
|
childComponent.id = componentId;
|
||||||
|
childComponent.events = useStore.getState().eventsSlice.getEventsByComponentsId(componentId);
|
||||||
childComponents.push(childComponent);
|
childComponents.push(childComponent);
|
||||||
|
|
||||||
// Recursively find children of the current child component
|
// Recursively find children of the current child component
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* eslint-disable import/no-unresolved */
|
||||||
|
import React from 'react';
|
||||||
|
import { openSearchPanel } from '@codemirror/search';
|
||||||
|
import './SearchBox.scss';
|
||||||
|
import { Button as ButtonComponent } from '@/components/ui/Button/Button.jsx';
|
||||||
|
|
||||||
|
export const CodeHinterBtns = ({ view, isPanelOpen, renderCopilot }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="d-flex tw-flex-col align-items-end tw-gap-[2.5px] w-100 position-absolute tw-pt-[4px] tw-pr-[4px]"
|
||||||
|
style={{ top: isPanelOpen ? '44px' : 0 }}
|
||||||
|
>
|
||||||
|
{!isPanelOpen && (
|
||||||
|
<ButtonComponent
|
||||||
|
iconOnly
|
||||||
|
trailingIcon="search01"
|
||||||
|
size="small"
|
||||||
|
variant="outline"
|
||||||
|
ariaLabel="Open search panel"
|
||||||
|
className="codehinter-search-btn"
|
||||||
|
onClick={() => openSearchPanel(view)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{renderCopilot && renderCopilot()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -20,10 +20,12 @@ import { PreviewBox } from './PreviewBox';
|
||||||
import { removeNestedDoubleCurlyBraces } from '@/_helpers/utils';
|
import { removeNestedDoubleCurlyBraces } from '@/_helpers/utils';
|
||||||
import useStore from '@/AppBuilder/_stores/store';
|
import useStore from '@/AppBuilder/_stores/store';
|
||||||
import { shallow } from 'zustand/shallow';
|
import { shallow } from 'zustand/shallow';
|
||||||
|
import { syntaxTree } from '@codemirror/language';
|
||||||
import { search, searchKeymap, searchPanelOpen } from '@codemirror/search';
|
import { search, searchKeymap, searchPanelOpen } from '@codemirror/search';
|
||||||
import { handleSearchPanel, SearchBtn } from './SearchBox';
|
import { handleSearchPanel } from './SearchBox';
|
||||||
import { useQueryPanelKeyHooks } from './useQueryPanelKeyHooks';
|
import { useQueryPanelKeyHooks } from './useQueryPanelKeyHooks';
|
||||||
import { isInsideParent } from './utils';
|
import { isInsideParent } from './utils';
|
||||||
|
import { CodeHinterBtns } from './CodehinterOverlayTriggers';
|
||||||
|
|
||||||
const langSupport = Object.freeze({
|
const langSupport = Object.freeze({
|
||||||
javascript: javascript(),
|
javascript: javascript(),
|
||||||
|
|
@ -66,7 +68,7 @@ const MultiLineCodeEditor = (props) => {
|
||||||
|
|
||||||
const context = useContext(CodeHinterContext);
|
const context = useContext(CodeHinterContext);
|
||||||
|
|
||||||
const { suggestionList } = createReferencesLookup(context, true);
|
const { suggestionList: paramList } = createReferencesLookup(context, true);
|
||||||
|
|
||||||
const currentValueRef = useRef(initialValue);
|
const currentValueRef = useRef(initialValue);
|
||||||
|
|
||||||
|
|
@ -74,6 +76,7 @@ const MultiLineCodeEditor = (props) => {
|
||||||
|
|
||||||
const [editorView, setEditorView] = React.useState(null);
|
const [editorView, setEditorView] = React.useState(null);
|
||||||
|
|
||||||
|
const [isSearchPanelOpen, setIsSearchPanelOpen] = React.useState(false);
|
||||||
const { queryPanelKeybindings } = useQueryPanelKeyHooks(onChange, currentValueRef, 'multiline');
|
const { queryPanelKeybindings } = useQueryPanelKeyHooks(onChange, currentValueRef, 'multiline');
|
||||||
|
|
||||||
const handleOnBlur = () => {
|
const handleOnBlur = () => {
|
||||||
|
|
@ -146,8 +149,29 @@ const MultiLineCodeEditor = (props) => {
|
||||||
return suggestion.hint.includes(nearestSubstring);
|
return suggestion.hint.includes(nearestSubstring);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const localVariables = new Set();
|
||||||
|
|
||||||
|
// Traverse the syntax tree to extract variable declarations
|
||||||
|
syntaxTree(context.state).iterate({
|
||||||
|
enter: (node) => {
|
||||||
|
// JavaScript: Detect variable declarations (var, let, const)
|
||||||
|
if (node.name === 'VariableDefinition') {
|
||||||
|
const varName = context.state.sliceDoc(node.from, node.to);
|
||||||
|
if (varName && varName.startsWith(nearestSubstring)) localVariables.add(varName);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert Set to an array of completion suggestions
|
||||||
|
const localVariableSuggestions = [...localVariables].map((varName) => ({
|
||||||
|
hint: varName,
|
||||||
|
type: 'variable',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const suggestionList = paramList.filter((paramSuggestion) => paramSuggestion.hint.includes(nearestSubstring));
|
||||||
|
|
||||||
const suggestions = generateHints(
|
const suggestions = generateHints(
|
||||||
[...JSLangHints, ...autoSuggestionList, ...suggestionList],
|
[...localVariableSuggestions, ...JSLangHints, ...autoSuggestionList, ...suggestionList],
|
||||||
null,
|
null,
|
||||||
nearestSubstring
|
nearestSubstring
|
||||||
).map((hint) => {
|
).map((hint) => {
|
||||||
|
|
@ -204,6 +228,7 @@ const MultiLineCodeEditor = (props) => {
|
||||||
return {
|
return {
|
||||||
from: context.pos,
|
from: context.pos,
|
||||||
options: [...suggestions],
|
options: [...suggestions],
|
||||||
|
filter: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -237,7 +262,7 @@ const MultiLineCodeEditor = (props) => {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
const overRideFunction = React.useCallback((context) => autoCompleteExtensionConfig(context), []);
|
const overRideFunction = React.useCallback((context) => autoCompleteExtensionConfig(context), [paramList]);
|
||||||
const { handleTogglePopupExapand, isOpen, setIsOpen, forceUpdate } = portalProps;
|
const { handleTogglePopupExapand, isOpen, setIsOpen, forceUpdate } = portalProps;
|
||||||
let cyLabel = paramLabel ? paramLabel.toLowerCase().trim().replace(/\s+/g, '-') : props.cyLabel;
|
let cyLabel = paramLabel ? paramLabel.toLowerCase().trim().replace(/\s+/g, '-') : props.cyLabel;
|
||||||
|
|
||||||
|
|
@ -258,7 +283,7 @@ const MultiLineCodeEditor = (props) => {
|
||||||
ref={wrapperRef}
|
ref={wrapperRef}
|
||||||
>
|
>
|
||||||
<div className={`${className} ${darkMode && 'cm-codehinter-dark-themed'}`}>
|
<div className={`${className} ${darkMode && 'cm-codehinter-dark-themed'}`}>
|
||||||
<SearchBtn view={editorView} />
|
<CodeHinterBtns view={editorView} isPanelOpen={isSearchPanelOpen} renderCopilot={renderCopilot} />
|
||||||
<CodeHinter.PopupIcon
|
<CodeHinter.PopupIcon
|
||||||
callback={handleTogglePopupExapand}
|
callback={handleTogglePopupExapand}
|
||||||
icon="portal-open"
|
icon="portal-open"
|
||||||
|
|
@ -266,7 +291,6 @@ const MultiLineCodeEditor = (props) => {
|
||||||
isMultiEditor={true}
|
isMultiEditor={true}
|
||||||
isQueryManager={isInsideQueryPane}
|
isQueryManager={isInsideQueryPane}
|
||||||
/>
|
/>
|
||||||
{renderCopilot && renderCopilot()}
|
|
||||||
|
|
||||||
<CodeHinter.Portal
|
<CodeHinter.Portal
|
||||||
isCopilotEnabled={false}
|
isCopilotEnabled={false}
|
||||||
|
|
@ -326,12 +350,7 @@ const MultiLineCodeEditor = (props) => {
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
editable={editable} //for transformations in query manager
|
editable={editable} //for transformations in query manager
|
||||||
onCreateEditor={(view) => setEditorView(view)}
|
onCreateEditor={(view) => setEditorView(view)}
|
||||||
onUpdate={(view) => {
|
onUpdate={(view) => setIsSearchPanelOpen(searchPanelOpen(view.state))}
|
||||||
const icon = document.querySelector('.codehinter-search-btn');
|
|
||||||
if (searchPanelOpen(view.state)) {
|
|
||||||
icon.style.display = 'none';
|
|
||||||
} else icon.style.display = 'block';
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{showPreview && (
|
{showPreview && (
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import {
|
||||||
findPrevious,
|
findPrevious,
|
||||||
replaceNext,
|
replaceNext,
|
||||||
replaceAll,
|
replaceAll,
|
||||||
openSearchPanel,
|
|
||||||
} from '@codemirror/search';
|
} from '@codemirror/search';
|
||||||
import './SearchBox.scss';
|
import './SearchBox.scss';
|
||||||
import InputComponent from '@/components/ui/Input/Index.jsx';
|
import InputComponent from '@/components/ui/Input/Index.jsx';
|
||||||
|
|
@ -162,22 +161,3 @@ function SearchPanel({ view }) {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SearchBtn = ({ view }) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="d-flex justify-content-end w-100 position-absolute tw-pt-[3px] tw-pr-[4px] codehinter-search-btn-wrapper"
|
|
||||||
style={{ top: 0 }}
|
|
||||||
>
|
|
||||||
<ButtonComponent
|
|
||||||
iconOnly
|
|
||||||
trailingIcon="search01"
|
|
||||||
size="small"
|
|
||||||
variant="outline"
|
|
||||||
ariaLabel="Open search panel"
|
|
||||||
className="codehinter-search-btn"
|
|
||||||
onClick={() => openSearchPanel(view)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,5 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.code-hinter-wrapper .codehinter-search-btn {
|
.code-hinter-wrapper .codehinter-search-btn {
|
||||||
display: block;
|
z-index: 1000;
|
||||||
padding-top: 1px;
|
|
||||||
z-index: 10000;
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,12 +1,18 @@
|
||||||
/* eslint-disable import/no-unresolved */
|
/* eslint-disable import/no-unresolved */
|
||||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useEffect, useMemo, useRef, useState, useContext } from 'react';
|
||||||
import { PreviewBox } from './PreviewBox';
|
import { PreviewBox } from './PreviewBox';
|
||||||
import { ToolTip } from '@/Editor/Inspector/Elements/Components/ToolTip';
|
import { ToolTip } from '@/Editor/Inspector/Elements/Components/ToolTip';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { camelCase, isEmpty, noop, get } from 'lodash';
|
import { camelCase, isEmpty, noop, get } from 'lodash';
|
||||||
import CodeMirror from '@uiw/react-codemirror';
|
import CodeMirror from '@uiw/react-codemirror';
|
||||||
import { javascript } from '@codemirror/lang-javascript';
|
import { javascript } from '@codemirror/lang-javascript';
|
||||||
import { autocompletion, completionKeymap, completionStatus, acceptCompletion } from '@codemirror/autocomplete';
|
import {
|
||||||
|
autocompletion,
|
||||||
|
completionKeymap,
|
||||||
|
completionStatus,
|
||||||
|
acceptCompletion,
|
||||||
|
startCompletion,
|
||||||
|
} from '@codemirror/autocomplete';
|
||||||
import { defaultKeymap } from '@codemirror/commands';
|
import { defaultKeymap } from '@codemirror/commands';
|
||||||
import { keymap } from '@codemirror/view';
|
import { keymap } from '@codemirror/view';
|
||||||
import FxButton from '../CodeBuilder/Elements/FxButton';
|
import FxButton from '../CodeBuilder/Elements/FxButton';
|
||||||
|
|
@ -22,6 +28,8 @@ import CodeHinter from './CodeHinter';
|
||||||
import { removeNestedDoubleCurlyBraces } from '@/_helpers/utils';
|
import { removeNestedDoubleCurlyBraces } from '@/_helpers/utils';
|
||||||
import useStore from '@/AppBuilder/_stores/store';
|
import useStore from '@/AppBuilder/_stores/store';
|
||||||
import { shallow } from 'zustand/shallow';
|
import { shallow } from 'zustand/shallow';
|
||||||
|
import { CodeHinterContext } from '../CodeBuilder/CodeHinterContext';
|
||||||
|
import { createReferencesLookup } from '@/_stores/utils';
|
||||||
import { useQueryPanelKeyHooks } from './useQueryPanelKeyHooks';
|
import { useQueryPanelKeyHooks } from './useQueryPanelKeyHooks';
|
||||||
|
|
||||||
const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...restProps }) => {
|
const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...restProps }) => {
|
||||||
|
|
@ -73,6 +81,7 @@ const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...r
|
||||||
if (typeof initialValue === 'string' && (initialValue?.includes('components') || initialValue?.includes('queries'))) {
|
if (typeof initialValue === 'string' && (initialValue?.includes('components') || initialValue?.includes('queries'))) {
|
||||||
newInitialValue = replaceIdsWithName(initialValue);
|
newInitialValue = replaceIdsWithName(initialValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Re render the component when the componentName changes as the initialValue is not updated
|
//! Re render the component when the componentName changes as the initialValue is not updated
|
||||||
|
|
||||||
// const { variablesExposedForPreview } = useContext(EditorContext) || {};
|
// const { variablesExposedForPreview } = useContext(EditorContext) || {};
|
||||||
|
|
@ -199,9 +208,14 @@ const EditorInput = ({
|
||||||
wrapperRef,
|
wrapperRef,
|
||||||
showSuggestions,
|
showSuggestions,
|
||||||
}) => {
|
}) => {
|
||||||
const getServerSideGlobalSuggestions = useStore((state) => state.getServerSideGlobalSuggestions, shallow);
|
const codeHinterContext = useContext(CodeHinterContext);
|
||||||
|
const { suggestionList: paramHints } = createReferencesLookup(codeHinterContext, true);
|
||||||
|
|
||||||
const getSuggestions = useStore((state) => state.getSuggestions, shallow);
|
const getSuggestions = useStore((state) => state.getSuggestions, shallow);
|
||||||
|
const [codeMirrorView, setCodeMirrorView] = useState(undefined);
|
||||||
|
|
||||||
|
const getServerSideGlobalSuggestions = useStore((state) => state.getServerSideGlobalSuggestions, shallow);
|
||||||
|
|
||||||
const { queryPanelKeybindings } = useQueryPanelKeyHooks(onBlurUpdate, currentValue, 'singleline');
|
const { queryPanelKeybindings } = useQueryPanelKeyHooks(onBlurUpdate, currentValue, 'singleline');
|
||||||
|
|
||||||
const isInsideQueryManager = useMemo(
|
const isInsideQueryManager = useMemo(
|
||||||
|
|
@ -209,16 +223,16 @@ const EditorInput = ({
|
||||||
[wrapperRef.current]
|
[wrapperRef.current]
|
||||||
);
|
);
|
||||||
function autoCompleteExtensionConfig(context) {
|
function autoCompleteExtensionConfig(context) {
|
||||||
const hints = getSuggestions();
|
const hintsWithoutParamHints = getSuggestions();
|
||||||
const serverHints = getServerSideGlobalSuggestions(isInsideQueryManager);
|
const serverHints = getServerSideGlobalSuggestions(isInsideQueryManager);
|
||||||
|
|
||||||
const allHints = {
|
|
||||||
...hints,
|
|
||||||
appHints: [...hints.appHints, ...serverHints],
|
|
||||||
};
|
|
||||||
|
|
||||||
let word = context.matchBefore(/\w*/);
|
let word = context.matchBefore(/\w*/);
|
||||||
|
|
||||||
|
const hints = {
|
||||||
|
...hintsWithoutParamHints,
|
||||||
|
appHints: [...hintsWithoutParamHints.appHints, ...serverHints, ...paramHints],
|
||||||
|
};
|
||||||
|
|
||||||
const totalReferences = (context.state.doc.toString().match(/{{/g) || []).length;
|
const totalReferences = (context.state.doc.toString().match(/{{/g) || []).length;
|
||||||
|
|
||||||
let queryInput = context.state.doc.toString();
|
let queryInput = context.state.doc.toString();
|
||||||
|
|
@ -247,17 +261,18 @@ const EditorInput = ({
|
||||||
queryInput = '{{' + currentWord + '}}';
|
queryInput = '{{' + currentWord + '}}';
|
||||||
}
|
}
|
||||||
|
|
||||||
let completions = getAutocompletion(queryInput, validationType, allHints, totalReferences, originalQueryInput);
|
let completions = getAutocompletion(queryInput, validationType, hints, totalReferences, originalQueryInput);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
from: word.from,
|
from: word.from,
|
||||||
options: completions,
|
options: completions,
|
||||||
validFor: /^\{\{.*\}\}$/,
|
validFor: /^\{\{.*\}\}$/,
|
||||||
|
filter: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
const overRideFunction = React.useCallback((context) => autoCompleteExtensionConfig(context), [isInsideQueryManager]);
|
const overRideFunction = React.useCallback((context) => autoCompleteExtensionConfig(context), [isInsideQueryManager, paramHints]);
|
||||||
|
|
||||||
const autoCompleteConfig = autocompletion({
|
const autoCompleteConfig = autocompletion({
|
||||||
override: [overRideFunction],
|
override: [overRideFunction],
|
||||||
|
|
@ -424,6 +439,9 @@ const EditorInput = ({
|
||||||
ref={previewRef}
|
ref={previewRef}
|
||||||
>
|
>
|
||||||
<CodeMirror
|
<CodeMirror
|
||||||
|
onCreateEditor={(view) => {
|
||||||
|
setCodeMirrorView(view);
|
||||||
|
}}
|
||||||
value={currentValue}
|
value={currentValue}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
height={isInsideQueryPane ? '100%' : showLineNumbers ? '400px' : '100%'}
|
height={isInsideQueryPane ? '100%' : showLineNumbers ? '400px' : '100%'}
|
||||||
|
|
@ -460,11 +478,16 @@ const EditorInput = ({
|
||||||
theme={theme}
|
theme={theme}
|
||||||
indentWithTab={false}
|
indentWithTab={false}
|
||||||
readOnly={disabled}
|
readOnly={disabled}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
if (event.key === 'Backspace') {
|
||||||
|
startCompletion(codeMirrorView);
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary >
|
||||||
</CodeHinter.Portal>
|
</CodeHinter.Portal >
|
||||||
</div>
|
</div >
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,8 @@ export const getAutocompletion = (input, fieldType, hints, totalReferences = 1,
|
||||||
originalQueryInput,
|
originalQueryInput,
|
||||||
searchInput
|
searchInput
|
||||||
);
|
);
|
||||||
return orderSuggestions(suggestions, fieldType);
|
|
||||||
|
return suggestions;
|
||||||
};
|
};
|
||||||
|
|
||||||
function orderSuggestions(suggestions, validationType) {
|
function orderSuggestions(suggestions, validationType) {
|
||||||
|
|
@ -90,10 +91,18 @@ export const generateHints = (hints, totalReferences = 1, input, searchText) =>
|
||||||
const hasDepth = currentWord.includes('.');
|
const hasDepth = currentWord.includes('.');
|
||||||
const lastDepth = getLastSubstring(currentWord);
|
const lastDepth = getLastSubstring(currentWord);
|
||||||
|
|
||||||
const displayLabel = getLastDepth(displayedHint);
|
let displayLabel = getLastDepth(displayedHint);
|
||||||
|
|
||||||
|
if (type != 'js_method') {
|
||||||
|
const currentWordDepth = currentWord.split('.').length;
|
||||||
|
displayLabel = hint
|
||||||
|
.split('.')
|
||||||
|
.slice(currentWordDepth - 1)
|
||||||
|
.join('.');
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
displayLabel: lastDepth === '' ? displayedHint : displayLabel,
|
displayLabel,
|
||||||
label: displayedHint,
|
label: displayedHint,
|
||||||
info: displayedHint,
|
info: displayedHint,
|
||||||
type: type === 'js_method' ? 'js_methods' : type?.toLowerCase(),
|
type: type === 'js_method' ? 'js_methods' : type?.toLowerCase(),
|
||||||
|
|
@ -154,40 +163,24 @@ export const generateHints = (hints, totalReferences = 1, input, searchText) =>
|
||||||
};
|
};
|
||||||
|
|
||||||
function filterHintsByDepth(input, hints) {
|
function filterHintsByDepth(input, hints) {
|
||||||
if (input === '') return hints;
|
const inputParts = input.split('.');
|
||||||
|
const inputDepth = inputParts.length + 1;
|
||||||
|
|
||||||
const inputDepth = input.includes('.') ? input.split('.').length : 0;
|
const hintsWithDepth = hints.map((hint) => {
|
||||||
|
const hintParts = hint.hint.split('.');
|
||||||
const filteredHints = hints.filter((cm) => {
|
return {
|
||||||
const hintParts = cm.hint.split('.');
|
...hint,
|
||||||
|
depth: hintParts.length,
|
||||||
let shouldInclude =
|
};
|
||||||
(cm.hint.startsWith(input) && hintParts.length === inputDepth + 1) ||
|
|
||||||
(cm.hint.startsWith(input) && hintParts.length === inputDepth);
|
|
||||||
|
|
||||||
const shouldFuzzyMatch = !shouldInclude ? hintParts.length > inputDepth : false;
|
|
||||||
|
|
||||||
if (shouldFuzzyMatch) {
|
|
||||||
// fuzzy match
|
|
||||||
let matchedDepth = -1;
|
|
||||||
for (let i = 0; i < hintParts.length; i++) {
|
|
||||||
if (hintParts[i].includes(input)) {
|
|
||||||
matchedDepth = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matchedDepth !== -1) {
|
|
||||||
shouldInclude = hintParts.length === matchedDepth + 1;
|
|
||||||
}
|
|
||||||
} else if (input.endsWith('.')) {
|
|
||||||
shouldInclude = cm.hint.startsWith(input) && hintParts.length === inputDepth;
|
|
||||||
}
|
|
||||||
|
|
||||||
return shouldInclude;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return filteredHints;
|
const filteredHints = hintsWithDepth.filter((hint) => {
|
||||||
|
return hint.depth <= inputDepth;
|
||||||
|
});
|
||||||
|
|
||||||
|
const sortedHints = filteredHints.sort((hint1, hint2) => hint1.depth - hint2.depth);
|
||||||
|
|
||||||
|
return sortedHints;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findNearestSubstring(inputStr, currentCurosorPos) {
|
export function findNearestSubstring(inputStr, currentCurosorPos) {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,20 @@
|
||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import Select from '@/_ui/Select';
|
import Select from '@/_ui/Select';
|
||||||
import { decodeEntities } from '@/_helpers/utils';
|
import { decodeEntities } from '@/_helpers/utils';
|
||||||
|
import usePopoverObserver from '@/AppBuilder/_hooks/usePopoverObserver';
|
||||||
|
|
||||||
export const ChangeDataSource = ({ dataSources, onChange, value, isVersionReleased }) => {
|
export const ChangeDataSource = ({ dataSources, onChange, value, isVersionReleased }) => {
|
||||||
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||||
|
|
||||||
|
usePopoverObserver(
|
||||||
|
document.getElementsByClassName('query-details')[0],
|
||||||
|
document.querySelector('.change-data-source-select.react-select__control'),
|
||||||
|
document.querySelector('.change-data-source-select.react-select__menu'),
|
||||||
|
isMenuOpen,
|
||||||
|
() => (document.querySelector('.change-data-source-select.react-select__menu').style.display = 'block'),
|
||||||
|
() => (document.querySelector('.change-data-source-select.react-select__menu').style.display = 'none')
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
className="w-100"
|
className="w-100"
|
||||||
|
|
@ -14,6 +26,13 @@ export const ChangeDataSource = ({ dataSources, onChange, value, isVersionReleas
|
||||||
}}
|
}}
|
||||||
useMenuPortal={true}
|
useMenuPortal={true}
|
||||||
isDisabled={isVersionReleased}
|
isDisabled={isVersionReleased}
|
||||||
|
customClassPrefix="change-data-source-select"
|
||||||
|
onMenuOpen={() => {
|
||||||
|
setIsMenuOpen(true);
|
||||||
|
}}
|
||||||
|
onMenuClose={() => {
|
||||||
|
setIsMenuOpen(false);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ const RunButton = ({ buttonLoadingState }) => {
|
||||||
<ButtonComponent
|
<ButtonComponent
|
||||||
size="medium"
|
size="medium"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() => runQuery(selectedQuery?.id, selectedQuery?.name, undefined, 'edit', {}, true)}
|
onClick={() => runQuery(selectedQuery?.id, selectedQuery?.name, undefined, 'edit', {}, true, undefined, true)}
|
||||||
leadingIcon="play01"
|
leadingIcon="play01"
|
||||||
disabled={isInDraft}
|
disabled={isInDraft}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ class Restapi extends React.Component {
|
||||||
codeHinterHeight: 32, // Default height
|
codeHinterHeight: 32, // Default height
|
||||||
};
|
};
|
||||||
this.codeHinterRef = React.createRef();
|
this.codeHinterRef = React.createRef();
|
||||||
|
this.isMenuOpenRef = React.createRef();
|
||||||
|
this.prevIsMenuOpenRef = React.createRef(false);
|
||||||
|
this.intersectionObserver = null;
|
||||||
this.resizeObserver = null;
|
this.resizeObserver = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,6 +50,9 @@ class Restapi extends React.Component {
|
||||||
if (this.codeHinterRef.current && !this.resizeObserver) {
|
if (this.codeHinterRef.current && !this.resizeObserver) {
|
||||||
this.setupResizeObserver();
|
this.setupResizeObserver();
|
||||||
}
|
}
|
||||||
|
if (!this.intersectionObserver) {
|
||||||
|
this.setupIntersectionObserver();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
|
@ -75,6 +81,7 @@ class Restapi extends React.Component {
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
this.setupResizeObserver();
|
this.setupResizeObserver();
|
||||||
|
this.setupIntersectionObserver();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
@ -84,6 +91,9 @@ class Restapi extends React.Component {
|
||||||
if (this.resizeObserver) {
|
if (this.resizeObserver) {
|
||||||
this.resizeObserver.disconnect();
|
this.resizeObserver.disconnect();
|
||||||
}
|
}
|
||||||
|
if (this.intersectionObserver) {
|
||||||
|
this.intersectionObserver.disconnect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setupResizeObserver() {
|
setupResizeObserver() {
|
||||||
|
|
@ -132,6 +142,33 @@ class Restapi extends React.Component {
|
||||||
this.resizeObserver.observe(element);
|
this.resizeObserver.observe(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupIntersectionObserver() {
|
||||||
|
const container = document.getElementsByClassName('query-details')[0];
|
||||||
|
const trigger = document.querySelector('.restapi-method-select.react-select__control');
|
||||||
|
|
||||||
|
if (this.intersectionObserver) {
|
||||||
|
this.intersectionObserver.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.intersectionObserver = new IntersectionObserver(
|
||||||
|
([entry]) => {
|
||||||
|
const popover = document.querySelector('.restapi-method-select.react-select__menu');
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
if (this.prevIsMenuOpenRef.current) {
|
||||||
|
popover.style.display = 'block';
|
||||||
|
this.prevIsMenuOpenRef.current = false;
|
||||||
|
}
|
||||||
|
} else if (this.isMenuOpenRef.current) {
|
||||||
|
popover.style.display = 'none';
|
||||||
|
this.prevIsMenuOpenRef.current = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ root: container, threshold: [0.5] }
|
||||||
|
);
|
||||||
|
|
||||||
|
this.intersectionObserver.observe(trigger);
|
||||||
|
}
|
||||||
|
|
||||||
initizalizeRetryNetworkErrorsToggle = () => {
|
initizalizeRetryNetworkErrorsToggle = () => {
|
||||||
const isRetryNetworkErrorToggleUnused = this.props.options.retry_network_errors === null;
|
const isRetryNetworkErrorToggleUnused = this.props.options.retry_network_errors === null;
|
||||||
if (isRetryNetworkErrorToggleUnused) {
|
if (isRetryNetworkErrorToggleUnused) {
|
||||||
|
|
@ -287,6 +324,13 @@ class Restapi extends React.Component {
|
||||||
height={32}
|
height={32}
|
||||||
styles={this.customSelectStyles(this.props.darkMode, 91)}
|
styles={this.customSelectStyles(this.props.darkMode, 91)}
|
||||||
useCustomStyles={true}
|
useCustomStyles={true}
|
||||||
|
customClassPrefix="restapi-method-select"
|
||||||
|
onMenuOpen={() => {
|
||||||
|
this.isMenuOpenRef.current = true;
|
||||||
|
}}
|
||||||
|
onMenuClose={() => {
|
||||||
|
this.isMenuOpenRef.current = false;
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,11 @@ export const BulkUploadPrimaryKey = () => {
|
||||||
<div className="field flex-grow-1 minw-400-w-400">
|
<div className="field flex-grow-1 minw-400-w-400">
|
||||||
<CodeHinter
|
<CodeHinter
|
||||||
type="basic"
|
type="basic"
|
||||||
initialValue={`{{${JSON.stringify(bulkUpdatePrimaryKey?.rows_update ?? [])}}}`}
|
initialValue={
|
||||||
|
bulkUpdatePrimaryKey?.rows_update
|
||||||
|
? `{{${JSON.stringify(bulkUpdatePrimaryKey?.rows_update ?? [])}}}`
|
||||||
|
: null
|
||||||
|
}
|
||||||
className="codehinter-plugins"
|
className="codehinter-plugins"
|
||||||
placeholder="{{ [ { 'column1': 'value', ... } ] }}"
|
placeholder="{{ [ { 'column1': 'value', ... } ] }}"
|
||||||
onChange={(newValue) => {
|
onChange={(newValue) => {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
import React, { useContext, useEffect } from 'react';
|
||||||
|
import { TooljetDatabaseContext } from '@/TooljetDatabase/index';
|
||||||
|
import { resolveReferences } from '@/AppBuilder/CodeEditor/utils';
|
||||||
|
import CodeHinter from '@/AppBuilder/CodeEditor';
|
||||||
|
|
||||||
|
export const BulkUpsertPrimaryKey = () => {
|
||||||
|
const {
|
||||||
|
columns,
|
||||||
|
bulkUpsertPrimaryKey,
|
||||||
|
handleBulkUpsertRowsOptionChanged,
|
||||||
|
handlePrimaryKeyOptionChangedForBulkUpsert,
|
||||||
|
} = useContext(TooljetDatabaseContext);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const primaryKeys = columns.reduce((acc, column) => {
|
||||||
|
if (column?.keytype === 'PRIMARY KEY' || column?.isPrimaryKey) {
|
||||||
|
acc.push(column?.accessor);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (primaryKeys.length > 0) {
|
||||||
|
handlePrimaryKeyOptionChangedForBulkUpsert(primaryKeys);
|
||||||
|
}
|
||||||
|
}, [columns]);
|
||||||
|
|
||||||
|
const handleRowsChange = (value) => {
|
||||||
|
handleBulkUpsertRowsOptionChanged(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="tab-content-wrapper tj-db-field-wrapper mt-2 d-flex flex-column custom-gap-16">
|
||||||
|
<div className="field-container d-flex tooljetdb-worflow-operations">
|
||||||
|
<label className="form-label flex-shrink-0">Primary key</label>
|
||||||
|
<div
|
||||||
|
className="field flex-grow-1 minw-400-w-400 px-1"
|
||||||
|
style={{ height: '28px', background: 'var(--controls-switch-tag)', borderRadius: '6px' }}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={bulkUpsertPrimaryKey?.primary_key?.join(', ') || ''}
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
border: '0',
|
||||||
|
color: 'var(--text-placeholder)',
|
||||||
|
background: 'transparent',
|
||||||
|
}}
|
||||||
|
disabled
|
||||||
|
placeholder={''}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="field-container d-flex tooljetdb-worflow-operations">
|
||||||
|
<label className="form-label flex-shrink-0" data-cy="">
|
||||||
|
Rows to upsert
|
||||||
|
</label>
|
||||||
|
<div className="field flex-grow-1 minw-400-w-400">
|
||||||
|
<CodeHinter
|
||||||
|
type="basic"
|
||||||
|
initialValue={
|
||||||
|
bulkUpsertPrimaryKey?.rows
|
||||||
|
? typeof bulkUpsertPrimaryKey?.rows === 'string'
|
||||||
|
? bulkUpsertPrimaryKey?.rows
|
||||||
|
: JSON.stringify(bulkUpsertPrimaryKey?.rows)
|
||||||
|
: bulkUpsertPrimaryKey?.rows
|
||||||
|
}
|
||||||
|
className="codehinter-plugins"
|
||||||
|
placeholder="{{ [ { 'column1': 'value', ... } ] }}"
|
||||||
|
onChange={handleRowsChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BulkUpsertPrimaryKey;
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import CodeHinter from '@/AppBuilder/CodeEditor';
|
import CodeHinter from '@/AppBuilder/CodeEditor';
|
||||||
import { resolveReferences } from '@/Editor/CodeEditor/utils';
|
|
||||||
import { ButtonSolid } from '@/_ui/AppButton/AppButton';
|
import { ButtonSolid } from '@/_ui/AppButton/AppButton';
|
||||||
import Trash from '@/_ui/Icon/solidIcons/Trash';
|
import Trash from '@/_ui/Icon/solidIcons/Trash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
@ -43,8 +42,7 @@ const RenderColumnUI = ({
|
||||||
placeholder="key"
|
placeholder="key"
|
||||||
onChange={(newValue) => {
|
onChange={(newValue) => {
|
||||||
if (isJSonTypeColumn) {
|
if (isJSonTypeColumn) {
|
||||||
const [_, __, resolvedValue] = resolveReferences(`{{${newValue}}}`);
|
handleValueChange(newValue);
|
||||||
handleValueChange(resolvedValue);
|
|
||||||
} else {
|
} else {
|
||||||
handleValueChange(newValue);
|
handleValueChange(newValue);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,9 @@ function DataSourceSelect({
|
||||||
if (isFirstPageLoaded && offset >= totalRecords) return;
|
if (isFirstPageLoaded && offset >= totalRecords) return;
|
||||||
if (foreignKeys.length < 1) return;
|
if (foreignKeys.length < 1) return;
|
||||||
setIsLoadingFKDetails(true);
|
setIsLoadingFKDetails(true);
|
||||||
const referencedColumns = foreignKeys.find((item) => item.column_names[0] === cellColumnName);
|
const referencedColumns = Array.isArray(foreignKeys)
|
||||||
|
? foreignKeys.find((item) => item.column_names[0] === cellColumnName)
|
||||||
|
: undefined;
|
||||||
if (!referencedColumns?.referenced_column_names?.length) return;
|
if (!referencedColumns?.referenced_column_names?.length) return;
|
||||||
|
|
||||||
const selectQuery = new PostgrestQueryBuilder();
|
const selectQuery = new PostgrestQueryBuilder();
|
||||||
|
|
@ -709,7 +711,8 @@ const MenuList = ({
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const menuListStyles = getStyles('menuList', props);
|
const menuListStyles = getStyles('menuList', props);
|
||||||
const referencedColumnDetails = foreignKeys?.find((item) => item.column_names[0] === cellColumnName);
|
const referencedColumnDetails =
|
||||||
|
Array.isArray(foreignKeys) && foreignKeys?.find((item) => item?.column_names[0] === cellColumnName);
|
||||||
|
|
||||||
const handleNavigateToReferencedTable = () => {
|
const handleNavigateToReferencedTable = () => {
|
||||||
const data = {
|
const data = {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import { getPrivateRoute } from '@/_helpers/routes';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { deepClone } from '@/_helpers/utilities/utils.helpers';
|
import { deepClone } from '@/_helpers/utilities/utils.helpers';
|
||||||
import { BulkUploadPrimaryKey } from './BulkUploadPrimaryKey';
|
import { BulkUploadPrimaryKey } from './BulkUploadPrimaryKey';
|
||||||
|
import BulkUpsertPrimaryKey from './BulkUpsertPrimaryKey';
|
||||||
|
|
||||||
import './styles.scss';
|
import './styles.scss';
|
||||||
import CodeHinter from '@/AppBuilder/CodeEditor';
|
import CodeHinter from '@/AppBuilder/CodeEditor';
|
||||||
|
|
@ -46,6 +47,7 @@ const ToolJetDbOperations = ({ optionchanged, options, darkMode, isHorizontalLay
|
||||||
const [tableForeignKeyInfo, setTableForeignKeyInfo] = useState({});
|
const [tableForeignKeyInfo, setTableForeignKeyInfo] = useState({});
|
||||||
|
|
||||||
const [bulkUpdatePrimaryKey, setBulkUpdatePrimaryKey] = useState(() => options['bulk_update_with_primary_key'] || {});
|
const [bulkUpdatePrimaryKey, setBulkUpdatePrimaryKey] = useState(() => options['bulk_update_with_primary_key'] || {});
|
||||||
|
const [bulkUpsertPrimaryKey, setBulkUpsertPrimaryKey] = useState(() => options['bulk_upsert_with_primary_key'] || {});
|
||||||
|
|
||||||
const joinOptions = options['join_table']?.['joins'] || [
|
const joinOptions = options['join_table']?.['joins'] || [
|
||||||
{ conditions: { conditionsList: [{ leftField: { table: selectedTableId } }] } },
|
{ conditions: { conditionsList: [{ leftField: { table: selectedTableId } }] } },
|
||||||
|
|
@ -196,6 +198,11 @@ const ToolJetDbOperations = ({ optionchanged, options, darkMode, isHorizontalLay
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [bulkUpdatePrimaryKey]);
|
}, [bulkUpdatePrimaryKey]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
mounted && optionchanged('bulk_upsert_with_primary_key', bulkUpsertPrimaryKey);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [bulkUpsertPrimaryKey]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
mounted && optionchanged('update_rows', updateRowsOptions);
|
mounted && optionchanged('update_rows', updateRowsOptions);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
|
@ -234,10 +241,18 @@ const ToolJetDbOperations = ({ optionchanged, options, darkMode, isHorizontalLay
|
||||||
setBulkUpdatePrimaryKey((prev) => ({ ...prev, rows_update: value }));
|
setBulkUpdatePrimaryKey((prev) => ({ ...prev, rows_update: value }));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleBulkUpsertRowsOptionChanged = (value) => {
|
||||||
|
setBulkUpsertPrimaryKey((prev) => ({ ...prev, rows: value }));
|
||||||
|
};
|
||||||
|
|
||||||
const handlePrimaryKeyOptionChangedForBulkUpdate = (value) => {
|
const handlePrimaryKeyOptionChangedForBulkUpdate = (value) => {
|
||||||
setBulkUpdatePrimaryKey((prev) => ({ ...prev, primary_key: value }));
|
setBulkUpdatePrimaryKey((prev) => ({ ...prev, primary_key: value }));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handlePrimaryKeyOptionChangedForBulkUpsert = (value) => {
|
||||||
|
setBulkUpsertPrimaryKey((prev) => ({ ...prev, primary_key: value }));
|
||||||
|
};
|
||||||
|
|
||||||
const loadTableInformation = async (tableId, isNewTableAdded) => {
|
const loadTableInformation = async (tableId, isNewTableAdded) => {
|
||||||
const tableDetails = findTableDetails(tableId);
|
const tableDetails = findTableDetails(tableId);
|
||||||
if (tableDetails?.table_name && !tableInfo[tableDetails?.table_name]) {
|
if (tableDetails?.table_name && !tableInfo[tableDetails?.table_name]) {
|
||||||
|
|
@ -340,8 +355,11 @@ const ToolJetDbOperations = ({ optionchanged, options, darkMode, isHorizontalLay
|
||||||
tableForeignKeyInfo,
|
tableForeignKeyInfo,
|
||||||
setTableForeignKeyInfo,
|
setTableForeignKeyInfo,
|
||||||
bulkUpdatePrimaryKey,
|
bulkUpdatePrimaryKey,
|
||||||
|
bulkUpsertPrimaryKey,
|
||||||
handleBulkUpdateWithPrimaryKeysRowsUpdateOptionChanged,
|
handleBulkUpdateWithPrimaryKeysRowsUpdateOptionChanged,
|
||||||
|
handleBulkUpsertRowsOptionChanged,
|
||||||
handlePrimaryKeyOptionChangedForBulkUpdate,
|
handlePrimaryKeyOptionChangedForBulkUpdate,
|
||||||
|
handlePrimaryKeyOptionChangedForBulkUpsert,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
organizationId,
|
organizationId,
|
||||||
|
|
@ -357,6 +375,7 @@ const ToolJetDbOperations = ({ optionchanged, options, darkMode, isHorizontalLay
|
||||||
joinOrderByOptions,
|
joinOrderByOptions,
|
||||||
selectedTableId,
|
selectedTableId,
|
||||||
bulkUpdatePrimaryKey,
|
bulkUpdatePrimaryKey,
|
||||||
|
bulkUpsertPrimaryKey,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -517,6 +536,8 @@ const ToolJetDbOperations = ({ optionchanged, options, darkMode, isHorizontalLay
|
||||||
return JoinTable;
|
return JoinTable;
|
||||||
case 'bulk_update_with_primary_key':
|
case 'bulk_update_with_primary_key':
|
||||||
return BulkUploadPrimaryKey;
|
return BulkUploadPrimaryKey;
|
||||||
|
case 'bulk_upsert_with_primary_key':
|
||||||
|
return BulkUpsertPrimaryKey;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -527,6 +548,7 @@ const ToolJetDbOperations = ({ optionchanged, options, darkMode, isHorizontalLay
|
||||||
{ label: 'Delete rows', value: 'delete_rows' },
|
{ label: 'Delete rows', value: 'delete_rows' },
|
||||||
{ label: 'Join tables', value: 'join_tables' },
|
{ label: 'Join tables', value: 'join_tables' },
|
||||||
{ label: 'Bulk update with primary key', value: 'bulk_update_with_primary_key' },
|
{ label: 'Bulk update with primary key', value: 'bulk_update_with_primary_key' },
|
||||||
|
{ label: 'Bulk upsert with primary key', value: 'bulk_upsert_with_primary_key' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const ComponentToRender = getComponent(operation);
|
const ComponentToRender = getComponent(operation);
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,25 @@ import CodeHinter from '@/AppBuilder/CodeEditor';
|
||||||
import './workflows-query.scss';
|
import './workflows-query.scss';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import useStore from '@/AppBuilder/_stores/store';
|
import useStore from '@/AppBuilder/_stores/store';
|
||||||
|
import usePopoverObserver from '@/AppBuilder/_hooks/usePopoverObserver';
|
||||||
|
|
||||||
export function Workflows({ options, optionsChanged, currentState }) {
|
export function Workflows({ options, optionsChanged, currentState }) {
|
||||||
const [workflowOptions, setWorkflowOptions] = useState([]);
|
const [workflowOptions, setWorkflowOptions] = useState([]);
|
||||||
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||||
const [_selectedWorkflowId, setSelectedWorkflowId] = useState(undefined);
|
const [_selectedWorkflowId, setSelectedWorkflowId] = useState(undefined);
|
||||||
const [params, setParams] = useState([...(options.params ?? [{ key: '', value: '' }])]);
|
const [params, setParams] = useState([...(options.params ?? [{ key: '', value: '' }])]);
|
||||||
|
|
||||||
const appId = useStore((state) => state.app.appId);
|
const appId = useStore((state) => state.app.appId);
|
||||||
|
|
||||||
|
usePopoverObserver(
|
||||||
|
document.getElementsByClassName('query-details')[0],
|
||||||
|
document.querySelector('.workflow-select.react-select__control'),
|
||||||
|
document.querySelector('.workflow-select.react-select__menu'),
|
||||||
|
isMenuOpen,
|
||||||
|
() => (document.querySelector('.workflow-select.react-select__menu').style.display = 'block'),
|
||||||
|
() => (document.querySelector('.workflow-select.react-select__menu').style.display = 'none')
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
appsService.getWorkflows(appId).then(({ workflows }) => {
|
appsService.getWorkflows(appId).then(({ workflows }) => {
|
||||||
setWorkflowOptions(
|
setWorkflowOptions(
|
||||||
|
|
@ -50,6 +61,13 @@ export function Workflows({ options, optionsChanged, currentState }) {
|
||||||
customWrap={true}
|
customWrap={true}
|
||||||
width="300px"
|
width="300px"
|
||||||
menuPlacement="bottom"
|
menuPlacement="bottom"
|
||||||
|
customClassPrefix="workflow-select"
|
||||||
|
onMenuOpen={() => {
|
||||||
|
setIsMenuOpen(true);
|
||||||
|
}}
|
||||||
|
onMenuClose={() => {
|
||||||
|
setIsMenuOpen(false);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<label className="my-2">Params</label>
|
<label className="my-2">Params</label>
|
||||||
<div className="grid"></div>
|
<div className="grid"></div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,538 @@
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import Accordion from '@/_ui/Accordion';
|
||||||
|
import { EventManager } from '../EventManager';
|
||||||
|
import { renderElement } from '../Utils';
|
||||||
|
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
|
||||||
|
import Popover from 'react-bootstrap/Popover';
|
||||||
|
import List from '@/ToolJetUI/List/List';
|
||||||
|
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
|
||||||
|
import useStore from '@/AppBuilder/_stores/store';
|
||||||
|
import CodeHinter from '@/AppBuilder/CodeEditor';
|
||||||
|
import AddNewButton from '@/ToolJetUI/Buttons/AddNewButton/AddNewButton';
|
||||||
|
import ListGroup from 'react-bootstrap/ListGroup';
|
||||||
|
import { ButtonSolid } from '@/_ui/AppButton/AppButton';
|
||||||
|
import SortableList from '@/_components/SortableList';
|
||||||
|
import Trash from '@/_ui/Icon/solidIcons/Trash';
|
||||||
|
import { shallow } from 'zustand/shallow';
|
||||||
|
import Switch from '@/Editor/CodeBuilder/Elements/Switch';
|
||||||
|
import { usePrevious } from '@dnd-kit/utilities';
|
||||||
|
|
||||||
|
export function Steps({ componentMeta, darkMode, ...restProps }) {
|
||||||
|
const {
|
||||||
|
layoutPropertyChanged,
|
||||||
|
component,
|
||||||
|
dataQueries,
|
||||||
|
paramUpdated,
|
||||||
|
currentState,
|
||||||
|
eventsChanged,
|
||||||
|
apps,
|
||||||
|
allComponents,
|
||||||
|
pages,
|
||||||
|
} = restProps;
|
||||||
|
const getResolvedValue = useStore((state) => state.getResolvedValue, shallow);
|
||||||
|
|
||||||
|
const isDynamicOptionsEnabled = getResolvedValue(component?.component?.definition?.properties?.advanced?.value);
|
||||||
|
const variant = component?.component?.definition?.properties?.variant?.value;
|
||||||
|
const prevVariant = usePrevious(variant)
|
||||||
|
console.log("variant", component?.component?.definition);
|
||||||
|
|
||||||
|
|
||||||
|
const [options, setOptions] = useState([]);
|
||||||
|
const [hoveredOptionIndex, setHoveredOptionIndex] = useState(null);
|
||||||
|
let properties = [];
|
||||||
|
let additionalActions = [];
|
||||||
|
let optionsProperties = [];
|
||||||
|
|
||||||
|
for (const [key] of Object.entries(componentMeta?.properties)) {
|
||||||
|
if (componentMeta?.properties[key]?.section === 'additionalActions') {
|
||||||
|
additionalActions.push(key);
|
||||||
|
} else if (componentMeta?.properties[key]?.accordian === 'Options') {
|
||||||
|
optionsProperties.push(key);
|
||||||
|
} else {
|
||||||
|
properties.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the default style of "number" & "titles" type are different for completed label
|
||||||
|
// TODO: Need to revisit this logic when text custom themes are implemented
|
||||||
|
useEffect(() => {
|
||||||
|
const completedLabelColor = component?.component?.definition?.styles?.completedLabel?.value;
|
||||||
|
if (variant !== prevVariant) {
|
||||||
|
if (variant === "numbers" && completedLabelColor === "#1B1F24") {
|
||||||
|
paramUpdated({ name: 'completedLabel' }, 'value', "#FFFFFF", 'styles', false, {});
|
||||||
|
} else if (variant === "titles" && completedLabelColor === "#FFFFFF") {
|
||||||
|
paramUpdated({ name: 'completedLabel' }, 'value', "#1B1F24", 'styles', false, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [variant])
|
||||||
|
|
||||||
|
const getItemStyle = (isDragging, draggableStyle) => ({
|
||||||
|
userSelect: 'none',
|
||||||
|
...draggableStyle,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateAllOptionsParams = (options, props) => {
|
||||||
|
paramUpdated({ name: 'steps' }, 'value', options, 'properties', false, props);
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateNewOptions = () => {
|
||||||
|
let found = false;
|
||||||
|
let label = '';
|
||||||
|
let currentNumber = options.length + 1;
|
||||||
|
while (!found) {
|
||||||
|
label = `step ${currentNumber}`;
|
||||||
|
if (options.find((option) => option.name === label) === undefined) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
currentNumber += 1;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: label,
|
||||||
|
id: currentNumber - 1,
|
||||||
|
tooltip: label,
|
||||||
|
visible: { value: '{{true}}' },
|
||||||
|
disabled: { value: '{{false}}' },
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddOption = () => {
|
||||||
|
let _option = generateNewOptions();
|
||||||
|
const _items = [...options, _option];
|
||||||
|
setOptions(_items);
|
||||||
|
updateAllOptionsParams(_items);
|
||||||
|
};
|
||||||
|
const handleDeleteOption = (index) => {
|
||||||
|
const _items = options.filter((option, i) => i !== index);
|
||||||
|
setOptions(_items);
|
||||||
|
updateAllOptionsParams(_items, { isParamFromDropdownOptions: true });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLabelChange = (propertyName, value, index) => {
|
||||||
|
const _options = options.map((option, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
return {
|
||||||
|
...option,
|
||||||
|
[propertyName]: value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return option;
|
||||||
|
});
|
||||||
|
setOptions(_options);
|
||||||
|
updateAllOptionsParams(_options);
|
||||||
|
};
|
||||||
|
|
||||||
|
const reorderOptions = async (startIndex, endIndex) => {
|
||||||
|
const result = [...options];
|
||||||
|
const [removed] = result.splice(startIndex, 1);
|
||||||
|
result.splice(endIndex, 0, removed);
|
||||||
|
setOptions(result);
|
||||||
|
updateAllOptionsParams(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDragEnd = ({ source, destination }) => {
|
||||||
|
if (!destination || source?.index === destination?.index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reorderOptions(source.index, destination.index);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnFxPress = (active, index, key) => {
|
||||||
|
const _options = options.map((option, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
return {
|
||||||
|
...option,
|
||||||
|
[key]: {
|
||||||
|
...option[key],
|
||||||
|
fxActive: active,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return option;
|
||||||
|
});
|
||||||
|
setOptions(_options);
|
||||||
|
updateAllOptionsParams(_options);
|
||||||
|
};
|
||||||
|
|
||||||
|
const _renderOverlay = (item, index) => {
|
||||||
|
return (
|
||||||
|
<Popover className={`${darkMode && 'dark-theme theme-dark'}`} style={{ minWidth: '248px' }}>
|
||||||
|
<Popover.Body>
|
||||||
|
<div className="field mb-3" data-cy={`input-and-label-column-name`}>
|
||||||
|
<label data-cy={`label-column-name`} className="font-weight-500 mb-1 font-size-12">
|
||||||
|
{'Id'}
|
||||||
|
</label>
|
||||||
|
<CodeHinter
|
||||||
|
type={'basic'}
|
||||||
|
initialValue={item?.id + ''}
|
||||||
|
theme={darkMode ? 'monokai' : 'default'}
|
||||||
|
mode="javascript"
|
||||||
|
lineNumbers={false}
|
||||||
|
placeholder={'Option label'}
|
||||||
|
onChange={(value) => handleLabelChange('id', value, index)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="field mb-3" data-cy={`input-and-label-column-name`}>
|
||||||
|
<label data-cy={`label-column-name`} className="font-weight-500 mb-1 font-size-12">
|
||||||
|
{'Label'}
|
||||||
|
</label>
|
||||||
|
<CodeHinter
|
||||||
|
type={'basic'}
|
||||||
|
initialValue={item?.name}
|
||||||
|
theme={darkMode ? 'monokai' : 'default'}
|
||||||
|
mode="javascript"
|
||||||
|
lineNumbers={false}
|
||||||
|
placeholder={'Option label'}
|
||||||
|
onChange={(value) => handleLabelChange('name', value, index)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="field mb-3" data-cy={`input-and-label-column-name`}>
|
||||||
|
<label data-cy={`label-column-name`} className="font-weight-500 mb-1 font-size-12">
|
||||||
|
{'Tooltip'}
|
||||||
|
</label>
|
||||||
|
<CodeHinter
|
||||||
|
type={'basic'}
|
||||||
|
initialValue={item?.tooltip + ''}
|
||||||
|
theme={darkMode ? 'monokai' : 'default'}
|
||||||
|
mode="javascript"
|
||||||
|
lineNumbers={false}
|
||||||
|
placeholder={'Tooltip'}
|
||||||
|
onChange={(value) => handleLabelChange('tooltip', value, index)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="field mb-2" data-cy={`input-and-label-column-name`}>
|
||||||
|
<CodeHinter
|
||||||
|
initialValue={item?.visible?.value}
|
||||||
|
theme={darkMode ? 'monokai' : 'default'}
|
||||||
|
mode="javascript"
|
||||||
|
lineNumbers={false}
|
||||||
|
component={component}
|
||||||
|
type={'fxEditor'}
|
||||||
|
paramLabel={'Visibility'}
|
||||||
|
onChange={(value) =>
|
||||||
|
handleLabelChange(
|
||||||
|
'visible',
|
||||||
|
{
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
index
|
||||||
|
)
|
||||||
|
}
|
||||||
|
paramName={'visible'}
|
||||||
|
onFxPress={(active) => handleOnFxPress(active, index, 'visible')}
|
||||||
|
fxActive={item?.visible?.fxActive}
|
||||||
|
fieldMeta={{
|
||||||
|
type: 'toggle',
|
||||||
|
displayName: 'Make editable',
|
||||||
|
}}
|
||||||
|
paramType={'toggle'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="field" data-cy={`input-and-label-column-name`}>
|
||||||
|
<CodeHinter
|
||||||
|
initialValue={item?.disabled?.value}
|
||||||
|
theme={darkMode ? 'monokai' : 'default'}
|
||||||
|
mode="javascript"
|
||||||
|
lineNumbers={false}
|
||||||
|
component={component}
|
||||||
|
type={'fxEditor'}
|
||||||
|
paramLabel={'Disable'}
|
||||||
|
paramName={'disable'}
|
||||||
|
onChange={(value) => handleLabelChange('disabled', { value }, index)}
|
||||||
|
onFxPress={(active) => handleOnFxPress(active, index, 'disabled')}
|
||||||
|
fxActive={item?.disabled?.fxActive}
|
||||||
|
fieldMeta={{
|
||||||
|
type: 'toggle',
|
||||||
|
displayName: 'Make editable',
|
||||||
|
}}
|
||||||
|
paramType={'toggle'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Popover.Body>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const _renderOptions = () => {
|
||||||
|
return (
|
||||||
|
<List style={{ marginBottom: '20px' }}>
|
||||||
|
<DragDropContext
|
||||||
|
onDragEnd={(result) => {
|
||||||
|
onDragEnd(result);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Droppable droppableId="droppable">
|
||||||
|
{({ innerRef, droppableProps, placeholder }) => (
|
||||||
|
<div className="w-100" {...droppableProps} ref={innerRef}>
|
||||||
|
{options?.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<Draggable key={item.name} draggableId={item.name} index={index}>
|
||||||
|
{(provided, snapshot) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
ref={provided.innerRef}
|
||||||
|
{...provided.draggableProps}
|
||||||
|
{...provided.dragHandleProps}
|
||||||
|
style={getItemStyle(snapshot.isDragging, provided.draggableProps.style)}
|
||||||
|
>
|
||||||
|
<OverlayTrigger
|
||||||
|
trigger="click"
|
||||||
|
placement="left"
|
||||||
|
rootClose
|
||||||
|
overlay={_renderOverlay(item, index)}
|
||||||
|
>
|
||||||
|
<div key={item.name + item.id}>
|
||||||
|
<ListGroup.Item
|
||||||
|
style={{ marginBottom: '8px', backgroundColor: 'var(--slate3)' }}
|
||||||
|
onMouseEnter={() => setHoveredOptionIndex(index)}
|
||||||
|
onMouseLeave={() => setHoveredOptionIndex(null)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-auto d-flex align-items-center">
|
||||||
|
<SortableList.DragHandle show />
|
||||||
|
</div>
|
||||||
|
<div className="col text-truncate cursor-pointer" style={{ padding: '0px' }}>
|
||||||
|
{getResolvedValue(item.name)}
|
||||||
|
</div>
|
||||||
|
<div className="col-auto">
|
||||||
|
{index === hoveredOptionIndex && (
|
||||||
|
<ButtonSolid
|
||||||
|
variant="danger"
|
||||||
|
size="xs"
|
||||||
|
className={'delete-icon-btn'}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleDeleteOption(index);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="d-flex">
|
||||||
|
<Trash fill={'var(--tomato9)'} width={12} />
|
||||||
|
</span>
|
||||||
|
</ButtonSolid>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ListGroup.Item>
|
||||||
|
</div>
|
||||||
|
</OverlayTrigger>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Draggable>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{placeholder}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Droppable>
|
||||||
|
</DragDropContext>
|
||||||
|
<AddNewButton onClick={handleAddOption} dataCy="add-new-dropdown-option" className="mt-0">
|
||||||
|
Add new option
|
||||||
|
</AddNewButton>
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isDynamicStepsEnabled = getResolvedValue(component?.component?.definition?.properties?.advanced?.value);
|
||||||
|
useEffect(() => {
|
||||||
|
setOptions(constructSteps());
|
||||||
|
}, [component?.id, isDynamicStepsEnabled]);
|
||||||
|
|
||||||
|
const constructSteps = () => {
|
||||||
|
try {
|
||||||
|
let optionsValue = isDynamicOptionsEnabled
|
||||||
|
? component?.component?.definition?.properties?.schema?.value
|
||||||
|
: component?.component?.definition?.properties?.steps?.value;
|
||||||
|
let options = [];
|
||||||
|
|
||||||
|
if (isDynamicOptionsEnabled || typeof optionsValue === 'string') {
|
||||||
|
options = getResolvedValue(optionsValue);
|
||||||
|
} else {
|
||||||
|
options = optionsValue?.map((option) => option);
|
||||||
|
}
|
||||||
|
return options.map((option) => {
|
||||||
|
const newOption = { ...option };
|
||||||
|
|
||||||
|
Object.keys(option).forEach((key) => {
|
||||||
|
if (typeof option[key]?.value === 'boolean') {
|
||||||
|
newOption[key]['value'] = `{{${option[key]?.value}}}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!('visible' in newOption)) {
|
||||||
|
newOption['visible'] = { value: '{{true}}' };
|
||||||
|
}
|
||||||
|
return newOption;
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let items = [];
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
title: 'Steps',
|
||||||
|
isOpen: true,
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
{properties
|
||||||
|
.filter((property) => !optionsProperties.includes(property))
|
||||||
|
?.map((property) => {
|
||||||
|
if (property === 'steps') {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{renderElement(
|
||||||
|
component,
|
||||||
|
componentMeta,
|
||||||
|
paramUpdated,
|
||||||
|
dataQueries,
|
||||||
|
'advanced',
|
||||||
|
'properties',
|
||||||
|
currentState,
|
||||||
|
allComponents
|
||||||
|
)}
|
||||||
|
{isDynamicStepsEnabled
|
||||||
|
? renderElement(
|
||||||
|
component,
|
||||||
|
componentMeta,
|
||||||
|
paramUpdated,
|
||||||
|
dataQueries,
|
||||||
|
'schema',
|
||||||
|
'properties',
|
||||||
|
currentState,
|
||||||
|
allComponents
|
||||||
|
)
|
||||||
|
: _renderOptions()}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// else if (property === 'variant') {
|
||||||
|
// return renderTest(
|
||||||
|
// component,
|
||||||
|
// componentMeta,
|
||||||
|
// paramUpdated,
|
||||||
|
// dataQueries,
|
||||||
|
// 'variant',
|
||||||
|
// 'properties',
|
||||||
|
// currentState,
|
||||||
|
// allComponents,
|
||||||
|
// handleLabelChange
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
return renderElement(
|
||||||
|
component,
|
||||||
|
componentMeta,
|
||||||
|
paramUpdated,
|
||||||
|
dataQueries,
|
||||||
|
property,
|
||||||
|
'properties',
|
||||||
|
currentState,
|
||||||
|
allComponents,
|
||||||
|
darkMode
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
title: 'Events',
|
||||||
|
isOpen: true,
|
||||||
|
children: (
|
||||||
|
<EventManager
|
||||||
|
sourceId={component?.id}
|
||||||
|
eventSourceType="component"
|
||||||
|
eventMetaDefinition={componentMeta}
|
||||||
|
dataQueries={dataQueries}
|
||||||
|
components={allComponents}
|
||||||
|
eventsChanged={eventsChanged}
|
||||||
|
apps={apps}
|
||||||
|
darkMode={darkMode}
|
||||||
|
pages={pages}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
items.push({
|
||||||
|
title: `Additional Actions`,
|
||||||
|
isOpen: true,
|
||||||
|
children: additionalActions.map((property) => {
|
||||||
|
return renderElement(
|
||||||
|
component,
|
||||||
|
componentMeta,
|
||||||
|
paramUpdated,
|
||||||
|
dataQueries,
|
||||||
|
property,
|
||||||
|
'properties',
|
||||||
|
currentState,
|
||||||
|
allComponents,
|
||||||
|
darkMode,
|
||||||
|
componentMeta.properties?.[property]?.placeholder
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
title: 'Devices',
|
||||||
|
isOpen: true,
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
{renderElement(
|
||||||
|
component,
|
||||||
|
componentMeta,
|
||||||
|
layoutPropertyChanged,
|
||||||
|
dataQueries,
|
||||||
|
'showOnDesktop',
|
||||||
|
'others',
|
||||||
|
currentState,
|
||||||
|
allComponents
|
||||||
|
)}
|
||||||
|
{renderElement(
|
||||||
|
component,
|
||||||
|
componentMeta,
|
||||||
|
layoutPropertyChanged,
|
||||||
|
dataQueries,
|
||||||
|
'showOnMobile',
|
||||||
|
'others',
|
||||||
|
currentState,
|
||||||
|
allComponents
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
return <Accordion items={items} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTest(...props) {
|
||||||
|
const [
|
||||||
|
component,
|
||||||
|
componentMeta,
|
||||||
|
paramUpdated,
|
||||||
|
dataQueries,
|
||||||
|
param,
|
||||||
|
paramType,
|
||||||
|
currentState,
|
||||||
|
components = {},
|
||||||
|
darkMode = false,
|
||||||
|
placeholder = '',
|
||||||
|
validationFn,
|
||||||
|
] = props;
|
||||||
|
const value = componentMeta?.definition?.properties?.variant?.value;
|
||||||
|
return (
|
||||||
|
<div style={{ marginBottom: 8 }}>
|
||||||
|
<Switch
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => {
|
||||||
|
paramUpdated({ name: 'variant' }, 'value', e, 'properties', false, props);
|
||||||
|
}}
|
||||||
|
meta={{
|
||||||
|
...componentMeta.properties[param],
|
||||||
|
fullWidth: true,
|
||||||
|
}}
|
||||||
|
paramName={param}
|
||||||
|
isIcon={false}
|
||||||
|
component={component.component.definition.name}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -255,7 +255,7 @@ export const PropertiesTabElements = ({
|
||||||
paramType="properties"
|
paramType="properties"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{resolveReferences(column?.isEditable) && (
|
{(column?.fxActiveFields?.includes('isEditable') || resolveReferences(column?.isEditable)) && (
|
||||||
<ValidationProperties
|
<ValidationProperties
|
||||||
column={column}
|
column={column}
|
||||||
index={index}
|
index={index}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useEffect, useContext } from 'react';
|
import React, { useState, useEffect, useContext, useRef } from 'react';
|
||||||
|
|
||||||
import { ActionTypes } from '@/Editor/ActionTypes';
|
import { ActionTypes } from '@/Editor/ActionTypes';
|
||||||
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
|
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
|
||||||
|
|
@ -32,6 +32,9 @@ import useStore from '@/AppBuilder/_stores/store';
|
||||||
import { useEventActions, useEvents } from '@/AppBuilder/_stores/slices/eventsSlice';
|
import { useEventActions, useEvents } from '@/AppBuilder/_stores/slices/eventsSlice';
|
||||||
import ToggleGroup from '@/ToolJetUI/SwitchGroup/ToggleGroup';
|
import ToggleGroup from '@/ToolJetUI/SwitchGroup/ToggleGroup';
|
||||||
import ToggleGroupItem from '@/ToolJetUI/SwitchGroup/ToggleGroupItem';
|
import ToggleGroupItem from '@/ToolJetUI/SwitchGroup/ToggleGroupItem';
|
||||||
|
import usePopoverObserver from '@/AppBuilder/_hooks/usePopoverObserver';
|
||||||
|
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
||||||
|
import { components as selectComponents } from 'react-select';
|
||||||
|
|
||||||
export const EventManager = ({
|
export const EventManager = ({
|
||||||
sourceId,
|
sourceId,
|
||||||
|
|
@ -82,6 +85,8 @@ export const EventManager = ({
|
||||||
|
|
||||||
const [events, setEvents] = useState([]);
|
const [events, setEvents] = useState([]);
|
||||||
const [focusedEventIndex, setFocusedEventIndex] = useState(null);
|
const [focusedEventIndex, setFocusedEventIndex] = useState(null);
|
||||||
|
const lastFocusedEventIndex = useRef(null);
|
||||||
|
const shouldSkipOnToggle = useRef(null);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
|
@ -101,8 +106,23 @@ export const EventManager = ({
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [JSON.stringify(currentEvents)]);
|
}, [JSON.stringify(currentEvents)]);
|
||||||
|
|
||||||
let actionOptions = ActionTypes.map((action) => {
|
let groupedOptions = ActionTypes.reduce((acc, action) => {
|
||||||
return { name: action.name, value: action.id };
|
const groupName = action.group;
|
||||||
|
|
||||||
|
if (!acc[groupName]) {
|
||||||
|
acc[groupName] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
acc[groupName].push({
|
||||||
|
label: action.name,
|
||||||
|
value: action.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
let actionOptions = Object.keys(groupedOptions).map((groupName) => {
|
||||||
|
return { label: groupName, options: groupedOptions[groupName] };
|
||||||
});
|
});
|
||||||
|
|
||||||
let checkIfClicksAreInsideOf = document.querySelector('.cm-completionListIncompleteBottom');
|
let checkIfClicksAreInsideOf = document.querySelector('.cm-completionListIncompleteBottom');
|
||||||
|
|
@ -124,6 +144,46 @@ export const EventManager = ({
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const actionStyles = {
|
||||||
|
...styles,
|
||||||
|
menuList: (base) => ({
|
||||||
|
...base,
|
||||||
|
padding: '8px 0 8px 8px',
|
||||||
|
'&::-webkit-scrollbar': {
|
||||||
|
width: '10px',
|
||||||
|
},
|
||||||
|
'&::-webkit-scrollbar-track': {
|
||||||
|
background: 'transparent',
|
||||||
|
},
|
||||||
|
'&::-webkit-scrollbar-thumb': {
|
||||||
|
background: '#E4E7EB',
|
||||||
|
border: '1px solid transparent',
|
||||||
|
backgroundClip: 'content-box',
|
||||||
|
},
|
||||||
|
'&::-webkit-scrollbar-thumb:hover': {
|
||||||
|
background: '#E4E7EB !important',
|
||||||
|
border: '1px solid transparent !important',
|
||||||
|
backgroundClip: 'content-box !important',
|
||||||
|
},
|
||||||
|
'&:hover': {
|
||||||
|
'&::-webkit-scrollbar-thumb': {
|
||||||
|
background: '#E4E7EB !important',
|
||||||
|
border: '1px solid transparent !important',
|
||||||
|
backgroundClip: 'content-box !important',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
group: (base) => ({
|
||||||
|
...base,
|
||||||
|
padding: 0,
|
||||||
|
}),
|
||||||
|
groupHeading: (base) => ({
|
||||||
|
...base,
|
||||||
|
margin: 0,
|
||||||
|
padding: '0',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
const actionLookup = Object.fromEntries(ActionTypes.map((actionType) => [actionType.id, actionType]));
|
const actionLookup = Object.fromEntries(ActionTypes.map((actionType) => [actionType.id, actionType]));
|
||||||
|
|
||||||
let alertTypes = [
|
let alertTypes = [
|
||||||
|
|
@ -394,6 +454,29 @@ export const EventManager = ({
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const formatGroupLabel = (data) => {
|
||||||
|
if (data.label === 'run-action') return;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="tw-border-x-0 tw-border-t-0 tw-border-b-[0.5px] tw-border-solid tw-my-[4px]"
|
||||||
|
style={{ borderColor: 'var(--border-weak)' }}
|
||||||
|
></div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CustomOption = (props) => {
|
||||||
|
return (
|
||||||
|
<selectComponents.Option {...props}>
|
||||||
|
<div className="d-flex align-items-center">
|
||||||
|
<div style={{ width: '16px', marginRight: '6px' }}>
|
||||||
|
{props.isSelected && <SolidIcon name="tickv3" width="16px" height="16px" />}
|
||||||
|
</div>
|
||||||
|
<span>{props.label}</span>
|
||||||
|
</div>
|
||||||
|
</selectComponents.Option>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
function eventPopover(event, index) {
|
function eventPopover(event, index) {
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popover
|
||||||
|
|
@ -433,13 +516,17 @@ export const EventManager = ({
|
||||||
<Select
|
<Select
|
||||||
className={`${darkMode ? 'select-search-dark' : 'select-search'} w-100`}
|
className={`${darkMode ? 'select-search-dark' : 'select-search'} w-100`}
|
||||||
options={actionOptions}
|
options={actionOptions}
|
||||||
value={event.actionId}
|
value={actionOptions
|
||||||
|
.flatMap((group) => group.options)
|
||||||
|
.find((option) => option.value === event.actionId)}
|
||||||
|
components={{ Option: CustomOption }}
|
||||||
search={false}
|
search={false}
|
||||||
onChange={(value) => handlerChanged(index, 'actionId', value)}
|
onChange={(value) => handlerChanged(index, 'actionId', value)}
|
||||||
placeholder={t('globals.select', 'Select') + '...'}
|
placeholder={t('globals.select', 'Select') + '...'}
|
||||||
styles={styles}
|
styles={actionStyles}
|
||||||
useMenuPortal={false}
|
useMenuPortal={false}
|
||||||
useCustomStyles={true}
|
useCustomStyles={true}
|
||||||
|
formatGroupLabel={formatGroupLabel}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1006,10 +1093,21 @@ export const EventManager = ({
|
||||||
placement={popoverPlacement || 'left'}
|
placement={popoverPlacement || 'left'}
|
||||||
rootClose={true}
|
rootClose={true}
|
||||||
overlay={eventPopover(event.event, index)}
|
overlay={eventPopover(event.event, index)}
|
||||||
onHide={() => setFocusedEventIndex(null)}
|
|
||||||
onToggle={(showing) => {
|
onToggle={(showing) => {
|
||||||
|
// If the toggle action should be skipped (e.g., due to a previous state change), reset the flag and exit early.
|
||||||
|
if (shouldSkipOnToggle.current) {
|
||||||
|
shouldSkipOnToggle.current = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is already a focused event, set the skip flag to prevent unnecessary state updates.
|
||||||
|
if (focusedEventIndex !== null && showing) {
|
||||||
|
shouldSkipOnToggle.current = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (showing) {
|
if (showing) {
|
||||||
setFocusedEventIndex(index);
|
setFocusedEventIndex(index);
|
||||||
|
lastFocusedEventIndex.current = index;
|
||||||
} else {
|
} else {
|
||||||
setFocusedEventIndex(null);
|
setFocusedEventIndex(null);
|
||||||
}
|
}
|
||||||
|
|
@ -1018,6 +1116,7 @@ export const EventManager = ({
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
|
id={`${sourceId}-${index}`}
|
||||||
ref={provided.innerRef}
|
ref={provided.innerRef}
|
||||||
{...provided.draggableProps}
|
{...provided.draggableProps}
|
||||||
{...provided.dragHandleProps}
|
{...provided.dragHandleProps}
|
||||||
|
|
@ -1061,6 +1160,17 @@ export const EventManager = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const shouldUsePopoverObserver = events.length !== 0 && eventSourceType === 'data_query';
|
||||||
|
|
||||||
|
usePopoverObserver(
|
||||||
|
shouldUsePopoverObserver ? document.getElementsByClassName('query-details')[0] : null,
|
||||||
|
document.getElementById(`${sourceId}-${lastFocusedEventIndex.current}`),
|
||||||
|
document.getElementById('popover-basic'),
|
||||||
|
focusedEventIndex !== null,
|
||||||
|
() => (document.getElementById('popover-basic').style.display = 'block'),
|
||||||
|
() => (document.getElementById('popover-basic').style.display = 'none')
|
||||||
|
);
|
||||||
|
|
||||||
if (events.length === 0) {
|
if (events.length === 0) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import Inspect from '@/_ui/Icon/solidIcons/Inspect';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { EMPTY_ARRAY } from '@/_stores/editorStore';
|
import { EMPTY_ARRAY } from '@/_stores/editorStore';
|
||||||
import { Select } from './Components/Select';
|
import { Select } from './Components/Select';
|
||||||
|
import { Steps } from './Components/Steps.jsx';
|
||||||
import { deepClone } from '@/_helpers/utilities/utils.helpers';
|
import { deepClone } from '@/_helpers/utilities/utils.helpers';
|
||||||
import useStore from '@/AppBuilder/_stores/store';
|
import useStore from '@/AppBuilder/_stores/store';
|
||||||
// import { componentTypes } from '@/Editor/WidgetManager/components';
|
// import { componentTypes } from '@/Editor/WidgetManager/components';
|
||||||
|
|
@ -90,6 +91,7 @@ const NEW_REVAMPED_COMPONENTS = [
|
||||||
'VerticalDivider',
|
'VerticalDivider',
|
||||||
'ModalV2',
|
'ModalV2',
|
||||||
'Link',
|
'Link',
|
||||||
|
'Steps',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const Inspector = ({ componentDefinitionChanged, darkMode, pages, selectedComponentId }) => {
|
export const Inspector = ({ componentDefinitionChanged, darkMode, pages, selectedComponentId }) => {
|
||||||
|
|
@ -539,8 +541,8 @@ export const Inspector = ({ componentDefinitionChanged, darkMode, pages, selecte
|
||||||
componentMeta.displayName === 'Toggle Switch (Legacy)'
|
componentMeta.displayName === 'Toggle Switch (Legacy)'
|
||||||
? 'Toggle (Legacy)'
|
? 'Toggle (Legacy)'
|
||||||
: componentMeta.displayName === 'Toggle Switch'
|
: componentMeta.displayName === 'Toggle Switch'
|
||||||
? 'Toggle Switch'
|
? 'Toggle Switch'
|
||||||
: componentMeta.component,
|
: componentMeta.component,
|
||||||
})}
|
})}
|
||||||
</small>
|
</small>
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -740,6 +742,8 @@ const GetAccordion = React.memo(
|
||||||
case 'DatePickerV2':
|
case 'DatePickerV2':
|
||||||
case 'TimePicker':
|
case 'TimePicker':
|
||||||
return <DatetimePickerV2 {...restProps} componentName={componentName} />;
|
return <DatetimePickerV2 {...restProps} componentName={componentName} />;
|
||||||
|
case 'Steps':
|
||||||
|
return <Steps {...restProps} />;
|
||||||
case 'PhoneInput':
|
case 'PhoneInput':
|
||||||
return <PhoneInput {...restProps} />;
|
return <PhoneInput {...restProps} />;
|
||||||
case 'CurrencyInput':
|
case 'CurrencyInput':
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ const NEW_WIDGETS = [
|
||||||
'TimePicker',
|
'TimePicker',
|
||||||
'ModalV2',
|
'ModalV2',
|
||||||
'TextArea',
|
'TextArea',
|
||||||
|
'EmailInput',
|
||||||
|
'PhoneInput',
|
||||||
|
'CurrencyInput',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const WidgetBox = ({ component, darkMode }) => {
|
export const WidgetBox = ({ component, darkMode }) => {
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,7 @@ export const Viewer = ({ id: appId, darkMode, moduleId = 'canvas', switchDarkMod
|
||||||
showViewerNavigation={!isPagesSidebarHidden}
|
showViewerNavigation={!isPagesSidebarHidden}
|
||||||
handleAppEnvironmentChanged={handleAppEnvironmentChanged}
|
handleAppEnvironmentChanged={handleAppEnvironmentChanged}
|
||||||
changeToDarkMode={changeToDarkMode}
|
changeToDarkMode={changeToDarkMode}
|
||||||
|
switchPage={switchPage}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="sub-section">
|
<div className="sub-section">
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ export const containerConfig = {
|
||||||
displayName: 'Container',
|
displayName: 'Container',
|
||||||
description: 'Group components',
|
description: 'Group components',
|
||||||
defaultSize: {
|
defaultSize: {
|
||||||
width: 10,
|
width: 13,
|
||||||
height: 200,
|
height: 480,
|
||||||
},
|
},
|
||||||
component: 'Container',
|
component: 'Container',
|
||||||
others: {
|
others: {
|
||||||
|
|
|
||||||
|
|
@ -4,25 +4,38 @@ export const stepsConfig = {
|
||||||
description: 'Step-by-step navigation aid',
|
description: 'Step-by-step navigation aid',
|
||||||
component: 'Steps',
|
component: 'Steps',
|
||||||
properties: {
|
properties: {
|
||||||
|
variant: {
|
||||||
|
type: 'switch',
|
||||||
|
displayName: 'Variant',
|
||||||
|
validation: { schema: { type: 'string' }, defaultValue: 'titles' },
|
||||||
|
options: [
|
||||||
|
{ displayName: 'Label', value: 'titles' },
|
||||||
|
{ displayName: 'Number', value: 'numbers' },
|
||||||
|
{ displayName: 'Plain', value: 'plain' },
|
||||||
|
],
|
||||||
|
accordian: 'label',
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
type: 'code',
|
||||||
|
displayName: 'Schema',
|
||||||
|
conditionallyRender: {
|
||||||
|
key: 'advanced',
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
accordian: 'Options',
|
||||||
|
},
|
||||||
steps: {
|
steps: {
|
||||||
type: 'code',
|
type: 'code',
|
||||||
displayName: 'Steps',
|
displayName: '',
|
||||||
|
showLabel: false,
|
||||||
validation: {
|
validation: {
|
||||||
schema: {
|
schema: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
element: { type: 'object', object: { id: { type: 'number' } } },
|
element: { type: 'object' },
|
||||||
},
|
},
|
||||||
defaultValue: `[{ name: 'step 1'}, {name: 'step 2'}]`,
|
defaultValue: `[{ name: 'step 1'}, {name: 'step 2'}]`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
currentStep: {
|
|
||||||
type: 'code',
|
|
||||||
displayName: 'Current step',
|
|
||||||
validation: {
|
|
||||||
schema: { type: 'number' },
|
|
||||||
defaultValue: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
stepsSelectable: {
|
stepsSelectable: {
|
||||||
type: 'toggle',
|
type: 'toggle',
|
||||||
displayName: 'Steps selectable',
|
displayName: 'Steps selectable',
|
||||||
|
|
@ -30,7 +43,38 @@ export const stepsConfig = {
|
||||||
schema: { type: 'boolean' },
|
schema: { type: 'boolean' },
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
},
|
},
|
||||||
|
section: 'additionalActions',
|
||||||
},
|
},
|
||||||
|
disabledState: {
|
||||||
|
type: 'toggle',
|
||||||
|
displayName: 'Disable',
|
||||||
|
validation: { schema: { type: 'boolean' } },
|
||||||
|
section: 'additionalActions',
|
||||||
|
},
|
||||||
|
visibility: {
|
||||||
|
type: 'toggle',
|
||||||
|
displayName: 'Visibility',
|
||||||
|
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||||
|
section: 'additionalActions',
|
||||||
|
},
|
||||||
|
advanced: {
|
||||||
|
type: 'toggle',
|
||||||
|
displayName: 'Dynamic options',
|
||||||
|
validation: {
|
||||||
|
schema: { type: 'boolean' },
|
||||||
|
defaultValue: true,
|
||||||
|
},
|
||||||
|
accordian: 'Options',
|
||||||
|
},
|
||||||
|
currentStep: {
|
||||||
|
type: 'code',
|
||||||
|
displayName: 'Current step',
|
||||||
|
validation: {
|
||||||
|
schema: { type: 'number' },
|
||||||
|
defaultValue: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
defaultSize: {
|
defaultSize: {
|
||||||
width: 22,
|
width: 22,
|
||||||
|
|
@ -40,46 +84,126 @@ export const stepsConfig = {
|
||||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||||
},
|
},
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
handle: 'setStep',
|
||||||
|
displayName: 'Set step',
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
handle: 'option',
|
||||||
|
displayName: 'Option',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
handle: 'setVisibility',
|
||||||
|
displayName: 'Set visibility',
|
||||||
|
params: [{ handle: 'visible', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
handle: 'setDisabled',
|
||||||
|
displayName: 'Set disabled',
|
||||||
|
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{true}}', type: 'toggle' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
handle: 'resetSteps',
|
||||||
|
displayName: 'Reset steps',
|
||||||
|
params: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
handle: 'setStepVisible',
|
||||||
|
displayName: 'Set step visible',
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
handle: 'id',
|
||||||
|
displayName: 'Step id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
handle: 'visibility',
|
||||||
|
displayName: 'visibility',
|
||||||
|
defaultValue: '{{false}}',
|
||||||
|
type: 'toggle',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
handle: 'setStepDisable',
|
||||||
|
displayName: 'Set step disable',
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
handle: 'id',
|
||||||
|
displayName: 'Step id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
handle: 'disabled',
|
||||||
|
displayName: 'disabled',
|
||||||
|
defaultValue: '{{true}}',
|
||||||
|
type: 'toggle',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
events: {
|
events: {
|
||||||
onSelect: { displayName: 'On select' },
|
onSelect: { displayName: 'On select' },
|
||||||
},
|
},
|
||||||
styles: {
|
styles: {
|
||||||
color: {
|
incompletedAccent: {
|
||||||
type: 'colorSwatches',
|
type: 'colorSwatches',
|
||||||
displayName: 'colorSwatches',
|
displayName: 'Incompleted accent',
|
||||||
|
validation: {
|
||||||
|
schema: { type: 'string' },
|
||||||
|
defaultValue: '#CCD1D5',
|
||||||
|
},
|
||||||
|
accordian: 'steps',
|
||||||
|
},
|
||||||
|
incompletedLabel: {
|
||||||
|
type: 'colorSwatches',
|
||||||
|
displayName: 'Incompleted label',
|
||||||
|
validation: {
|
||||||
|
schema: { type: 'string' },
|
||||||
|
defaultValue: '#1B1F24',
|
||||||
|
},
|
||||||
|
accordian: 'steps',
|
||||||
|
},
|
||||||
|
completedAccent: {
|
||||||
|
type: 'colorSwatches',
|
||||||
|
displayName: 'Completed accent',
|
||||||
validation: {
|
validation: {
|
||||||
schema: { type: 'string' },
|
schema: { type: 'string' },
|
||||||
defaultValue: 'var(--primary-brand)',
|
defaultValue: 'var(--primary-brand)',
|
||||||
},
|
},
|
||||||
|
accordian: 'steps',
|
||||||
},
|
},
|
||||||
textColor: {
|
completedLabel: {
|
||||||
type: 'colorSwatches',
|
type: 'colorSwatches',
|
||||||
displayName: 'Text color',
|
displayName: 'Completed label',
|
||||||
validation: {
|
validation: {
|
||||||
schema: { type: 'string' },
|
schema: { type: 'string' },
|
||||||
defaultValue: '#000000',
|
defaultValue: '#1B1F24',
|
||||||
},
|
},
|
||||||
|
accordian: 'steps',
|
||||||
},
|
},
|
||||||
theme: {
|
currentStepLabel: {
|
||||||
type: 'select',
|
type: 'colorSwatches',
|
||||||
displayName: 'Theme',
|
displayName: 'Current step label',
|
||||||
|
validation: {
|
||||||
|
schema: { type: 'string' },
|
||||||
|
defaultValue: '#1B1F24',
|
||||||
|
},
|
||||||
|
accordian: 'steps',
|
||||||
|
},
|
||||||
|
padding: {
|
||||||
|
type: 'switch',
|
||||||
|
displayName: 'Padding',
|
||||||
|
validation: {
|
||||||
|
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||||
|
defaultValue: 'default',
|
||||||
|
},
|
||||||
options: [
|
options: [
|
||||||
{ name: 'titles', value: 'titles' },
|
{ displayName: 'Default', value: 'default' },
|
||||||
{ name: 'numbers', value: 'numbers' },
|
{ displayName: 'None', value: 'none' },
|
||||||
{ name: 'plain', value: 'plain' },
|
|
||||||
],
|
],
|
||||||
validation: {
|
accordian: 'container',
|
||||||
schema: { type: 'string' },
|
|
||||||
defaultValue: 'titles',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
visibility: {
|
|
||||||
type: 'toggle',
|
|
||||||
displayName: 'Visibility',
|
|
||||||
validation: {
|
|
||||||
schema: { type: 'boolean' },
|
|
||||||
defaultValue: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
exposedVariables: {
|
exposedVariables: {
|
||||||
|
|
@ -92,17 +216,35 @@ export const stepsConfig = {
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
steps: {
|
steps: {
|
||||||
value: `{{ [{ name: 'step 1', tooltip: 'some tooltip', id: 1},{ name: 'step 2', tooltip: 'some tooltip', id: 2},{ name: 'step 3', tooltip: 'some tooltip', id: 3},{ name: 'step 4', tooltip: 'some tooltip', id: 4},{ name: 'step 5', tooltip: 'some tooltip', id: 5}]}}`,
|
value: [
|
||||||
|
{ name: 'step 1', tooltip: '', id: 1, visible: { value: true }, disabled: { value: false } },
|
||||||
|
{ name: 'step 2', tooltip: '', id: 2, visible: { value: true }, disabled: { value: false } },
|
||||||
|
{ name: 'step 3', tooltip: '', id: 3, visible: { value: true }, disabled: { value: false } },
|
||||||
|
{ name: 'step 4', tooltip: '', id: 4, visible: { value: true }, disabled: { value: false } },
|
||||||
|
{ name: 'step 5', tooltip: '', id: 5, visible: { value: true }, disabled: { value: false } },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
schema: {
|
||||||
|
value: `{{ [{ name: 'step 1', tooltip: '', id: 1,visible: true, disabled: false},{ name: 'step 2', tooltip: '', id: 2,visible: true, disabled: false},{ name: 'step 3', tooltip: '', id: 3,visible: true, disabled: false},{ name: 'step 4', tooltip: '', id: 4,visible: true, disabled: false},{ name: 'step 5', tooltip: '', id: 5,visible: true, disabled: false}]}}`,
|
||||||
|
},
|
||||||
|
disabledState: { value: '{{false}}' },
|
||||||
|
variant: { value: 'titles' },
|
||||||
currentStep: { value: '{{3}}' },
|
currentStep: { value: '{{3}}' },
|
||||||
stepsSelectable: { value: true },
|
stepsSelectable: { value: true },
|
||||||
|
advanced: { value: `{{false}}` },
|
||||||
|
visibility: { value: '{{true}}' },
|
||||||
},
|
},
|
||||||
events: [],
|
events: [],
|
||||||
styles: {
|
styles: {
|
||||||
visibility: { value: '{{true}}' },
|
visibility: { value: '{{true}}' },
|
||||||
theme: { value: 'titles' },
|
// color: { value: '' },
|
||||||
color: { value: 'var(--primary-brand)' },
|
// textColor: { value: '' },
|
||||||
textColor: { value: '' },
|
padding: { value: 'default' },
|
||||||
|
incompletedAccent: { value: '#E4E7EB' },
|
||||||
|
incompletedLabel: { value: '#1B1F24' },
|
||||||
|
completedAccent: { value: 'var(--primary-brand)' },
|
||||||
|
completedLabel: { value: '#1B1F24' },
|
||||||
|
currentStepLabel: { value: '#1B1F24' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -216,248 +216,237 @@ const useAppData = (appId, moduleId, darkMode, mode = 'edit', { environmentId, v
|
||||||
}
|
}
|
||||||
|
|
||||||
// const appDataPromise = appService.fetchApp(appId);
|
// const appDataPromise = appService.fetchApp(appId);
|
||||||
appDataPromise
|
appDataPromise.then(async (result) => {
|
||||||
.then(async (result) => {
|
let appData = { ...result };
|
||||||
let appData = { ...result };
|
let editorEnvironment = result.editorEnvironment;
|
||||||
let editorEnvironment = result.editorEnvironment;
|
if (isPreviewForVersion) {
|
||||||
if (isPreviewForVersion) {
|
const rawDataQueries = appData?.data_queries;
|
||||||
const rawDataQueries = appData?.data_queries;
|
const rawEditingVersionDataQueries = appData?.editing_version?.data_queries;
|
||||||
const rawEditingVersionDataQueries = appData?.editing_version?.data_queries;
|
appData = convertAllKeysToSnakeCase(appData);
|
||||||
appData = convertAllKeysToSnakeCase(appData);
|
|
||||||
|
|
||||||
appData.data_queries = rawDataQueries;
|
appData.data_queries = rawDataQueries;
|
||||||
if (appData.editing_version && rawEditingVersionDataQueries) {
|
if (appData.editing_version && rawEditingVersionDataQueries) {
|
||||||
appData.editing_version.data_queries = rawEditingVersionDataQueries;
|
appData.editing_version.data_queries = rawEditingVersionDataQueries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editorEnvironment = {
|
||||||
|
id: environmentId,
|
||||||
|
name: queryParams.env,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let constantsResp;
|
||||||
|
if (mode !== 'edit') {
|
||||||
|
try {
|
||||||
|
const queryParams = { slug: slug };
|
||||||
|
const viewerEnvironment = await appEnvironmentService.getEnvironment(environmentId, queryParams);
|
||||||
editorEnvironment = {
|
editorEnvironment = {
|
||||||
id: environmentId,
|
id: viewerEnvironment?.environment?.id,
|
||||||
name: queryParams.env,
|
name: viewerEnvironment?.environment?.name,
|
||||||
};
|
};
|
||||||
|
constantsResp =
|
||||||
|
isPublicAccess && appData.is_public
|
||||||
|
? await orgEnvironmentConstantService.getConstantsFromPublicApp(slug, viewerEnvironment?.environment?.id)
|
||||||
|
: await orgEnvironmentConstantService.getConstantsFromApp(slug, viewerEnvironment?.environment?.id);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching viewer environment:', error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let constantsResp;
|
if (mode === 'edit') {
|
||||||
if (mode !== 'edit') {
|
constantsResp = await orgEnvironmentConstantService.getConstantsFromEnvironment(editorEnvironment?.id);
|
||||||
try {
|
}
|
||||||
const queryParams = { slug: slug };
|
// get the constants for specific environment
|
||||||
const viewerEnvironment = await appEnvironmentService.getEnvironment(environmentId, queryParams);
|
constantsResp.constants = extractEnvironmentConstantsFromConstantsList(
|
||||||
editorEnvironment = {
|
constantsResp?.constants,
|
||||||
id: viewerEnvironment?.environment?.id,
|
editorEnvironment?.name
|
||||||
name: viewerEnvironment?.environment?.name,
|
);
|
||||||
};
|
|
||||||
constantsResp =
|
|
||||||
isPublicAccess && appData.is_public
|
|
||||||
? await orgEnvironmentConstantService.getConstantsFromPublicApp(
|
|
||||||
slug,
|
|
||||||
viewerEnvironment?.environment?.id
|
|
||||||
)
|
|
||||||
: await orgEnvironmentConstantService.getConstantsFromApp(slug, viewerEnvironment?.environment?.id);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching viewer environment:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode === 'edit') {
|
setIsPublicAccess(isPublicAccess && mode !== 'edit' && appData.is_public);
|
||||||
constantsResp = await orgEnvironmentConstantService.getConstantsFromEnvironment(editorEnvironment?.id);
|
|
||||||
}
|
|
||||||
// get the constants for specific environment
|
|
||||||
constantsResp.constants = extractEnvironmentConstantsFromConstantsList(
|
|
||||||
constantsResp?.constants,
|
|
||||||
editorEnvironment?.name
|
|
||||||
);
|
|
||||||
|
|
||||||
setIsPublicAccess(isPublicAccess && mode !== 'edit' && appData.is_public);
|
fetchAndInjectCustomStyles(isPublicAccess && mode !== 'edit' && appData.is_public);
|
||||||
|
|
||||||
fetchAndInjectCustomStyles(isPublicAccess && mode !== 'edit' && appData.is_public);
|
const pages = appData.pages.map((page) => {
|
||||||
|
return page;
|
||||||
const pages = appData.pages.map((page) => {
|
|
||||||
return page;
|
|
||||||
});
|
|
||||||
const conversation = appData.ai_conversation;
|
|
||||||
const docsConversation = appData.ai_conversation_learn;
|
|
||||||
if (setConversation && setDocsConversation) {
|
|
||||||
setConversation(conversation);
|
|
||||||
setDocsConversation(docsConversation);
|
|
||||||
// important to control ai inputs
|
|
||||||
getCreditBalance();
|
|
||||||
}
|
|
||||||
|
|
||||||
let showWalkthrough = true;
|
|
||||||
// if app was created from propmt, and no earlier messages are present in the conversation, send the prompt message
|
|
||||||
|
|
||||||
// handles the getappdataby slug api call. Gets the homePageId from the appData.
|
|
||||||
const homePageId =
|
|
||||||
appData.editing_version?.homePageId || appData.editing_version?.home_page_id || appData.home_page_id;
|
|
||||||
|
|
||||||
setApp({
|
|
||||||
appName: appData.name,
|
|
||||||
appId: appData.id,
|
|
||||||
slug: appData.slug,
|
|
||||||
currentAppEnvironmentId: editorEnvironment.id,
|
|
||||||
isMaintenanceOn:
|
|
||||||
'is_maintenance_on' in result
|
|
||||||
? result.is_maintenance_on
|
|
||||||
: 'isMaintenanceOn' in result
|
|
||||||
? result.isMaintenanceOn
|
|
||||||
: false,
|
|
||||||
organizationId: appData.organizationId || appData.organization_id,
|
|
||||||
homePageId: homePageId,
|
|
||||||
isPublic: appData.is_public,
|
|
||||||
creationMode: appData.creation_mode,
|
|
||||||
});
|
|
||||||
setIsEditorFreezed(appData.should_freeze_editor);
|
|
||||||
const global_settings = mapKeys(
|
|
||||||
appData.editing_version?.global_settings || appData.global_settings,
|
|
||||||
(value, key) => camelCase(key)
|
|
||||||
);
|
|
||||||
if (!global_settings?.theme) {
|
|
||||||
global_settings.theme = baseTheme;
|
|
||||||
}
|
|
||||||
setGlobalSettings(global_settings);
|
|
||||||
setPages(pages, moduleId);
|
|
||||||
setPageSettings(
|
|
||||||
computePageSettings(deepCamelCase(appData?.editing_version?.page_settings ?? appData?.page_settings))
|
|
||||||
);
|
|
||||||
|
|
||||||
// set starting page as homepage initially
|
|
||||||
let startingPage = appData.pages.find((page) => page.id === homePageId);
|
|
||||||
|
|
||||||
//no access to homepage, set to the next available page
|
|
||||||
if (startingPage?.restricted) {
|
|
||||||
startingPage = appData.pages.find((page) => !page?.restricted);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initialLoadRef.current) {
|
|
||||||
// if initial load, check if the path has a page handle and set that as the starting page
|
|
||||||
const initialLoadPath = location.pathname.split('/').pop();
|
|
||||||
|
|
||||||
const page = appData.pages.find((page) => page.handle === initialLoadPath && !page.isPageGroup);
|
|
||||||
if (page) {
|
|
||||||
// if page is disabled, and not editing redirect to home page
|
|
||||||
const shouldRedirect = page?.restricted || (mode !== 'edit' && page?.disabled);
|
|
||||||
|
|
||||||
if (shouldRedirect) {
|
|
||||||
const newUrl = window.location.href.replace(initialLoadPath, startingPage.handle);
|
|
||||||
window.history.replaceState(null, null, newUrl);
|
|
||||||
|
|
||||||
if (page?.restricted) {
|
|
||||||
toast.error('Access to this page is restricted. Contact admin to know more.', {
|
|
||||||
className: 'text-nowrap w-auto mw-100',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
startingPage = page;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// navigate(`/${getWorkspaceId()}/apps/${slug ?? appId}/${startingPage.handle}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add page id and handle to the state on initial load
|
|
||||||
const currentState = window.history.state || {};
|
|
||||||
const pageInfo = {
|
|
||||||
id: startingPage.id,
|
|
||||||
handle: startingPage.handle,
|
|
||||||
};
|
|
||||||
const newState = { ...currentState, ...pageInfo };
|
|
||||||
window.history.replaceState(newState, '', window.location.href);
|
|
||||||
|
|
||||||
setCurrentPageHandle(startingPage.handle);
|
|
||||||
updateFeatureAccess();
|
|
||||||
setCurrentPageId(startingPage.id, moduleId);
|
|
||||||
setResolvedPageConstants({
|
|
||||||
id: startingPage?.id,
|
|
||||||
handle: startingPage?.handle,
|
|
||||||
name: startingPage?.name,
|
|
||||||
});
|
|
||||||
setComponentNameIdMapping(moduleId);
|
|
||||||
updateEventsField('events', appData.events);
|
|
||||||
setCurrentVersionId(appData.editing_version?.id || appData.current_version_id);
|
|
||||||
setAppHomePageId(homePageId);
|
|
||||||
|
|
||||||
const queryData =
|
|
||||||
isPublicAccess || (mode !== 'edit' && appData.is_public)
|
|
||||||
? appData
|
|
||||||
: await dataqueryService.getAll(appData.editing_version?.id || appData.current_version_id);
|
|
||||||
const dataQueries = queryData.data_queries || queryData?.editing_version?.data_queries;
|
|
||||||
dataQueries.forEach((query) => normalizeQueryTransformationOptions(query));
|
|
||||||
setQueries(dataQueries);
|
|
||||||
if (dataQueries?.length > 0) {
|
|
||||||
setSelectedQuery(dataQueries[0]?.id);
|
|
||||||
initialiseResolvedQuery(dataQueries.map((query) => query.id));
|
|
||||||
}
|
|
||||||
const constants = constantsResp?.constants;
|
|
||||||
|
|
||||||
if (constants) {
|
|
||||||
const orgConstants = {};
|
|
||||||
const orgSecrets = {};
|
|
||||||
constants.map((constant) => {
|
|
||||||
if (constant.type !== 'Secret') {
|
|
||||||
orgConstants[constant.name] = constant.value;
|
|
||||||
} else {
|
|
||||||
orgSecrets[constant.name] = constant.value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setResolvedConstants(orgConstants);
|
|
||||||
setSecrets(orgSecrets);
|
|
||||||
}
|
|
||||||
setQueryMapping(moduleId);
|
|
||||||
|
|
||||||
setResolvedGlobals('environment', editorEnvironment);
|
|
||||||
setResolvedGlobals('mode', { value: mode });
|
|
||||||
setResolvedGlobals('currentUser', {
|
|
||||||
...user,
|
|
||||||
groups: currentSession?.groups,
|
|
||||||
role: currentSession?.role?.name,
|
|
||||||
ssoUserInfo: currentSession?.ssoUserInfo,
|
|
||||||
...(currentSession?.currentUser?.metadata && !isEmpty(currentSession?.currentUser?.metadata)
|
|
||||||
? { metadata: currentSession?.currentUser?.metadata }
|
|
||||||
: {}),
|
|
||||||
});
|
|
||||||
setResolvedGlobals('urlparams', JSON.parse(JSON.stringify(queryString.parse(location?.search))));
|
|
||||||
initDependencyGraph(moduleId);
|
|
||||||
setCurrentMode(mode); // TODO: set mode based on the slug/appDef
|
|
||||||
if (
|
|
||||||
state.ai &&
|
|
||||||
state?.prompt &&
|
|
||||||
initialLoadRef.current &&
|
|
||||||
(conversation?.aiConversationMessages || []).length === 0
|
|
||||||
) {
|
|
||||||
setSelectedSidebarItem('tooljetai');
|
|
||||||
toggleLeftSidebar('true');
|
|
||||||
sendMessage(state.prompt);
|
|
||||||
setConversationZeroState(true);
|
|
||||||
showWalkthrough = false;
|
|
||||||
}
|
|
||||||
// fetchDataSources(appData.editing_version.id, editorEnvironment.id);
|
|
||||||
if (!isPublicAccess) {
|
|
||||||
const envFromQueryParams = mode === 'view' && new URLSearchParams(location?.search)?.get('env');
|
|
||||||
useStore.getState().init(appData.editing_version?.id || appData.current_version_id, envFromQueryParams);
|
|
||||||
fetchGlobalDataSources(
|
|
||||||
appData.organization_id,
|
|
||||||
appData.editing_version?.id || appData.current_version_id,
|
|
||||||
editorEnvironment.id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
useStore.getState().updateEditingVersion(appData.editing_version?.id || appData.current_version_id); //check if this is needed
|
|
||||||
updateReleasedVersionId(appData.current_version_id);
|
|
||||||
|
|
||||||
setEditorLoading(false);
|
|
||||||
initialLoadRef.current = false;
|
|
||||||
// only show if app is not created from prompt
|
|
||||||
if (showWalkthrough) initEditorWalkThrough();
|
|
||||||
checkAndSetTrueBuildSuggestionsFlag();
|
|
||||||
return () => {
|
|
||||||
document.title = retrieveWhiteLabelText();
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
if (isPublicAccess) {
|
|
||||||
if (mode !== 'edit') {
|
|
||||||
handleError('view', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
const conversation = appData.ai_conversation;
|
||||||
|
const docsConversation = appData.ai_conversation_learn;
|
||||||
|
if (setConversation && setDocsConversation) {
|
||||||
|
setConversation(conversation);
|
||||||
|
setDocsConversation(docsConversation);
|
||||||
|
// important to control ai inputs
|
||||||
|
getCreditBalance();
|
||||||
|
}
|
||||||
|
|
||||||
|
let showWalkthrough = true;
|
||||||
|
// if app was created from propmt, and no earlier messages are present in the conversation, send the prompt message
|
||||||
|
|
||||||
|
// handles the getappdataby slug api call. Gets the homePageId from the appData.
|
||||||
|
const homePageId =
|
||||||
|
appData.editing_version?.homePageId || appData.editing_version?.home_page_id || appData.home_page_id;
|
||||||
|
|
||||||
|
setApp({
|
||||||
|
appName: appData.name,
|
||||||
|
appId: appData.id,
|
||||||
|
slug: appData.slug,
|
||||||
|
currentAppEnvironmentId: editorEnvironment.id,
|
||||||
|
isMaintenanceOn:
|
||||||
|
'is_maintenance_on' in result
|
||||||
|
? result.is_maintenance_on
|
||||||
|
: 'isMaintenanceOn' in result
|
||||||
|
? result.isMaintenanceOn
|
||||||
|
: false,
|
||||||
|
organizationId: appData.organizationId || appData.organization_id,
|
||||||
|
homePageId: homePageId,
|
||||||
|
isPublic: appData.is_public,
|
||||||
|
creationMode: appData.creation_mode,
|
||||||
|
});
|
||||||
|
setIsEditorFreezed(appData.should_freeze_editor);
|
||||||
|
const global_settings = mapKeys(
|
||||||
|
appData.editing_version?.global_settings || appData.global_settings,
|
||||||
|
(value, key) => camelCase(key)
|
||||||
|
);
|
||||||
|
if (!global_settings?.theme) {
|
||||||
|
global_settings.theme = baseTheme;
|
||||||
|
}
|
||||||
|
setGlobalSettings(global_settings);
|
||||||
|
setPages(pages, moduleId);
|
||||||
|
setPageSettings(
|
||||||
|
computePageSettings(deepCamelCase(appData?.editing_version?.page_settings ?? appData?.page_settings))
|
||||||
|
);
|
||||||
|
|
||||||
|
// set starting page as homepage initially
|
||||||
|
let startingPage = appData.pages.find((page) => page.id === homePageId);
|
||||||
|
|
||||||
|
//no access to homepage, set to the next available page
|
||||||
|
if (startingPage?.restricted) {
|
||||||
|
startingPage = appData.pages.find((page) => !page?.restricted);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialLoadRef.current) {
|
||||||
|
// if initial load, check if the path has a page handle and set that as the starting page
|
||||||
|
const initialLoadPath = location.pathname.split('/').pop();
|
||||||
|
|
||||||
|
const page = appData.pages.find((page) => page.handle === initialLoadPath && !page.isPageGroup);
|
||||||
|
if (page) {
|
||||||
|
// if page is disabled, and not editing redirect to home page
|
||||||
|
const shouldRedirect = page?.restricted || (mode !== 'edit' && page?.disabled);
|
||||||
|
|
||||||
|
if (shouldRedirect) {
|
||||||
|
const newUrl = window.location.href.replace(initialLoadPath, startingPage.handle);
|
||||||
|
window.history.replaceState(null, null, newUrl);
|
||||||
|
|
||||||
|
if (page?.restricted) {
|
||||||
|
toast.error('Access to this page is restricted. Contact admin to know more.', {
|
||||||
|
className: 'text-nowrap w-auto mw-100',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
startingPage = page;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// navigate(`/${getWorkspaceId()}/apps/${slug ?? appId}/${startingPage.handle}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add page id and handle to the state on initial load
|
||||||
|
const currentState = window.history.state || {};
|
||||||
|
const pageInfo = {
|
||||||
|
id: startingPage.id,
|
||||||
|
handle: startingPage.handle,
|
||||||
|
};
|
||||||
|
const newState = { ...currentState, ...pageInfo };
|
||||||
|
window.history.replaceState(newState, '', window.location.href);
|
||||||
|
|
||||||
|
setCurrentPageHandle(startingPage.handle);
|
||||||
|
updateFeatureAccess();
|
||||||
|
setCurrentPageId(startingPage.id, moduleId);
|
||||||
|
setResolvedPageConstants({
|
||||||
|
id: startingPage?.id,
|
||||||
|
handle: startingPage?.handle,
|
||||||
|
name: startingPage?.name,
|
||||||
|
});
|
||||||
|
setComponentNameIdMapping(moduleId);
|
||||||
|
updateEventsField('events', appData.events);
|
||||||
|
setCurrentVersionId(appData.editing_version?.id || appData.current_version_id);
|
||||||
|
setAppHomePageId(homePageId);
|
||||||
|
|
||||||
|
const queryData =
|
||||||
|
isPublicAccess || (mode !== 'edit' && appData.is_public)
|
||||||
|
? appData
|
||||||
|
: await dataqueryService.getAll(appData.editing_version?.id || appData.current_version_id);
|
||||||
|
const dataQueries = queryData.data_queries || queryData?.editing_version?.data_queries;
|
||||||
|
dataQueries.forEach((query) => normalizeQueryTransformationOptions(query));
|
||||||
|
setQueries(dataQueries);
|
||||||
|
if (dataQueries?.length > 0) {
|
||||||
|
setSelectedQuery(dataQueries[0]?.id);
|
||||||
|
initialiseResolvedQuery(dataQueries.map((query) => query.id));
|
||||||
|
}
|
||||||
|
const constants = constantsResp?.constants;
|
||||||
|
|
||||||
|
if (constants) {
|
||||||
|
const orgConstants = {};
|
||||||
|
const orgSecrets = {};
|
||||||
|
constants.map((constant) => {
|
||||||
|
if (constant.type !== 'Secret') {
|
||||||
|
orgConstants[constant.name] = constant.value;
|
||||||
|
} else {
|
||||||
|
orgSecrets[constant.name] = constant.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setResolvedConstants(orgConstants);
|
||||||
|
setSecrets(orgSecrets);
|
||||||
|
}
|
||||||
|
setQueryMapping(moduleId);
|
||||||
|
|
||||||
|
setResolvedGlobals('environment', editorEnvironment);
|
||||||
|
setResolvedGlobals('mode', { value: mode });
|
||||||
|
setResolvedGlobals('currentUser', {
|
||||||
|
...user,
|
||||||
|
groups: currentSession?.groups,
|
||||||
|
role: currentSession?.role?.name,
|
||||||
|
ssoUserInfo: currentSession?.ssoUserInfo,
|
||||||
|
...(currentSession?.currentUser?.metadata && !isEmpty(currentSession?.currentUser?.metadata)
|
||||||
|
? { metadata: currentSession?.currentUser?.metadata }
|
||||||
|
: {}),
|
||||||
|
});
|
||||||
|
setResolvedGlobals('urlparams', JSON.parse(JSON.stringify(queryString.parse(location?.search))));
|
||||||
|
initDependencyGraph(moduleId);
|
||||||
|
setCurrentMode(mode); // TODO: set mode based on the slug/appDef
|
||||||
|
if (
|
||||||
|
state.ai &&
|
||||||
|
state?.prompt &&
|
||||||
|
initialLoadRef.current &&
|
||||||
|
(conversation?.aiConversationMessages || []).length === 0
|
||||||
|
) {
|
||||||
|
setSelectedSidebarItem('tooljetai');
|
||||||
|
toggleLeftSidebar('true');
|
||||||
|
sendMessage(state.prompt);
|
||||||
|
setConversationZeroState(true);
|
||||||
|
showWalkthrough = false;
|
||||||
|
}
|
||||||
|
// fetchDataSources(appData.editing_version.id, editorEnvironment.id);
|
||||||
|
if (!isPublicAccess) {
|
||||||
|
const envFromQueryParams = mode === 'view' && new URLSearchParams(location?.search)?.get('env');
|
||||||
|
useStore.getState().init(appData.editing_version?.id || appData.current_version_id, envFromQueryParams);
|
||||||
|
fetchGlobalDataSources(
|
||||||
|
appData.organization_id,
|
||||||
|
appData.editing_version?.id || appData.current_version_id,
|
||||||
|
editorEnvironment.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
useStore.getState().updateEditingVersion(appData.editing_version?.id || appData.current_version_id); //check if this is needed
|
||||||
|
updateReleasedVersionId(appData.current_version_id);
|
||||||
|
|
||||||
|
setEditorLoading(false);
|
||||||
|
initialLoadRef.current = false;
|
||||||
|
// only show if app is not created from prompt
|
||||||
|
if (showWalkthrough) initEditorWalkThrough();
|
||||||
|
checkAndSetTrueBuildSuggestionsFlag();
|
||||||
|
return () => {
|
||||||
|
document.title = retrieveWhiteLabelText();
|
||||||
|
};
|
||||||
|
});
|
||||||
}, [setApp, setEditorLoading, currentSession]);
|
}, [setApp, setEditorLoading, currentSession]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue