mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 01:18:23 +00:00
Merge branch 'appbuilder/sprint-12' into feat/steps-v2-alignment-style-improvement
This commit is contained in:
commit
8cd1ca26a4
34 changed files with 636 additions and 618 deletions
68
.github/workflows/cypress-appbuilder.yml
vendored
68
.github/workflows/cypress-appbuilder.yml
vendored
|
|
@ -13,16 +13,18 @@ jobs:
|
|||
Cypress-App-Builder:
|
||||
runs-on: ubuntu-22.04
|
||||
if: |
|
||||
contains(github.event.pull_request.labels.*.name, 'run-ce-app-builder') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'run-ee-app-builder') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'run-cypress')
|
||||
contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ce') ||
|
||||
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-ce')
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
edition: >-
|
||||
${{
|
||||
contains(github.event.pull_request.labels.*.name, 'run-ce-app-builder') && fromJson('["ce"]') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'run-ee-app-builder') && fromJson('["ee"]') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-ce') && fromJson('["ce"]') ||
|
||||
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"]') ||
|
||||
fromJson('[]')
|
||||
}}
|
||||
|
|
@ -158,35 +160,35 @@ jobs:
|
|||
name: screenshots-appbuilder-${{ matrix.edition }}
|
||||
path: cypress-tests/cypress/screenshots
|
||||
|
||||
Cypress-App-builder-Subpath:
|
||||
runs-on: ubuntu-22.04
|
||||
if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-subpath')
|
||||
# Cypress-App-builder-Subpath:
|
||||
# runs-on: ubuntu-22.04
|
||||
# if: contains(github.event.pull_request.labels.*.name, 'run-cypress') ||
|
||||
# contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-subpath')
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
# steps:
|
||||
# - name: Checkout
|
||||
# uses: actions/checkout@v3
|
||||
# with:
|
||||
# ref: ${{ github.event.pull_request.head.ref }}
|
||||
|
||||
- name: Create Cypress environment file
|
||||
id: create-json
|
||||
uses: jsdaniell/create-json@1.1.2
|
||||
with:
|
||||
name: "cypress.env.json"
|
||||
json: ${{ secrets.CYPRESS_SECRETS }}
|
||||
dir: "./cypress-tests"
|
||||
# - name: Create Cypress environment file
|
||||
# id: create-json
|
||||
# uses: jsdaniell/create-json@1.1.2
|
||||
# with:
|
||||
# name: "cypress.env.json"
|
||||
# json: ${{ secrets.CYPRESS_SECRETS }}
|
||||
# dir: "./cypress-tests"
|
||||
|
||||
- name: App Builder subpath
|
||||
uses: cypress-io/github-action@v5
|
||||
with:
|
||||
working-directory: ./cypress-tests
|
||||
config: "baseUrl=http://localhost:80/apps/tooljet/"
|
||||
config-file: cypress-app-builder.config.js
|
||||
# - name: App Builder subpath
|
||||
# uses: cypress-io/github-action@v5
|
||||
# with:
|
||||
# working-directory: ./cypress-tests
|
||||
# config: "baseUrl=http://localhost:80/apps/tooljet/"
|
||||
# config-file: cypress-app-builder.config.js
|
||||
|
||||
- name: Capture Screenshots
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: screenshots
|
||||
path: cypress-tests/cypress/screenshots
|
||||
# - name: Capture Screenshots
|
||||
# uses: actions/upload-artifact@v4
|
||||
# if: always()
|
||||
# with:
|
||||
# name: screenshots
|
||||
# path: cypress-tests/cypress/screenshots
|
||||
|
|
|
|||
10
.github/workflows/cypress-marketplace.yml
vendored
10
.github/workflows/cypress-marketplace.yml
vendored
|
|
@ -15,16 +15,18 @@ jobs:
|
|||
runs-on: ubuntu-22.04
|
||||
|
||||
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-ee-cypress-marketplace')
|
||||
contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ce') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-ee') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce')
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
edition: >-
|
||||
${{
|
||||
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-ee-cypress-marketplace') && fromJson('["ee"]') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce') && fromJson('["ce"]') ||
|
||||
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('[]')
|
||||
}}
|
||||
|
||||
|
|
|
|||
11
.github/workflows/cypress-platform.yml
vendored
11
.github/workflows/cypress-platform.yml
vendored
|
|
@ -13,15 +13,18 @@ jobs:
|
|||
Cypress-Platform:
|
||||
runs-on: ubuntu-22.04
|
||||
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-ee-cypress-platform')
|
||||
contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ce') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'run-cypress-platform-ee') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce')
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
edition: >-
|
||||
${{
|
||||
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-ee-cypress-platform') && fromJson('["ee"]') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'run-cypress-ce') && fromJson('["ce"]') ||
|
||||
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('[]')
|
||||
}}
|
||||
|
||||
|
|
|
|||
116
.github/workflows/render-preview-deploy.yml
vendored
116
.github/workflows/render-preview-deploy.yml
vendored
|
|
@ -170,7 +170,7 @@ jobs:
|
|||
"serviceDetails": {
|
||||
"disk": {
|
||||
"name": "tooljet-ce-pr-${{ env.PR_NUMBER }}-postgresql",
|
||||
"mountPath": "/data",
|
||||
"mountPath": "/var/lib/postgresql/13/main",
|
||||
"sizeGB": 10
|
||||
},
|
||||
"env": "docker",
|
||||
|
|
@ -283,35 +283,35 @@ jobs:
|
|||
console.log(e)
|
||||
}
|
||||
|
||||
- name: Install PostgreSQL client
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install postgresql-client -y
|
||||
# - name: Install PostgreSQL client
|
||||
# run: |
|
||||
# sudo apt update
|
||||
# sudo apt install postgresql-client -y
|
||||
|
||||
- name: Wait after installing PostgreSQL
|
||||
run: sleep 25
|
||||
# - name: Wait after installing PostgreSQL
|
||||
# run: sleep 25
|
||||
|
||||
- name: Drop PostgreSQL PR databases
|
||||
env:
|
||||
PGHOST: ${{ secrets.RENDER_DS_PG_HOST }}
|
||||
PGPORT: 5432
|
||||
PGUSER: ${{ secrets.RENDER_DS_PG_USER }}
|
||||
PGDATABASE: ${{ env.PR_NUMBER }}-ce
|
||||
PGTJBDATABASE: ${{ env.PR_NUMBER }}-ce-tjdb
|
||||
run: |
|
||||
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..."
|
||||
PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGDATABASE\" ;"
|
||||
else
|
||||
echo "Database $PGDATABASE does not exist."
|
||||
fi
|
||||
# - name: Drop PostgreSQL PR databases
|
||||
# env:
|
||||
# PGHOST: ${{ secrets.RENDER_DS_PG_HOST }}
|
||||
# PGPORT: 5432
|
||||
# PGUSER: ${{ secrets.RENDER_DS_PG_USER }}
|
||||
# PGDATABASE: ${{ env.PR_NUMBER }}-ce
|
||||
# PGTJBDATABASE: ${{ env.PR_NUMBER }}-ce-tjdb
|
||||
# run: |
|
||||
# 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..."
|
||||
# PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGDATABASE\" ;"
|
||||
# else
|
||||
# echo "Database $PGDATABASE does not exist."
|
||||
# fi
|
||||
|
||||
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..."
|
||||
PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGTJBDATABASE\" ;"
|
||||
else
|
||||
echo "Database $PGTJBDATABASE does not exist."
|
||||
fi
|
||||
# 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..."
|
||||
# PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGTJBDATABASE\" ;"
|
||||
# else
|
||||
# echo "Database $PGTJBDATABASE does not exist."
|
||||
# fi
|
||||
|
||||
suspend-ce-review-app:
|
||||
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'suspend-ce-review-app' }}
|
||||
|
|
@ -321,7 +321,7 @@ jobs:
|
|||
- name: Suspend service
|
||||
run: |
|
||||
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 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \
|
||||
jq -r '.[0].service.id')
|
||||
|
|
@ -353,7 +353,7 @@ jobs:
|
|||
- name: Resume service
|
||||
run: |
|
||||
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 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \
|
||||
jq -r '.[0].service.id')
|
||||
|
|
@ -542,7 +542,7 @@ jobs:
|
|||
"serviceDetails": {
|
||||
"disk": {
|
||||
"name": "tooljet-ee-pr-${{ env.PR_NUMBER }}-postgresql",
|
||||
"mountPath": "/data",
|
||||
"mountPath": "/var/lib/postgresql/13/main",
|
||||
"sizeGB": 10
|
||||
},
|
||||
"env": "docker",
|
||||
|
|
@ -655,35 +655,35 @@ jobs:
|
|||
console.log(e)
|
||||
}
|
||||
|
||||
- name: Install PostgreSQL client
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install postgresql-client -y
|
||||
# - name: Install PostgreSQL client
|
||||
# run: |
|
||||
# sudo apt update
|
||||
# sudo apt install postgresql-client -y
|
||||
|
||||
- name: Wait after installing PostgreSQL
|
||||
run: sleep 25
|
||||
# - name: Wait after installing PostgreSQL
|
||||
# run: sleep 25
|
||||
|
||||
- name: Drop PostgreSQL PR databases
|
||||
env:
|
||||
PGHOST: ${{ secrets.RENDER_DS_PG_HOST }}
|
||||
PGPORT: 5432
|
||||
PGUSER: ${{ secrets.RENDER_DS_PG_USER }}
|
||||
PGDATABASE: ${{ env.PR_NUMBER }}-ee
|
||||
PGTJBDATABASE: ${{ env.PR_NUMBER }}-ee-tjdb
|
||||
run: |
|
||||
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..."
|
||||
PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGDATABASE\" ;"
|
||||
else
|
||||
echo "Database $PGDATABASE does not exist."
|
||||
fi
|
||||
# - name: Drop PostgreSQL PR databases
|
||||
# env:
|
||||
# PGHOST: ${{ secrets.RENDER_DS_PG_HOST }}
|
||||
# PGPORT: 5432
|
||||
# PGUSER: ${{ secrets.RENDER_DS_PG_USER }}
|
||||
# PGDATABASE: ${{ env.PR_NUMBER }}-ee
|
||||
# PGTJBDATABASE: ${{ env.PR_NUMBER }}-ee-tjdb
|
||||
# run: |
|
||||
# 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..."
|
||||
# PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGDATABASE\" ;"
|
||||
# else
|
||||
# echo "Database $PGDATABASE does not exist."
|
||||
# fi
|
||||
|
||||
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..."
|
||||
PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGTJBDATABASE\" ;"
|
||||
else
|
||||
echo "Database $PGTJBDATABASE does not exist."
|
||||
fi
|
||||
# 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..."
|
||||
# PGPASSWORD=${{ secrets.RENDER_DS_PG_PASS }} psql -h $PGHOST -p $PGPORT -U $PGUSER -d postgres -c "drop database \"$PGTJBDATABASE\" ;"
|
||||
# else
|
||||
# echo "Database $PGTJBDATABASE does not exist."
|
||||
# fi
|
||||
|
||||
suspend-ee-review-app:
|
||||
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'suspend-ee-review-app' }}
|
||||
|
|
@ -693,7 +693,7 @@ jobs:
|
|||
- name: Suspend service
|
||||
run: |
|
||||
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 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \
|
||||
jq -r '.[0].service.id')
|
||||
|
|
@ -725,7 +725,7 @@ jobs:
|
|||
- name: Resume service
|
||||
run: |
|
||||
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 'authorization: Bearer ${{ secrets.RENDER_API_KEY }}' | \
|
||||
jq -r '.[0].service.id')
|
||||
|
|
|
|||
|
|
@ -39,11 +39,11 @@ module.exports = defineConfig({
|
|||
chromeWebSecurity: false,
|
||||
trashAssetsBeforeRuns: true,
|
||||
e2e: {
|
||||
setupNodeEvents(on, config) {
|
||||
setupNodeEvents (on, config) {
|
||||
config.baseUrl = environment.baseUrl;
|
||||
|
||||
on("task", {
|
||||
readPdf(pathToPdf) {
|
||||
readPdf (pathToPdf) {
|
||||
return new Promise((resolve) => {
|
||||
const pdfPath = path.resolve(pathToPdf);
|
||||
let dataBuffer = fs.readFileSync(pdfPath);
|
||||
|
|
@ -55,7 +55,7 @@ module.exports = defineConfig({
|
|||
});
|
||||
|
||||
on("task", {
|
||||
readXlsx(filePath) {
|
||||
readXlsx (filePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
let dataBuffer = fs.readFileSync(filePath);
|
||||
|
|
@ -69,7 +69,7 @@ module.exports = defineConfig({
|
|||
});
|
||||
|
||||
on("task", {
|
||||
deleteFolder(folderName) {
|
||||
deleteFolder (folderName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
rmdir(folderName, { maxRetries: 10, recursive: true }, (err) => {
|
||||
if (err) {
|
||||
|
|
@ -83,7 +83,7 @@ module.exports = defineConfig({
|
|||
});
|
||||
|
||||
on("task", {
|
||||
dbConnection({ dbconfig, sql }) {
|
||||
dbConnection ({ dbconfig, sql }) {
|
||||
const client = new pg.Pool(dbconfig);
|
||||
return client.query(sql);
|
||||
},
|
||||
|
|
@ -97,9 +97,9 @@ module.exports = defineConfig({
|
|||
baseUrl: environment.baseUrl,
|
||||
configFile: environment.configFile,
|
||||
specPattern: [
|
||||
"cypress/e2e/happyPath/platform/ceTestcases/userFlow/firstUserOnboarding.cy.js",
|
||||
"cypress/e2e/happyPath/platform/commonTestcases/workspace/dashboard.cy.js",
|
||||
"cypress/e2e/happyPath/platform/ceTestcases/!(userFlow)/**/*.cy.js",
|
||||
"cypress/e2e/happyPath/platform/firstUser/firstUserOnboarding.cy.js",
|
||||
"cypress/e2e/happyPath/platform/ceTestcases/apps/appSlug.cy.js",
|
||||
"cypress/e2e/happyPath/platform/ceTestcases/**/!(*appSlug).cy.js",
|
||||
"cypress/e2e/happyPath/platform/commonTestcases/**/*.cy.js",
|
||||
],
|
||||
numTestsKeptInMemory: 1,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { passwordInputText } from "Texts/passwordInput";
|
|||
import { importSelectors } from "Selectors/exportImport";
|
||||
import { importText } from "Texts/exportImport";
|
||||
import { onboardingSelectors } from "Selectors/onboarding";
|
||||
import { selectAppCardOption } from "Support/utils/common";
|
||||
|
||||
const API_ENDPOINT =
|
||||
Cypress.env("environment") === "Community"
|
||||
|
|
@ -160,12 +161,10 @@ Cypress.Commands.add(
|
|||
|
||||
Cypress.Commands.add("deleteApp", (appName) => {
|
||||
cy.intercept("DELETE", "/api/apps/*").as("appDeleted");
|
||||
cy.get(commonSelectors.appCard(appName))
|
||||
.realHover()
|
||||
.find(commonSelectors.appCardOptionsButton)
|
||||
.realHover()
|
||||
.click();
|
||||
cy.get(commonSelectors.deleteAppOption).click();
|
||||
selectAppCardOption(
|
||||
appName,
|
||||
commonSelectors.appCardOptions(commonText.deleteAppOption)
|
||||
);
|
||||
cy.get(commonSelectors.buttonSelector(commonText.modalYesButton)).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
|
|
@ -227,9 +226,9 @@ Cypress.Commands.add(
|
|||
.invoke("text")
|
||||
.then((text) => {
|
||||
cy.wrap(subject).realType(createBackspaceText(text)),
|
||||
{
|
||||
delay: 0,
|
||||
};
|
||||
{
|
||||
delay: 0,
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
@ -398,39 +397,38 @@ Cypress.Commands.add("getPosition", (componentName) => {
|
|||
});
|
||||
|
||||
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.visit("/my-workspace");
|
||||
cy.wait(2000);
|
||||
cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
|
||||
// cy.wait("@library_apps");
|
||||
cy.apiLogin(
|
||||
"dev@tooljet.io",
|
||||
"password",
|
||||
workspaceId,
|
||||
"/my-workspace"
|
||||
).then(() => {
|
||||
cy.visit("/");
|
||||
cy.wait(2000);
|
||||
cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
"visitSlug",
|
||||
({
|
||||
actualUrl,
|
||||
errorUrls = [
|
||||
`${Cypress.config("baseUrl")}/error/unknown`,
|
||||
`${Cypress.config("baseUrl")}/error/restricted`,
|
||||
],
|
||||
}) => {
|
||||
if (!actualUrl) {
|
||||
throw new Error("actualUrl is required for visitSlug command.");
|
||||
Cypress.Commands.add("visitSlug", ({ actualUrl }) => {
|
||||
cy.visit(actualUrl);
|
||||
cy.wait(1000);
|
||||
|
||||
cy.url().then((currentUrl) => {
|
||||
if (currentUrl !== actualUrl) {
|
||||
cy.visit(actualUrl);
|
||||
cy.wait(1000);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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", () => {
|
||||
if (Cypress.env("environment") !== "Community") {
|
||||
|
|
@ -551,7 +549,7 @@ Cypress.Commands.add("installMarketplacePlugin", (pluginName) => {
|
|||
}
|
||||
});
|
||||
|
||||
function installPlugin(pluginName) {
|
||||
function installPlugin (pluginName) {
|
||||
cy.get('[data-cy="-list-item"]').eq(1).click();
|
||||
cy.wait(1000);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ export const commonSelectors = {
|
|||
toastMessage: ".go3958317564",
|
||||
oldToastMessage: ".go318386747",
|
||||
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"]',
|
||||
editButton: "[data-cy=edit-button]",
|
||||
workspaceConstantNameInput: '[data-cy="name-input-field"]',
|
||||
|
|
@ -18,7 +19,7 @@ export const commonSelectors = {
|
|||
appCardOptionsButton: "[data-cy=app-card-menu-icon]",
|
||||
autoSave: "[data-cy=autosave-indicator]",
|
||||
nameInputFieldd: "[data-cy=name-input-field]",
|
||||
valueInputFieldd: '[data-cy=value-input-field]',
|
||||
valueInputFieldd: "[data-cy=value-input-field]",
|
||||
skipButton: ".driver-close-btn",
|
||||
skipInstallationModal: "[data-cy=skip-button]",
|
||||
homePageLogo: "[data-cy=home-page-logo]",
|
||||
|
|
@ -395,7 +396,7 @@ export const commonWidgetSelector = {
|
|||
modalCloseButton: '[data-cy="modal-close-button"]',
|
||||
iframeLinkLabel: '[data-cy="iframe-link-label"]',
|
||||
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"]',
|
||||
appSlugInfoLabel: '[data-cy="helper-text"]',
|
||||
appLinkLabel: '[data-cy="app-link-label"]',
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export const restAPISelector = {
|
|||
return `[data-cy="${cyParamName(header)}-delete-button-${cyParamName(index)}"]`;
|
||||
},
|
||||
addMoreButton: (header) => {
|
||||
return `[data-cy="${cyParamName(header)}-add-more-button"]`;
|
||||
return `[data-cy="${cyParamName(header)}-add-button"]`;
|
||||
},
|
||||
dropdownLabel: (label) => {
|
||||
return `[data-cy="${cyParamName(label)}-dropdown-label"]`;
|
||||
|
|
|
|||
|
|
@ -8,11 +8,7 @@ export const editVersionText = {
|
|||
|
||||
export const deleteVersionText = {
|
||||
deleteModalText: (text) => {
|
||||
// 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(
|
||||
return `Are you sure you want to delete this version - ${cyParamName(
|
||||
text
|
||||
)}?`;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -46,9 +46,7 @@ describe("App Export", () => {
|
|||
});
|
||||
|
||||
it("Verify the elements of export dialog box", () => {
|
||||
cy.window({ log: false }).then((win) => {
|
||||
win.localStorage.setItem("walkthroughCompleted", "true");
|
||||
});
|
||||
cy.skipWalkthrough()
|
||||
|
||||
cy.apiLogin();
|
||||
cy.visit(`${data.workspaceSlug}`);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ describe("App Import Functionality", () => {
|
|||
cy.apiLogin();
|
||||
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
|
||||
cy.apiLogout();
|
||||
cy.skipWalkthrough()
|
||||
});
|
||||
|
||||
it("should verify app import functionality", () => {
|
||||
|
|
@ -100,12 +101,13 @@ describe("App Import Functionality", () => {
|
|||
.and("have.text", importText.appImportedToastMessage);
|
||||
|
||||
// Verify imported app
|
||||
cy.get(".driver-close-btn").click();
|
||||
cy.get(commonSelectors.toastCloseButton).click();
|
||||
cy.wait(500);
|
||||
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
|
||||
"contain.value",
|
||||
"three-versions"
|
||||
);
|
||||
cy.get(appVersionSelectors.currentVersionField("v3")).should("be.visible");
|
||||
|
||||
// Configure app
|
||||
cy.skipEditorPopover();
|
||||
|
|
|
|||
|
|
@ -27,17 +27,21 @@ describe("App Slug", () => {
|
|||
});
|
||||
|
||||
it("Verify app slug cases in global settings", () => {
|
||||
cy.apiLogin();
|
||||
const workspaceId = Cypress.env("workspaceId");
|
||||
const appId = Cypress.env("appId");
|
||||
const appUrl = `${host}/${Cypress.env("workspaceId")}/apps/${Cypress.env("appId")}/`;
|
||||
|
||||
cy.visit("/my-workspace");
|
||||
cy.wait(1000);
|
||||
cy.apiLogin();
|
||||
cy.skipWalkthrough();
|
||||
|
||||
cy.window({ log: false }).then((win) => {
|
||||
win.localStorage.setItem("walkthroughCompleted", "true");
|
||||
cy.visit(appUrl);
|
||||
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.get(commonSelectors.leftSideBarSettingsButton).click();
|
||||
|
|
|
|||
|
|
@ -78,11 +78,11 @@ describe("Private and Public apps", {
|
|||
|
||||
// Test private access
|
||||
logout();
|
||||
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
||||
|
||||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
|
||||
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
||||
cy.wait(2000);
|
||||
cy.appUILogin();
|
||||
|
|
@ -116,6 +116,9 @@ describe("Private and Public apps", {
|
|||
|
||||
inviteUserToWorkspace(data.firstName, data.email);
|
||||
logout();
|
||||
cy.visit("/");
|
||||
cy.wait(2000);
|
||||
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
||||
|
||||
// Test private access
|
||||
cy.visitSlug({
|
||||
|
|
@ -141,6 +144,8 @@ describe("Private and Public apps", {
|
|||
cy.wait(1000);
|
||||
cy.apiMakeAppPublic();
|
||||
logout();
|
||||
cy.wait(1000);
|
||||
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
||||
|
||||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
|
|
@ -177,6 +182,9 @@ describe("Private and Public apps", {
|
|||
cy.apiMakeAppPublic();
|
||||
logout();
|
||||
|
||||
cy.wait(1000);
|
||||
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
||||
|
||||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
|
|
@ -229,6 +237,8 @@ describe("Private and Public apps", {
|
|||
|
||||
cy.get('[data-cy="viewer-page-logo"]').click();
|
||||
logout();
|
||||
cy.wait(1000);
|
||||
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
||||
|
||||
// Setup new workspace and app
|
||||
cy.defaultWorkspaceLogin();
|
||||
|
|
@ -123,7 +123,7 @@ describe("App Version", () => {
|
|||
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
|
||||
cy.apiAddComponentToApp(
|
||||
data.appName,
|
||||
|
|
@ -44,6 +44,164 @@ describe("dashboard", () => {
|
|||
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", () => {
|
||||
cy.intercept("GET", "/api/metadata", {
|
||||
body: {
|
||||
|
|
@ -171,181 +329,6 @@ describe("dashboard", () => {
|
|||
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", () => {
|
||||
const customLayout = {
|
||||
desktop: { top: 100, left: 20 },
|
||||
|
|
@ -369,10 +352,7 @@ describe("dashboard", () => {
|
|||
cy.wait("@appLibrary");
|
||||
|
||||
cy.deleteApp(data.appName);
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
commonText.appDeletedToast
|
||||
);
|
||||
|
||||
verifyAppDelete(data.appName);
|
||||
});
|
||||
|
||||
|
|
@ -493,10 +473,7 @@ describe("dashboard", () => {
|
|||
|
||||
cy.get(commonSelectors.allApplicationsLink).click();
|
||||
cy.deleteApp(data.appName);
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
commonText.appDeletedToast
|
||||
);
|
||||
|
||||
verifyAppDelete(data.appName);
|
||||
logout();
|
||||
});
|
||||
|
|
@ -204,10 +204,7 @@ describe("Manage Groups", () => {
|
|||
|
||||
cy.wait(2500);
|
||||
cy.deleteApp(data.appName);
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
commonText.appDeletedToast
|
||||
);
|
||||
|
||||
|
||||
// Folder operations
|
||||
createFolder(data.folderName);
|
||||
|
|
@ -101,11 +101,14 @@ export const navigateToAppEditor = (appName) => {
|
|||
|
||||
export const viewAppCardOptions = (appName) => {
|
||||
cy.wait(1000);
|
||||
cy.reloadAppForTheElement(appName);
|
||||
cy.get(commonSelectors.appCard(appName))
|
||||
.realHover()
|
||||
.find(commonSelectors.appCardOptionsButton)
|
||||
.realHover()
|
||||
cy.contains("div", appName)
|
||||
.parent()
|
||||
.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) => {
|
||||
cy.wait(1000);
|
||||
viewAppCardOptions(appName);
|
||||
cy.get(appCardOption).should("be.visible").click({ force: true });
|
||||
cy.get(appCardOption).should("be.visible").click();
|
||||
};
|
||||
|
||||
export const navigateToDatabase = () => {
|
||||
|
|
|
|||
|
|
@ -239,7 +239,8 @@ export const createRestAPIQuery = (
|
|||
key = "",
|
||||
value = "",
|
||||
url = "",
|
||||
run = true
|
||||
run = true,
|
||||
kind = "restapi"
|
||||
) => {
|
||||
cy.getCookie("tj_auth_token").then((cookie) => {
|
||||
const headers = {
|
||||
|
|
@ -247,7 +248,6 @@ export const createRestAPIQuery = (
|
|||
Cookie: `tj_auth_token=${cookie.value}`,
|
||||
};
|
||||
|
||||
cy.log(Cypress.env("appId"));
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url: `${Cypress.env("server_host")}/api/apps/${Cypress.env("appId")}`,
|
||||
|
|
@ -255,13 +255,13 @@ export const createRestAPIQuery = (
|
|||
}).then((response) => {
|
||||
const editingVersionId = response.body.editing_version.id;
|
||||
|
||||
const data_source_id = Cypress.env(`${dsName}-id`);
|
||||
const data_source_id = Cypress.env(kind);
|
||||
|
||||
const requestBody = {
|
||||
app_id: Cypress.env("appId"),
|
||||
app_version_id: editingVersionId,
|
||||
name: queryName,
|
||||
kind: "restapi",
|
||||
kind: kind,
|
||||
options: {
|
||||
method: "get",
|
||||
url: url,
|
||||
|
|
|
|||
|
|
@ -115,8 +115,8 @@ export const verifyDuplicateVersion = (newVersion = [], version) => {
|
|||
cy.get(appVersionSelectors.createNewVersionButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
// appVersionText.versionNameAlreadyExists
|
||||
"Already exists!"
|
||||
appVersionText.versionNameAlreadyExists
|
||||
// "Already exists!"
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -80,13 +80,21 @@ RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-k
|
|||
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list
|
||||
RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor
|
||||
|
||||
RUN mkdir -p /var/log/supervisor /var/run/postgresql && \
|
||||
chown -R postgres:postgres /var/run/postgresql /var/log/supervisor
|
||||
|
||||
# Explicitly create PG main directory with correct ownership
|
||||
RUN mkdir -p /var/lib/postgresql/13/main && \
|
||||
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" \
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ WORKDIR /app
|
|||
ARG CUSTOM_GITHUB_TOKEN
|
||||
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 http.version HTTP/1.1
|
||||
|
|
@ -109,6 +109,14 @@ RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-k
|
|||
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list
|
||||
RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor --fix-missing
|
||||
|
||||
|
||||
# Explicitly create PG main directory with correct ownership
|
||||
RUN mkdir -p /var/lib/postgresql/13/main && \
|
||||
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 && \
|
||||
|
|
|
|||
|
|
@ -216,248 +216,237 @@ const useAppData = (appId, moduleId, darkMode, mode = 'edit', { environmentId, v
|
|||
}
|
||||
|
||||
// const appDataPromise = appService.fetchApp(appId);
|
||||
appDataPromise
|
||||
.then(async (result) => {
|
||||
let appData = { ...result };
|
||||
let editorEnvironment = result.editorEnvironment;
|
||||
if (isPreviewForVersion) {
|
||||
const rawDataQueries = appData?.data_queries;
|
||||
const rawEditingVersionDataQueries = appData?.editing_version?.data_queries;
|
||||
appData = convertAllKeysToSnakeCase(appData);
|
||||
appDataPromise.then(async (result) => {
|
||||
let appData = { ...result };
|
||||
let editorEnvironment = result.editorEnvironment;
|
||||
if (isPreviewForVersion) {
|
||||
const rawDataQueries = appData?.data_queries;
|
||||
const rawEditingVersionDataQueries = appData?.editing_version?.data_queries;
|
||||
appData = convertAllKeysToSnakeCase(appData);
|
||||
|
||||
appData.data_queries = rawDataQueries;
|
||||
if (appData.editing_version && rawEditingVersionDataQueries) {
|
||||
appData.editing_version.data_queries = rawEditingVersionDataQueries;
|
||||
}
|
||||
appData.data_queries = rawDataQueries;
|
||||
if (appData.editing_version && 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 = {
|
||||
id: environmentId,
|
||||
name: queryParams.env,
|
||||
id: viewerEnvironment?.environment?.id,
|
||||
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') {
|
||||
try {
|
||||
const queryParams = { slug: slug };
|
||||
const viewerEnvironment = await appEnvironmentService.getEnvironment(environmentId, queryParams);
|
||||
editorEnvironment = {
|
||||
id: viewerEnvironment?.environment?.id,
|
||||
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') {
|
||||
constantsResp = await orgEnvironmentConstantService.getConstantsFromEnvironment(editorEnvironment?.id);
|
||||
}
|
||||
// get the constants for specific environment
|
||||
constantsResp.constants = extractEnvironmentConstantsFromConstantsList(
|
||||
constantsResp?.constants,
|
||||
editorEnvironment?.name
|
||||
);
|
||||
|
||||
if (mode === 'edit') {
|
||||
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);
|
||||
|
||||
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 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 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();
|
||||
};
|
||||
});
|
||||
}, [setApp, setEditorLoading, currentSession]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import { Constants } from '@/_helpers/utils';
|
|||
import { OverlayTrigger, Tooltip } from 'react-bootstrap';
|
||||
import Sharepoint from '@/_components/Sharepoint';
|
||||
import AccordionForm from './AccordionForm';
|
||||
import { generateCypressDataCy } from '../modules/common/helpers/cypressHelpers';
|
||||
|
||||
const DynamicForm = ({
|
||||
schema,
|
||||
|
|
@ -534,7 +535,7 @@ const DynamicForm = ({
|
|||
const labelElement = (
|
||||
<label
|
||||
className="form-label"
|
||||
data-cy={`label-${String(label).toLowerCase().replace(/\s+/g, '-')}`}
|
||||
data-cy={`label-${generateCypressDataCy(label)}`}
|
||||
style={{ textDecoration: tooltip ? 'underline 2px dashed' : 'none', textDecorationColor: 'var(--slate8)' }}
|
||||
>
|
||||
{label}
|
||||
|
|
@ -572,7 +573,7 @@ const DynamicForm = ({
|
|||
'd-flex': isHorizontalLayout,
|
||||
'dynamic-form-row': isHorizontalLayout,
|
||||
})}
|
||||
data-cy={`${key.replace(/_/g, '-')}-section`}
|
||||
data-cy={`${generateCypressDataCy(key)}-section`}
|
||||
key={key}
|
||||
>
|
||||
{!isSpecificComponent && (
|
||||
|
|
@ -628,7 +629,7 @@ const DynamicForm = ({
|
|||
<Element
|
||||
{...getElementProps(obj[key])}
|
||||
{...computedProps[propertyKey]}
|
||||
data-cy={`${String(label).toLocaleLowerCase().replace(/\s+/g, '-')}-text-field`}
|
||||
data-cy={`${generateCypressDataCy(label)}-text-field`}
|
||||
dataCy={obj[key].key.replace(/_/g, '-')}
|
||||
//to be removed after whole ui is same
|
||||
isHorizontalLayout={isHorizontalLayout}
|
||||
|
|
@ -663,15 +664,16 @@ const DynamicForm = ({
|
|||
{(flipComponentDropdown.label || isHorizontalLayout) && (
|
||||
<label
|
||||
className={cx('form-label')}
|
||||
data-cy={`${String(flipComponentDropdown.label)
|
||||
.toLocaleLowerCase()
|
||||
.replace(/\s+/g, '-')}-dropdown-label`}
|
||||
data-cy={`${generateCypressDataCy(flipComponentDropdown.label)}-dropdown-label`}
|
||||
>
|
||||
{flipComponentDropdown.label}
|
||||
</label>
|
||||
)}
|
||||
|
||||
<div data-cy={`${String(flipComponentDropdown.label).toLocaleLowerCase().replace(/\s+/g, '-')}-select-dropdown`} className={cx({ 'flex-grow-1': isHorizontalLayout })}>
|
||||
<div
|
||||
data-cy={`${generateCypressDataCy(flipComponentDropdown.label)}-select-dropdown`}
|
||||
className={cx({ 'flex-grow-1': isHorizontalLayout })}
|
||||
>
|
||||
<Select
|
||||
{...getElementProps(flipComponentDropdown)}
|
||||
styles={computeSelectStyles ? computeSelectStyles('100%') : {}}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { canDeleteDataSource, canUpdateDataSource } from '@/_helpers';
|
|||
import { OverlayTrigger, Tooltip } from 'react-bootstrap';
|
||||
import { orgEnvironmentVariableService, orgEnvironmentConstantService } from '../_services';
|
||||
import { Constants } from '@/_helpers/utils';
|
||||
import { generateCypressDataCy } from '../modules/common/helpers/cypressHelpers.js';
|
||||
|
||||
const DynamicFormV2 = ({
|
||||
schema,
|
||||
|
|
@ -437,7 +438,7 @@ const DynamicFormV2 = ({
|
|||
const labelElement = (
|
||||
<label
|
||||
className="form-label"
|
||||
data-cy={`label-${String(label).toLowerCase().replace(/\s+/g, '-')}`}
|
||||
data-cy={`label-${generateCypressDataCy(label)}`}
|
||||
style={{ textDecoration: tooltip ? 'underline 2px dashed' : 'none', textDecorationColor: 'var(--slate8)' }}
|
||||
>
|
||||
{label}
|
||||
|
|
@ -475,6 +476,7 @@ const DynamicFormV2 = ({
|
|||
'd-flex': isHorizontalLayout,
|
||||
'dynamic-form-row': isHorizontalLayout,
|
||||
})}
|
||||
data-cy={`${generateCypressDataCy(key)}-section`}
|
||||
key={key}
|
||||
>
|
||||
{!isSpecificComponent && (
|
||||
|
|
@ -505,7 +507,8 @@ const DynamicFormV2 = ({
|
|||
<Element
|
||||
{...getElementProps(uiProperties[key])}
|
||||
{...computedProps[propertyKey]}
|
||||
data-cy={`${String(label).toLocaleLowerCase().replace(/\s+/g, '-')}-text-field`}
|
||||
data-cy={`${generateCypressDataCy(label)}-text-field`}
|
||||
dataCy={uiProperties[key].key.replace(/_/g, '-')}
|
||||
//to be removed after whole ui is same
|
||||
isHorizontalLayout={isHorizontalLayout}
|
||||
/>
|
||||
|
|
@ -539,15 +542,16 @@ const DynamicFormV2 = ({
|
|||
{(flipComponentDropdown.label || isHorizontalLayout) && (
|
||||
<label
|
||||
className={cx('form-label')}
|
||||
data-cy={`${String(flipComponentDropdown.label)
|
||||
.toLocaleLowerCase()
|
||||
.replace(/\s+/g, '-')}-dropdown-label`}
|
||||
data-cy={`${generateCypressDataCy(flipComponentDropdown.label)}-dropdown-label`}
|
||||
>
|
||||
{flipComponentDropdown.label}
|
||||
</label>
|
||||
)}
|
||||
|
||||
<div data-cy={'query-select-dropdown'} className={cx({ 'flex-grow-1': isHorizontalLayout })}>
|
||||
<div
|
||||
data-cy={`${generateCypressDataCy(flipComponentDropdown.label)}-select-dropdown`}
|
||||
className={cx({ 'flex-grow-1': isHorizontalLayout })}
|
||||
>
|
||||
<Select {...getElementProps(flipComponentDropdown)} styles={{}} useCustomStyles={false} />
|
||||
</div>
|
||||
{flipComponentDropdown.helpText && (
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@ export default ({
|
|||
return (
|
||||
<div className="table-content-wrapper">
|
||||
{options.length === 0 && (
|
||||
<div className="empty-key-value"
|
||||
data-cy="label-empty-key-value">
|
||||
<div className="empty-key-value" data-cy="label-empty-key-value">
|
||||
<InfoIcon style={{ width: '16px', marginRight: '5px' }} />
|
||||
<span>There are no key value pairs added</span>
|
||||
</div>
|
||||
|
|
@ -86,7 +85,7 @@ export default ({
|
|||
|
||||
<div className="d-flex mb-2" style={{ height: '16px' }}>
|
||||
<ButtonSolid
|
||||
data-cy={`${dataCy}-add-more-button`}
|
||||
data-cy={`${dataCy}-add-button`}
|
||||
variant="ghostBlue"
|
||||
size="sm"
|
||||
onClick={() => addNewKeyValuePair(options)}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import NumberInput from './NumberInput';
|
|||
import TextInput from './TextInput';
|
||||
import { HelperMessage, InputLabel, ValidationMessage } from '../InputUtils/InputUtils';
|
||||
import { ButtonSolid } from '../../../../_components/AppButton';
|
||||
import { generateCypressDataCy } from '../../../../modules/common/helpers/cypressHelpers.js';
|
||||
|
||||
const CommonInput = ({ label, helperText, disabled, required, onChange: change, ...restProps }) => {
|
||||
const { type, encrypted, validation, isValidatedMessages, isDisabled } = restProps;
|
||||
|
|
@ -65,13 +66,14 @@ const CommonInput = ({ label, helperText, disabled, required, onChange: change,
|
|||
rel="noreferrer"
|
||||
disabled={isDisabled}
|
||||
onClick={toggleEditing}
|
||||
data-cy={`button-${generateCypressDataCy(isEditing ? 'Cancel' : 'Edit')}`}
|
||||
>
|
||||
{isEditing ? 'Cancel' : 'Edit'}
|
||||
</ButtonSolid>
|
||||
</div>
|
||||
|
||||
<div className="col-auto mb-2">
|
||||
<small className="text-green">
|
||||
<small className="text-green" data-cy="encrypted-text">
|
||||
<img className="mx-2 encrypted-icon" src="assets/images/icons/padlock.svg" width="12" height="12" />
|
||||
Encrypted
|
||||
</small>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Label } from '../../Label/Label';
|
|||
import ValidationIcon from './ValidationIcon';
|
||||
import { cn } from '@/lib/utils';
|
||||
import HelperIcon from './HelperIcon';
|
||||
import { generateCypressDataCy } from '../../../../modules/common/helpers/cypressHelpers.js';
|
||||
|
||||
export const ValidationMessage = ({ response, validationMessage, className }) => (
|
||||
<div className={cn('tw-flex tw-pl-[2px] tw-items-start tw-my-[2px]', className)}>
|
||||
|
|
@ -14,7 +15,7 @@ export const ValidationMessage = ({ response, validationMessage, className }) =>
|
|||
type="helper"
|
||||
size="default"
|
||||
className={`tw-font-normal ${response === true ? 'tw-text-text-success' : '!tw-text-text-warning'}`}
|
||||
data-cy="validation-label"
|
||||
data-cy={`${generateCypressDataCy(validationMessage)}-validation-label`}
|
||||
>
|
||||
{validationMessage}
|
||||
</Label>
|
||||
|
|
@ -53,7 +54,7 @@ export const InputLabel = ({ disabled, label, required }) => (
|
|||
type="label"
|
||||
size="default"
|
||||
className={`tw-font-medium tw-mb-[2px] ${disabled ? 'tw-text-text-disabled' : ''}`}
|
||||
data-cy="input-field-label"
|
||||
data-cy={`${generateCypressDataCy(label)}-field-label`}
|
||||
>
|
||||
{label}
|
||||
{required && <RequiredIndicator disabled={disabled} />}
|
||||
|
|
|
|||
6
frontend/src/modules/common/helpers/cypressHelpers.js
Normal file
6
frontend/src/modules/common/helpers/cypressHelpers.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export function generateCypressDataCy(text) {
|
||||
return String(text)
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "");
|
||||
}
|
||||
|
|
@ -36,6 +36,7 @@ import './dataSourceManager.theme.scss';
|
|||
import { canUpdateDataSource } from '@/_helpers';
|
||||
import DataSourceSchemaManager from '@/_helpers/dataSourceSchemaManager';
|
||||
import MultiEnvTabs from './MultiEnvTabs';
|
||||
import { generateCypressDataCy } from '../../../common/helpers/cypressHelpers';
|
||||
|
||||
class DataSourceManagerComponent extends React.Component {
|
||||
constructor(props) {
|
||||
|
|
@ -1127,7 +1128,11 @@ class DataSourceManagerComponent extends React.Component {
|
|||
<div className="row w-100">
|
||||
<div className="alert alert-danger" role="alert">
|
||||
{validationError.map((error, index) => (
|
||||
<div key={index} className="text-muted" data-cy="connection-alert-text">
|
||||
<div
|
||||
key={index}
|
||||
className="text-muted"
|
||||
data-cy={`${generateCypressDataCy(error)}-field-alert-text`}
|
||||
>
|
||||
{error}
|
||||
</div>
|
||||
))}
|
||||
|
|
|
|||
Loading…
Reference in a new issue