mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 17:08:34 +00:00
Merge branch 'main' into feat/steps-v2-alignment-style-improvement
This commit is contained in:
commit
68bf2807fd
255 changed files with 3183 additions and 18235 deletions
90
.github/workflows/cypress-appbuilder.yml
vendored
90
.github/workflows/cypress-appbuilder.yml
vendored
|
|
@ -3,7 +3,6 @@ name: Cypress App-Builder
|
|||
on:
|
||||
pull_request_target:
|
||||
types: [labeled, unlabeled, closed]
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
|
|
@ -54,20 +53,9 @@ jobs:
|
|||
git submodule foreach --recursive '
|
||||
git checkout ${{ env.BRANCH_NAME }} 2>/dev/null || git checkout main'
|
||||
|
||||
|
||||
- name: Set up Docker
|
||||
uses: docker-practice/actions-setup-docker@master
|
||||
|
||||
- name: Run PosgtreSQL Database Docker Container
|
||||
run: |
|
||||
sudo docker network create tooljet
|
||||
sudo docker run -d --name postgres --network tooljet -p 5432:5432 -e POSTGRES_PASSWORD=postgres -e POSTGRES_USER=postgres -e POSTGRES_PORT=5432 -d postgres:13
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
|
||||
- name: Install and build dependencies
|
||||
run: |
|
||||
npm cache clean --force
|
||||
|
|
@ -76,50 +64,59 @@ jobs:
|
|||
npm install --prefix frontend
|
||||
npm run build:plugins
|
||||
|
||||
- name: Local development setup
|
||||
run: |
|
||||
sudo docker network create tooljet
|
||||
sudo docker run -d --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=postgres -e POSTGRES_USER=postgres -e POSTGRES_PORT=5432 -d postgres:13
|
||||
|
||||
- name: Run PostgREST Docker Container
|
||||
run: |
|
||||
sudo docker run -d --name postgrest --network tooljet -p 3001:3000 \
|
||||
-e PGRST_DB_URI="postgres://postgres:postgres@localhost:5432/tooljet" \
|
||||
-e PGRST_DB_ANON_ROLE="postgres" \
|
||||
-e PGRST_JWT_SECRET="r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj" \
|
||||
-e PGRST_DB_PRE_CONFIG=postgrest.pre_config \
|
||||
postgrest/postgrest:v12.2.0
|
||||
|
||||
- name: Set up environment variables
|
||||
run: |
|
||||
echo "TOOLJET_EDITION=${{ matrix.edition == 'ee' && 'EE' || 'CE' }}" >> .env
|
||||
echo "TOOLJET_EDITION=${{ matrix.edition == 'ee' && 'ee' || 'ce' }}" >> .env
|
||||
echo "TOOLJET_HOST=http://localhost:8082" >> .env
|
||||
echo "LOCKBOX_MASTER_KEY=cd97331a419c09387bef49787f7da8d2a81d30733f0de6bed23ad8356d2068b2" >> .env
|
||||
echo "SECRET_KEY_BASE=7073b9a35a15dd20914ae17e36a693093f25b74b96517a5fec461fc901c51e011cd142c731bee48c5081ec8bac321c1f259ef097ef2a16f25df17a3798c03426" >> .env
|
||||
echo "SECRET_KEY_BASE=7073b9a35a15dd20914ae17e36a693093f25b74b96517a5fec461fc901c51e011cd142c731bee48c5081ec8bac321c1f259ef097ef2a16f25df17a3798c03426" >> .env
|
||||
echo "PG_DB=tooljet_development" >> .env
|
||||
echo "PG_USER=postgres" >> .env
|
||||
echo "PG_HOST=localhost" >> .env
|
||||
echo "PG_PASS=postgres" >> .env
|
||||
echo "PG_PORT=5432" >> .env
|
||||
echo "ENABLE_TOOLJET_DB=true" >> .env
|
||||
echo "TOOLJET_DB=tooljet" >> .env
|
||||
echo "TOOLJET_DB=tooljet_db" >> .env
|
||||
echo "TOOLJET_DB_USER=postgres" >> .env
|
||||
echo "TOOLJET_DB_HOST=localhost" >> .env
|
||||
echo "TOOLJET_DB_PASS=postgres" >> .env
|
||||
echo "PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj" >> .env
|
||||
echo "PGRST_HOST=localhost:3001" >> .env
|
||||
echo "TOOLJET_DB_STATEMENT_TIMEOUT=60000" >> .env
|
||||
echo "TOOLJET_DB_RECONFIG=true" >> .env
|
||||
echo "PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj" >> .env
|
||||
echo "PGRST_HOST=localhost:3001" >> .env
|
||||
echo "PGRST_DB_PRE_CONFIG=postgrest.pre_config" >> .env
|
||||
echo "PGRST_DB_URI=postgres://postgres:postgres@localhost:5432/tooljet" >> .env
|
||||
echo "ENABLE_MARKETPLACE_FEATURE=true" >> .env
|
||||
echo "ENABLE_MARKETPLACE_DEV_MODE=true" >> .env
|
||||
echo "ENABLE_PRIVATE_APP_EMBED=true" >> .env
|
||||
|
||||
- name: Set up database
|
||||
run: |
|
||||
npm run --prefix server db:create
|
||||
npm run --prefix server db:reset
|
||||
npm run --prefix server db:seed
|
||||
|
||||
- name: sleep 5
|
||||
run: sleep 5
|
||||
|
||||
- name: Run PostgREST Docker Container
|
||||
- name: Start services
|
||||
run: |
|
||||
sudo docker run -d --name postgrest --network tooljet -p 3001:3000 \
|
||||
-e PGRST_DB_URI="postgres://postgres:postgres@postgres:5432/tooljet" -e PGRST_DB_ANON_ROLE="postgres" -e PGRST_JWT_SECRET="r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj" -e PGRST_DB_PRE_CONFIG=postgrest.pre_config \
|
||||
postgrest/postgrest:v12.2.0
|
||||
|
||||
- name: Run plugins compilation in watch mode
|
||||
run: cd plugins && npm start &
|
||||
|
||||
- name: Run the server
|
||||
run: cd server && npm run start:dev &
|
||||
|
||||
- name: Run the client
|
||||
run: cd frontend && npm start &
|
||||
cd plugins && npm start &
|
||||
cd server && npm run start:dev &
|
||||
cd frontend && npm start &
|
||||
|
||||
- name: Wait for the server to be ready
|
||||
run: |
|
||||
|
|
@ -128,6 +125,18 @@ jobs:
|
|||
sleep 5
|
||||
done'
|
||||
|
||||
- name: Seeding (Setup Super Admin)
|
||||
run: |
|
||||
curl 'http://localhost:3000/api/onboarding/setup-super-admin' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"companyName": "ToolJet",
|
||||
"name": "The Developer",
|
||||
"workspaceName": "Tooljet'\''s workspace",
|
||||
"email": "dev@tooljet.io",
|
||||
"password": "password"
|
||||
}'
|
||||
|
||||
- name: docker logs
|
||||
run: sudo docker logs postgrest
|
||||
|
||||
|
|
@ -140,7 +149,7 @@ jobs:
|
|||
dir: "./cypress-tests"
|
||||
|
||||
- name: App builder
|
||||
uses: cypress-io/github-action@v5
|
||||
uses: cypress-io/github-action@v6
|
||||
with:
|
||||
working-directory: ./cypress-tests
|
||||
config: "baseUrl=http://localhost:8082"
|
||||
|
|
@ -150,10 +159,10 @@ jobs:
|
|||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: screenshots
|
||||
name: screenshots-appbuilder-${{ matrix.edition }}
|
||||
path: cypress-tests/cypress/screenshots
|
||||
|
||||
Cypress-App-builder-Subpath:
|
||||
Cypress-App-builder-Subpath:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'run-cypress-app-builder-subpath' }}
|
||||
|
|
@ -228,8 +237,17 @@ jobs:
|
|||
sleep 5
|
||||
done'
|
||||
|
||||
- name: Seeding
|
||||
run: docker exec Tooljet-app npm run db:seed:prod
|
||||
- name: Seeding (Setup Super Admin)
|
||||
run: |
|
||||
curl 'http://localhost:3000/api/onboarding/setup-super-admin' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"companyName": "ToolJet",,
|
||||
"name": "The Developer",
|
||||
"workspaceName": "Tooljet'\''s workspace",
|
||||
"email": "dev@tooljet.io",
|
||||
"password": "password"
|
||||
}'
|
||||
|
||||
- name: Create Cypress environment file
|
||||
id: create-json
|
||||
|
|
|
|||
35
.github/workflows/cypress-marketplace.yml
vendored
35
.github/workflows/cypress-marketplace.yml
vendored
|
|
@ -67,8 +67,8 @@ jobs:
|
|||
with:
|
||||
context: .
|
||||
file: docker/ce-production.Dockerfile
|
||||
push: false
|
||||
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}
|
||||
push: true
|
||||
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}-ce
|
||||
platforms: linux/amd64
|
||||
env:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
|
|
@ -80,8 +80,8 @@ jobs:
|
|||
with:
|
||||
context: .
|
||||
file: docker/ee/ee-production.Dockerfile
|
||||
push: false
|
||||
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}
|
||||
push: true
|
||||
tags: tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}-ee
|
||||
platforms: linux/amd64
|
||||
env:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
|
|
@ -116,10 +116,16 @@ jobs:
|
|||
- name: Pulling the docker-compose file
|
||||
run: curl -LO https://tooljet-test.s3.us-west-1.amazonaws.com/docker-compose.yaml && mkdir postgres_data
|
||||
|
||||
- name: Update docker-compose file
|
||||
- name: Update docker-compose file for CE
|
||||
run: |
|
||||
# Update docker-compose.yaml with the new image
|
||||
sed -i '/^[[:space:]]*tooljet:/,/^$/ s|^\([[:space:]]*image:[[:space:]]*\).*|\1tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}|' docker-compose.yaml
|
||||
sed -i '/^[[:space:]]*tooljet:/,/^$/ s|^\([[:space:]]*image:[[:space:]]*\).*|\1tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}-ce|' docker-compose.yaml
|
||||
|
||||
- name: Update docker-compose file for CE
|
||||
if: matrix.edition == 'ee'
|
||||
run: |
|
||||
# Update docker-compose.yaml with the new image
|
||||
sed -i '/^[[:space:]]*tooljet:/,/^$/ s|^\([[:space:]]*image:[[:space:]]*\).*|\1tooljet/tj-osv:${{ env.SAFE_BRANCH_NAME }}-ee|' docker-compose.yaml
|
||||
|
||||
- name: Install Docker Compose
|
||||
run: |
|
||||
|
|
@ -132,6 +138,9 @@ jobs:
|
|||
- name: Checking containers
|
||||
run: docker ps -a
|
||||
|
||||
- name: Checking containers
|
||||
run: docker ps -a
|
||||
|
||||
- name: docker logs
|
||||
run: sudo docker logs Tooljet-app
|
||||
|
||||
|
|
@ -142,8 +151,18 @@ jobs:
|
|||
sleep 5
|
||||
done'
|
||||
|
||||
- name: Seeding
|
||||
run: docker exec Tooljet-app npm run db:seed:prod
|
||||
- name: Seeding (Setup Super Admin)
|
||||
run: |
|
||||
curl 'http://localhost:3000/api/onboarding/setup-super-admin' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"companyName": "ToolJet",
|
||||
"name": "The Developer",
|
||||
"workspaceName": "Tooljet'\''s workspace",
|
||||
"email": "dev@tooljet.io",
|
||||
"password": "password"
|
||||
}'
|
||||
|
||||
|
||||
- name: Create Cypress environment file
|
||||
id: create-json
|
||||
|
|
|
|||
4
.github/workflows/cypress-platform.yml
vendored
4
.github/workflows/cypress-platform.yml
vendored
|
|
@ -102,6 +102,10 @@ jobs:
|
|||
echo "ENABLE_MARKETPLACE_FEATURE=true" >> .env
|
||||
echo "ENABLE_MARKETPLACE_DEV_MODE=true" >> .env
|
||||
echo "ENABLE_PRIVATE_APP_EMBED=true" >> .env
|
||||
echo "SSO_GOOGLE_OAUTH2_CLIENT_ID=123456789.apps.googleusercontent.com" >> .env
|
||||
echo "SSO_GOOGLE_OAUTH2_CLIENT_SECRET=ABCGFDNF-FHSDVFY-bskfh6234" >> .env
|
||||
echo "SSO_GIT_OAUTH2_CLIENT_ID=1234567890" >> .env
|
||||
echo "SSO_GIT_OAUTH2_CLIENT_SECRET=3346shfvkdjjsfkvxce32854e026a4531ed" >> .env
|
||||
|
||||
- name: Set up database
|
||||
run: |
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ module.exports = defineConfig({
|
|||
trashAssetsBeforeRuns: true,
|
||||
|
||||
e2e: {
|
||||
setupNodeEvents (on, config) {
|
||||
setupNodeEvents(on, config) {
|
||||
on("task", {
|
||||
readPdf (pathToPdf) {
|
||||
readPdf(pathToPdf) {
|
||||
return new Promise((resolve) => {
|
||||
const pdfPath = path.resolve(pathToPdf);
|
||||
let dataBuffer = fs.readFileSync(pdfPath);
|
||||
|
|
@ -33,7 +33,7 @@ module.exports = defineConfig({
|
|||
});
|
||||
|
||||
on("task", {
|
||||
readXlsx (filePath) {
|
||||
readXlsx(filePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
let dataBuffer = fs.readFileSync(filePath);
|
||||
|
|
@ -48,7 +48,7 @@ module.exports = defineConfig({
|
|||
});
|
||||
|
||||
on("task", {
|
||||
deleteFolder (folderName) {
|
||||
deleteFolder(folderName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
rmdir(folderName, { maxRetries: 10, recursive: true }, (err) => {
|
||||
if (err) {
|
||||
|
|
@ -62,7 +62,7 @@ module.exports = defineConfig({
|
|||
});
|
||||
|
||||
on("task", {
|
||||
dbConnection ({ dbconfig, sql }) {
|
||||
dbConnection({ dbconfig, sql }) {
|
||||
const client = new pg.Pool(dbconfig);
|
||||
return client.query(sql);
|
||||
},
|
||||
|
|
@ -76,8 +76,8 @@ module.exports = defineConfig({
|
|||
experimentalRunAllSpecs: true,
|
||||
baseUrl: "http://localhost:8082",
|
||||
specPattern: [
|
||||
"cypress/e2e/happyPath/appbuilder/commonTestcases/**/*.cy.js",
|
||||
"cypress/e2e/happyPath/appbuilder/ceTestcases/**/*.cy.js"
|
||||
"cypress/e2e/happyPath/appbuilder/commonTestcases/newSuits/**/*.cy.js",
|
||||
// "cypress/e2e/happyPath/appbuilder/ceTestcases/**/*.cy.js"
|
||||
],
|
||||
numTestsKeptInMemory: 1,
|
||||
redirectionLimit: 7,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
|
|
@ -98,6 +98,7 @@ module.exports = defineConfig({
|
|||
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/commonTestcases/**/*.cy.js",
|
||||
],
|
||||
|
|
|
|||
|
|
@ -92,11 +92,7 @@ module.exports = defineConfig({
|
|||
experimentalModfyObstructiveThirdPartyCode: true,
|
||||
experimentalRunAllSpecs: true,
|
||||
baseUrl: "http://localhost:8082",
|
||||
specPattern: [
|
||||
"cypress/e2e/happyPath/platform/ceTestcases/userFlow/firstUserOnboarding.cy.js",
|
||||
"cypress/e2e/happyPath/platform/ceTestcases/!(userFlow)/**/*.cy.js",
|
||||
"cypress/e2e/happyPath/platform/commonTestcases/**/*.cy.js",
|
||||
],
|
||||
specPattern: "cypress/e2e/happyPath/**/*.cy.js",
|
||||
downloadsFolder: "cypress/downloads",
|
||||
numTestsKeptInMemory: 0,
|
||||
redirectionLimit: 10,
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ Cypress.Commands.add("apiCreateGDS", (url, name, kind, options) => {
|
|||
log: false;
|
||||
}
|
||||
expect(response.status).to.equal(201);
|
||||
Cypress.env(`${name}-id`, response.body.id);
|
||||
Cypress.env(`${kind}`, response.body.id);
|
||||
|
||||
Cypress.log({
|
||||
name: "Create Data Source",
|
||||
|
|
@ -63,6 +63,30 @@ Cypress.Commands.add("apiCreateGDS", (url, name, kind, options) => {
|
|||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("apiFetchDataSourcesId", () => {
|
||||
cy.getAuthHeaders().then((headers) => {
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url: `${Cypress.env("server_host")}/api/data-sources/${Cypress.env("workspaceId")}/environments/${Cypress.env("environmentId")}/versions/${Cypress.env("editingVersionId")}`,
|
||||
headers,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
const dataSources = response.body?.data_sources || [];
|
||||
|
||||
dataSources.forEach((item) => {
|
||||
Cypress.env(`${item.kind}`, `${item.id}`);
|
||||
});
|
||||
|
||||
Cypress.log({
|
||||
name: "DS Fetch",
|
||||
displayName: "Data Sources Fetched",
|
||||
message: dataSources.map(ds => `\nKind: '${ds.kind}', Name: '${ds.id}'`).join(','),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Cypress.Commands.add("apiCreateApp", (appName = "testApp") => {
|
||||
cy.window({ log: false }).then((win) => {
|
||||
win.localStorage.setItem("walkthroughCompleted", "true");
|
||||
|
|
@ -140,14 +164,11 @@ Cypress.Commands.add(
|
|||
cy.visit(`/${workspaceId}/apps/${appId}/${slug}`);
|
||||
|
||||
cy.wait("@getAppData").then((interception) => {
|
||||
// Assuming the response body is a JSON object
|
||||
const responseData = interception.response.body;
|
||||
|
||||
// Set the response data as an environment variable
|
||||
Cypress.env("apiResponseData", responseData);
|
||||
Cypress.env("editingVersionId", responseData.editing_version.id);
|
||||
Cypress.env("environmentId", responseData.editorEnvironment.id);
|
||||
|
||||
// You can log it to check if the env var is set correctly
|
||||
cy.log(Cypress.env("apiResponseData"));
|
||||
});
|
||||
cy.get(componentSelector, { timeout: 10000 });
|
||||
}
|
||||
|
|
@ -267,6 +288,7 @@ Cypress.Commands.add("apiAddQuery", (queryName, query, dataQueryId) => {
|
|||
Cypress.Commands.add(
|
||||
"apiAddQueryToApp",
|
||||
(queryName, options, dsName, dsKind) => {
|
||||
cy.log(`${Cypress.env("server_host")}/api/data-queries/data-sources/${Cypress.env(dsKind)}/versions/${Cypress.env("editingVersionId")}`)
|
||||
cy.getCookie("tj_auth_token", { log: false }).then((cookie) => {
|
||||
const authToken = `tj_auth_token=${cookie.value}`;
|
||||
const workspaceId = Cypress.env("workspaceId");
|
||||
|
|
@ -286,7 +308,7 @@ Cypress.Commands.add(
|
|||
|
||||
cy.request({
|
||||
method: "POST",
|
||||
url: `${Cypress.env("server_host")}/api/data-queries`,
|
||||
url: `${Cypress.env("server_host")}/api/data-queries/data-sources/${Cypress.env(dsKind)}/versions/${Cypress.env("editingVersionId")}`,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Cookie: authToken,
|
||||
|
|
@ -627,10 +649,11 @@ Cypress.Commands.add("apiAddDataToTable", (tableName, data) => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add("apiGetDataSourceIdByName", (dataSourceName) => {
|
||||
const workspaceId = Cypress.env("workspaceId");
|
||||
cy.getAuthHeaders().then((headers) => {
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url: `${Cypress.env("server_host")}/api/data-sources`,
|
||||
url: `${Cypress.env("server_host")}/api/data-sources/${workspaceId}`,
|
||||
headers: headers,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
|
|
@ -665,7 +688,7 @@ Cypress.Commands.add(
|
|||
name: dataSourceName,
|
||||
options: [
|
||||
{ key: "connection_type", value: "manual", encrypted: false },
|
||||
{ key: "host", value: "35.202.183.199" },
|
||||
{ key: "host", value: "35.238.9.114" },
|
||||
{ key: "port", value: 5432 },
|
||||
{ key: "database", value: "student" },
|
||||
{ key: "username", value: "postgres" },
|
||||
|
|
|
|||
|
|
@ -15,15 +15,11 @@ const API_ENDPOINT =
|
|||
Cypress.Commands.add(
|
||||
"appUILogin",
|
||||
(email = "dev@tooljet.io", password = "password") => {
|
||||
cy.visit("/");
|
||||
cy.wait(1000);
|
||||
cy.clearAndType(onboardingSelectors.loginEmailInput, email);
|
||||
cy.clearAndType(onboardingSelectors.loginPasswordInput, password);
|
||||
cy.get(onboardingSelectors.signInButton).click();
|
||||
|
||||
cy.intercept("GET", API_ENDPOINT).as("library_apps");
|
||||
cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
|
||||
cy.wait("@library_apps");
|
||||
cy.wait(2000);
|
||||
cy.get('[data-cy="main-wrapper"]', { timeout: 10000 }).should("be.visible");
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -400,36 +396,39 @@ Cypress.Commands.add("getPosition", (componentName) => {
|
|||
Cypress.Commands.add("defaultWorkspaceLogin", () => {
|
||||
cy.apiLogin();
|
||||
|
||||
// cy.intercept("GET", API_ENDPOINT).as("library_apps");
|
||||
cy.visit("/my-workspace");
|
||||
cy.intercept("GET", API_ENDPOINT).as("library_apps");
|
||||
cy.wait(2000)
|
||||
cy.get(commonSelectors.homePageLogo, { timeout: 10000 });
|
||||
cy.wait("@library_apps");
|
||||
// });
|
||||
// cy.wait("@library_apps");
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
"visitSlug",
|
||||
({
|
||||
actualUrl,
|
||||
currentUrl = `${Cypress.config("baseUrl")}/error/unknown`,
|
||||
errorUrls = [
|
||||
`${Cypress.config("baseUrl")}/error/unknown`,
|
||||
`${Cypress.config("baseUrl")}/error/restricted`,
|
||||
],
|
||||
}) => {
|
||||
// Ensure actualUrl is provided
|
||||
if (!actualUrl) {
|
||||
throw new Error("actualUrl is required for visitSlug command.");
|
||||
}
|
||||
|
||||
cy.visit(actualUrl);
|
||||
|
||||
// Dynamically wait for the correct URL or handle navigation errors
|
||||
cy.url().then((url) => {
|
||||
if (url === currentUrl) {
|
||||
cy.log(`Navigation resulted in unexpected URL: ${url}. Retrying...`);
|
||||
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") {
|
||||
cy.get(commonEeSelectors.promoteButton).click();
|
||||
|
|
@ -520,16 +519,6 @@ Cypress.Commands.add("verifyElement", (selector, text, eqValue) => {
|
|||
element.should("be.visible").and("have.text", text);
|
||||
});
|
||||
|
||||
Cypress.Commands.add("loginWithCredentials", (email, password) => {
|
||||
cy.get(onboardingSelectors.loginEmailInput, { timeout: 20000 }).should(
|
||||
"be.visible"
|
||||
);
|
||||
cy.clearAndType(onboardingSelectors.loginEmailInput, email);
|
||||
cy.clearAndType(onboardingSelectors.loginPasswordInput, password);
|
||||
cy.get(onboardingSelectors.signInButton).click();
|
||||
cy.wait(3000);
|
||||
cy.get(commonSelectors.pageLogo).should("be.visible");
|
||||
});
|
||||
|
||||
Cypress.Commands.add("getAppId", (appName) => {
|
||||
cy.task("dbConnection", {
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ export const commonSelectors = {
|
|||
cloneAppTitle: '[data-cy="clone-app-title"]',
|
||||
cloneAppButton: '[data-cy="clone-app"]',
|
||||
appNameErrorLabel: '[data-cy="app-name-error-label"]',
|
||||
importAppTitle: '[data-cy="import-app-title"]',
|
||||
importAppTitle: '[data-cy="import-an-app"]',
|
||||
importAppButton: '[data-cy="import-app"]',
|
||||
chooseFromTemplateButton: '[data-cy="choose-from-template-button"]',
|
||||
CreateAppFromTemplateButton: '[data-cy="create-new-app-from-template-title"]',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export const multipageSelector = {
|
||||
sidebarPageButton: '[data-cy="left-sidebar-page-button"]',
|
||||
pagesLabel: '[data-cy="label-pages"]',
|
||||
addPageIcon: '[title="Add Page"]',
|
||||
addPageIcon: '[data-cy="add-page-button"]',
|
||||
searchPageIcon: '[title="Search"]',
|
||||
pagesPinIcon: '[title="Pin"]',
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export const dataSourceText = {
|
|||
? "Databases (20)"
|
||||
: "Databases (18)";
|
||||
},
|
||||
allApis: "APIs (20)",
|
||||
allApis: "APIs (21)",
|
||||
allCloudStorage: "Cloud Storages (4)",
|
||||
pluginsLabelAndCount: "Plugins (0)",
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export const postgreSqlText = {
|
|||
allDataSources: () => {
|
||||
return Cypress.env("marketplace_action")
|
||||
? "All data sources (44)"
|
||||
: "All data sources (43)";
|
||||
: "All data sources (45)";
|
||||
},
|
||||
commonlyUsed: "Commonly used (5)",
|
||||
allDatabase: () => {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ export const workspaceConstantsText = {
|
|||
secretsConstantInfo: "To resolve a secret workspace constant use {{secrets.access_token}}Read documentation",
|
||||
emptyStateHeader: "No Workspace constants yet",
|
||||
emptyStateText:
|
||||
"Use workspace constants seamlessly in both the app builder and data source connections across ToolJet.",
|
||||
"Use workspace constants seamlessly within both the app builder and data source connections across the platform.",
|
||||
addNewConstantButton: "+ Create new constant",
|
||||
addConstatntText: "Add new constant in production ",
|
||||
constantCreatedToast: (type) => { return `${type} constant created successfully!` },
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ describe("Text Input", () => {
|
|||
).should("have.css", "border-radius", "20px");
|
||||
});
|
||||
|
||||
it.skip("should verify the app preview", () => {});
|
||||
it.skip("should verify the app preview", () => { });
|
||||
|
||||
it("should verify CSA", () => {
|
||||
const data = {};
|
||||
|
|
@ -43,7 +43,7 @@ describe("Editor title", () => {
|
|||
cy.apiDeleteApp();
|
||||
});
|
||||
it("should verify titles", () => {
|
||||
cy.url().should("include", "/tjs-workspace");
|
||||
cy.url().should("include", "/tooljets-workspace");
|
||||
// cy.title().should("eq", "Dashboard | ToolJet");
|
||||
cy.title().should("eq", "ToolJet");
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ describe("Editor title", () => {
|
|||
cy.openInCurrentTab(commonWidgetSelector.previewButton);
|
||||
|
||||
cy.url().should("include", `/applications/${Cypress.env("appId")}`);
|
||||
cy.title().should("eq", `${data.appName} | ToolJet`);
|
||||
// cy.title().should("eq", `${data.appName} | ToolJet`);
|
||||
// cy.title().should("eq", `Preview - ${data.appName} | ToolJet`);
|
||||
|
||||
cy.go("back");
|
||||
|
|
@ -76,7 +76,7 @@ describe('Button Component Tests', () => {
|
|||
cy.apiCreateApp(`${fake.companyName}-Button-App`);
|
||||
cy.openApp();
|
||||
cy.dragAndDropWidget("Button", 50, 50);
|
||||
cy.get('[data-cy="query-manager-collapse-button"]').click();
|
||||
cy.get('[data-cy="query-manager-toggle-button"]').click();
|
||||
});
|
||||
|
||||
it('should verify all the exposed values on inspector', () => {
|
||||
|
|
@ -90,7 +90,7 @@ describe('Button Component Tests', () => {
|
|||
|
||||
});
|
||||
|
||||
it('should verify all the events from the button', () => {
|
||||
it.skip('should verify all the events from the button', () => {
|
||||
const events = [
|
||||
{ event: "On hover", message: "On hover Event" },
|
||||
{ event: "On Click", message: "On Click Event" },
|
||||
|
|
@ -110,7 +110,7 @@ describe('Button Component Tests', () => {
|
|||
verifyTextInputEvents(textInputSelector);
|
||||
});
|
||||
|
||||
it('should verify all the CSA from button', () => {
|
||||
it.skip('should verify all the CSA from button', () => {
|
||||
addMultiEventsWithAlert([
|
||||
{ event: "On hover", message: "On hover Event" },
|
||||
{ event: "On Click", message: "On Click Event" },
|
||||
|
|
@ -84,7 +84,7 @@ describe('Checkbox Component Tests', () => {
|
|||
cy.apiCreateApp(`${fake.companyName}-Checkbox-App`);
|
||||
cy.openApp();
|
||||
cy.dragAndDropWidget("Checkbox", 50, 50);
|
||||
cy.get('[data-cy="query-manager-collapse-button"]').click();
|
||||
cy.get('[data-cy="query-manager-toggle-button"]').click();
|
||||
});
|
||||
|
||||
it('should verify all the exposed values on inspector', () => {
|
||||
|
|
@ -98,7 +98,7 @@ describe('Checkbox Component Tests', () => {
|
|||
|
||||
});
|
||||
|
||||
it('should verify all the events from the Checkbox', () => {
|
||||
it.skip('should verify all the events from the Checkbox', () => {
|
||||
const events = [
|
||||
{ event: "On Change", message: "On Change Event" },
|
||||
];
|
||||
|
|
@ -118,7 +118,7 @@ describe('Checkbox Component Tests', () => {
|
|||
verifyTextInputEvents(textInputSelector);
|
||||
});
|
||||
|
||||
it('should verify all the CSA from Checkbox', () => {
|
||||
it.skip('should verify all the CSA from Checkbox', () => {
|
||||
const events = [
|
||||
{ event: "On Change", message: "On Change Event" },
|
||||
];
|
||||
|
|
@ -93,7 +93,7 @@ describe('Dropdown Component Tests', () => {
|
|||
cy.apiCreateApp(`${fake.companyName}-Dropdown-App`);
|
||||
cy.openApp();
|
||||
cy.dragAndDropWidget("Dropdown", 50, 50);
|
||||
cy.get('[data-cy="query-manager-collapse-button"]').click();
|
||||
cy.get('[data-cy="query-manager-toggle-button"]').click();
|
||||
});
|
||||
|
||||
it('should verify all the exposed values on inspector', () => {
|
||||
|
|
@ -91,7 +91,7 @@ describe("Global Actions", () => {
|
|||
cy.waitForAutoSave();
|
||||
addInputOnQueryField("runjs", "actions.showModal('modal1');");
|
||||
query("run");
|
||||
cy.get('[data-cy="modal-title"]').should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
|
||||
addInputOnQueryField("runjs", "actions.closeModal('modal1');");
|
||||
query("run");
|
||||
|
|
@ -114,7 +114,7 @@ describe("Global Actions", () => {
|
|||
"actions.setLocalStorage('localStorage','data from runjs');"
|
||||
);
|
||||
query("run");
|
||||
|
||||
cy.wait(500)
|
||||
cy.getAllLocalStorage().then((result) => {
|
||||
expect(result[Cypress.config().baseUrl].localStorage).to.deep.equal(
|
||||
"data from runjs"
|
||||
|
|
@ -96,7 +96,7 @@ describe('Multiselect Component Tests', () => {
|
|||
cy.apiCreateApp(`${fake.companyName}-Multiselect-App`);
|
||||
cy.openApp();
|
||||
cy.dragAndDropWidget("Multiselect", 50, 50);
|
||||
cy.get('[data-cy="query-manager-collapse-button"]').click();
|
||||
cy.get('[data-cy="query-manager-toggle-button"]').click();
|
||||
});
|
||||
|
||||
it('should verify all the exposed values on inspector', () => {
|
||||
|
|
@ -87,7 +87,7 @@ describe('Number Input Component Tests', () => {
|
|||
cy.apiCreateApp(`${fake.companyName}-Numberinput-App`);
|
||||
cy.openApp();
|
||||
cy.dragAndDropWidget("Number Input", 50, 50);
|
||||
cy.get('[data-cy="query-manager-collapse-button"]').click();
|
||||
cy.get('[data-cy="query-manager-toggle-button"]').click();
|
||||
});
|
||||
|
||||
it('should verify all the exposed values on inspector', () => {
|
||||
|
|
@ -101,7 +101,7 @@ describe('Number Input Component Tests', () => {
|
|||
|
||||
});
|
||||
|
||||
it('should verify all the events from the number input', () => {
|
||||
it.skip('should verify all the events from the number input', () => {
|
||||
const events = [
|
||||
{ event: "On Focus", message: "On Focus Event" },
|
||||
{ event: "On Blur", message: "On Blur Event" },
|
||||
|
|
@ -129,7 +129,7 @@ describe('Number Input Component Tests', () => {
|
|||
inputEvents(inputSelector);
|
||||
});
|
||||
|
||||
it('should verify all the CSA from number input', () => {
|
||||
it.skip('should verify all the CSA from number input', () => {
|
||||
const actions = [
|
||||
{ event: "On click", action: "Set visibility", valueToggle: "{{false}}" }, //b1
|
||||
{ event: "On click", action: "Set visibility", valueToggle: "{{true}}" },//b2
|
||||
|
|
@ -87,7 +87,7 @@ describe('Password Input Component Tests', () => {
|
|||
cy.apiCreateApp(`${fake.companyName}-Passwordinput-App`);
|
||||
cy.openApp();
|
||||
cy.dragAndDropWidget("Password Input", 50, 50);
|
||||
cy.get('[data-cy="query-manager-collapse-button"]').click();
|
||||
cy.get('[data-cy="query-manager-toggle-button"]').click();
|
||||
});
|
||||
|
||||
it('should verify all the exposed values on inspector', () => {
|
||||
|
|
@ -101,7 +101,7 @@ describe('Password Input Component Tests', () => {
|
|||
|
||||
});
|
||||
|
||||
it('should verify all the events from the password input', () => {
|
||||
it.skip('should verify all the events from the password input', () => {
|
||||
const events = [
|
||||
{ event: "On Focus", message: "On Focus Event" },
|
||||
{ event: "On Blur", message: "On Blur Event" },
|
||||
|
|
@ -95,10 +95,10 @@ describe('Text Input Component Tests', () => {
|
|||
cy.apiCreateApp(`${fake.companyName}-Textinput-App`);
|
||||
cy.openApp();
|
||||
cy.dragAndDropWidget("Text Input", 50, 50);
|
||||
cy.get('[data-cy="query-manager-collapse-button"]').click();
|
||||
cy.get('[data-cy="query-manager-toggle-button"]').click();
|
||||
});
|
||||
|
||||
it('should verify all the exposed values on inspector', () => {
|
||||
it.skip('should verify all the exposed values on inspector', () => {
|
||||
cy.get(commonWidgetSelector.sidebarinspector).click();
|
||||
cy.get(".tooltip-inner").invoke("hide");
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ describe('Text Input Component Tests', () => {
|
|||
|
||||
});
|
||||
|
||||
it('should verify all the events from the text input', () => {
|
||||
it.skip('should verify all the events from the text input', () => {
|
||||
const events = [
|
||||
{ event: "On Focus", message: "On Focus Event" },
|
||||
{ event: "On Blur", message: "On Blur Event" },
|
||||
|
|
@ -137,7 +137,7 @@ describe('Text Input Component Tests', () => {
|
|||
verifyTextInputEvents(textInputSelector);
|
||||
});
|
||||
|
||||
it('should verify all the CSA from text input', () => {
|
||||
it.skip('should verify all the CSA from text input', () => {
|
||||
const actions = [
|
||||
{ event: "On click", action: "Set visibility", valueToggle: "{{false}}" }, //b1
|
||||
{ event: "On click", action: "Visibility", valueToggle: "{{true}}" },//b2
|
||||
|
|
@ -80,7 +80,7 @@ describe('ToggleSwitch Component Tests', () => {
|
|||
cy.apiCreateApp(`${fake.companyName}-Toggle-App`);
|
||||
cy.openApp();
|
||||
cy.dragAndDropWidget("Toggle Switch", 50, 50);
|
||||
cy.get('[data-cy="query-manager-collapse-button"]').click();
|
||||
cy.get('[data-cy="query-manager-toggle-button"]').click();
|
||||
});
|
||||
|
||||
it('should verify all the exposed values on inspector', () => {
|
||||
|
|
@ -137,6 +137,8 @@ describe('ToggleSwitch Component Tests', () => {
|
|||
cy.get(commonWidgetSelector.draggableWidget(component)).should("not.be.visible");
|
||||
|
||||
cy.get(commonWidgetSelector.draggableWidget("button2")).click();
|
||||
cy.wait(500);
|
||||
cy.forceClickOnCanvas();
|
||||
cy.get(commonWidgetSelector.draggableWidget(component)).should("be.visible");
|
||||
|
||||
cy.get(commonWidgetSelector.draggableWidget("button3")).click();
|
||||
|
|
@ -17,6 +17,7 @@ describe("Editor- Inspector", () => {
|
|||
cy.apiLogin();
|
||||
cy.apiCreateApp(`${fake.companyName}-inspector-App`);
|
||||
cy.openApp("?key=value");
|
||||
cy.viewport(1800, 1800);
|
||||
});
|
||||
|
||||
it("should verify the values of inspector", () => {
|
||||
|
|
@ -45,14 +46,14 @@ describe("Editor- Inspector", () => {
|
|||
cy.apiDeleteApp();
|
||||
});
|
||||
|
||||
it("should verify dynamic items", () => {
|
||||
it.skip("should verify dynamic items", () => {
|
||||
cy.get(commonWidgetSelector.sidebarinspector).click();
|
||||
cy.get(".tooltip-inner").invoke("hide");
|
||||
|
||||
cy.get(multipageSelector.sidebarPageButton).click();
|
||||
addNewPage("test_page");
|
||||
|
||||
cy.dragAndDropWidget("Button", 500, 500);
|
||||
cy.dragAndDropWidget("Button", 100, 100);
|
||||
selectEvent("On click", "Switch page");
|
||||
cy.get('[data-cy="switch-page-label-and-input"] > .select-search').click().type("home{enter}");
|
||||
|
||||
|
|
@ -72,7 +73,9 @@ describe("Editor- Inspector", () => {
|
|||
cy.dragAndDropWidget("Button", 500, 300);
|
||||
selectEvent("On click", "Set variable");
|
||||
addSupportCSAData("event-key", "globalVar");
|
||||
cy.wait(500)
|
||||
addSupportCSAData("variable", "globalVar");
|
||||
cy.wait(500)
|
||||
|
||||
cy.forceClickOnCanvas();
|
||||
cy.waitForAutoSave();
|
||||
|
|
@ -141,17 +144,17 @@ describe("Editor- Inspector", () => {
|
|||
cy.dragAndDropWidget("Button", 500, 300);
|
||||
cy.get(commonWidgetSelector.sidebarinspector).click();
|
||||
openNode("components");
|
||||
cy.get(`[data-cy="inspector-node-button1"] > .mx-1`).realHover();
|
||||
cy.get('[style="height: 13px; width: 13px;"] > img').click();
|
||||
cy.get(`[data-cy="inspector-node-button1"] > .mx-1`).eq(0).realHover();
|
||||
cy.get('[style="height: 13px; width: 13px;"] > img').last().click();
|
||||
cy.notVisible(commonWidgetSelector.draggableWidget("button1"));
|
||||
cy.apiDeleteApp();
|
||||
});
|
||||
|
||||
it("should verify deletion of component from inspector", () => {
|
||||
it.skip("should verify deletion of component from inspector", () => {
|
||||
cy.dragAndDropWidget("button", 500, 500);
|
||||
cy.get(commonWidgetSelector.sidebarinspector).click();
|
||||
deleteComponentFromInspector("button1");
|
||||
cy.verifyToastMessage(`[class=go3958317564]`, "Component deleted! (⌘ + Z to undo)");
|
||||
cy.verifyToastMessage(`[class=go3958317564]`, "Component deleted! (ctrl + Z to undo)");
|
||||
|
||||
navigateToCreateNewVersionModal((currentVersion = "v1"));
|
||||
createNewVersion((newVersion = ["v2"]), (versionFrom = "v1"));
|
||||
|
|
@ -14,6 +14,7 @@ describe("Chaining of queries", () => {
|
|||
cy.apiLogin();
|
||||
cy.apiCreateApp(`${fake.companyName}-chaining-App`);
|
||||
cy.openApp();
|
||||
cy.apiFetchDataSourcesId()
|
||||
cy.viewport(1800, 1800);
|
||||
cy.dragAndDropWidget("Button");
|
||||
resizeQueryPanel("80");
|
||||
|
|
@ -57,7 +58,7 @@ describe("Chaining of queries", () => {
|
|||
);
|
||||
|
||||
cy.apiCreateGDS(
|
||||
"http://localhost:3000/api/v2/data_sources",
|
||||
`http://localhost:3000/api/data-sources`,
|
||||
`cypress-${dsName}-qc-postgresql`,
|
||||
"postgresql",
|
||||
[
|
||||
|
|
@ -68,8 +69,10 @@ describe("Chaining of queries", () => {
|
|||
{ key: "password", value: Cypress.env("pg_password"), encrypted: true },
|
||||
{ key: "ssl_enabled", value: false, encrypted: false },
|
||||
{ key: "ssl_certificate", value: "none", encrypted: false },
|
||||
{ key: "connection_type", value: "manual", encrypted: false }
|
||||
]
|
||||
);
|
||||
cy.log("Data source created");
|
||||
cy.apiAddQueryToApp(
|
||||
"psql",
|
||||
{
|
||||
|
|
@ -92,8 +95,17 @@ describe("Chaining of queries", () => {
|
|||
chainQuery("restapi", "tjdb");
|
||||
addSuccessNotification("restapi");
|
||||
|
||||
cy.get(`[data-cy="list-query-tjdb"]`).click();
|
||||
cy.get('[data-cy="query-tab-settings"]').click();
|
||||
selectEvent("Query Failure", "Show Alert");
|
||||
cy.get('[data-cy="debounce-input-field"]')
|
||||
.click()
|
||||
.type(`{selectAll}{backspace}2000{enter}`);
|
||||
cy.wait(1000)
|
||||
cy.get('[data-cy="query-tab-setup"]').click();
|
||||
|
||||
openEditorSidebar(buttonText.defaultWidgetName);
|
||||
selectEvent("On Click", "Run Query", 1, `[data-cy="add-event-handler"]`, 1);
|
||||
selectEvent("On Click", "Run Query", 0, `[data-cy="add-event-handler"]`, 0);
|
||||
cy.wait(500);
|
||||
cy.get('[data-cy="query-selection-field"]')
|
||||
.click()
|
||||
|
|
@ -105,11 +117,13 @@ describe("Chaining of queries", () => {
|
|||
cy.verifyToastMessage(commonSelectors.toastMessage, "psql");
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, "runjs");
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, "runpy");
|
||||
cy.wait(500);
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, "restapi");
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, "Invalid operation");
|
||||
// cy.verifyToastMessage(commonSelectors.toastMessage, "Hello World");
|
||||
});
|
||||
|
||||
it("should verify query duplication", () => {
|
||||
it.skip("should verify query duplication", () => {
|
||||
|
||||
const data = {};
|
||||
let dsName = fake.companyName;
|
||||
data.customText = randomString(12);
|
||||
|
|
@ -133,7 +147,7 @@ describe("Chaining of queries", () => {
|
|||
addSuccessNotification("runjs");
|
||||
|
||||
openEditorSidebar(buttonText.defaultWidgetName);
|
||||
selectEvent("On Click", "Run Query", 1, `[data-cy="add-event-handler"]`, 1);
|
||||
selectEvent("On Click", "Run Query", 0, `[data-cy="add-event-handler"]`, 0);
|
||||
cy.wait(500);
|
||||
cy.get('[data-cy="query-selection-field"]')
|
||||
.click()
|
||||
|
|
@ -54,7 +54,7 @@ describe("RunJS", () => {
|
|||
cy.apiDeleteApp();
|
||||
});
|
||||
|
||||
it("should verify global and page data", () => {
|
||||
it.skip("should verify global and page data", () => {
|
||||
const data = {};
|
||||
data.customText = randomString(12);
|
||||
|
||||
|
|
@ -147,9 +147,9 @@ describe("RunJS", () => {
|
|||
"runjs",
|
||||
"actions.showAlert('success', 'alert from runjs');"
|
||||
);
|
||||
cy.get('[data-cy="query-tab-Settings"]').click();
|
||||
cy.get('[data-cy="query-tab-settings"]').click();
|
||||
changeQueryToggles("run-on-app-load");
|
||||
cy.wait(`@editQuery`);
|
||||
// cy.wait(`@editQuery`);
|
||||
cy.waitForAutoSave();
|
||||
cy.waitForAutoSave();
|
||||
cy.reload();
|
||||
|
|
@ -159,9 +159,9 @@ describe("RunJS", () => {
|
|||
"alert from runjs",
|
||||
false
|
||||
);
|
||||
cy.get('[data-cy="query-tab-Settings"]').click();
|
||||
cy.get('[data-cy="query-tab-settings"]').click();
|
||||
changeQueryToggles("confirmation-before-run");
|
||||
cy.wait(`@editQuery`);
|
||||
// cy.wait(`@editQuery`);
|
||||
cy.waitForAutoSave();
|
||||
cy.reload();
|
||||
cy.get('[data-cy="modal-message"]').verifyVisibleElement(
|
||||
|
|
@ -172,12 +172,12 @@ describe("RunJS", () => {
|
|||
cy.verifyToastMessage(commonSelectors.toastMessage, "alert from runjs");
|
||||
|
||||
resizeQueryPanel("80");
|
||||
cy.get('[data-cy="query-tab-Settings"]').click();
|
||||
cy.get('[data-cy="query-tab-settings"]').click();
|
||||
changeQueryToggles("notification-on-success");
|
||||
cy.get('[data-cy="success-message-input-field"]').clearAndTypeOnCodeMirror(
|
||||
"Success alert"
|
||||
);
|
||||
cy.get('[data-cy="query-tab-Setup"]').click();
|
||||
cy.get('[data-cy="query-tab-setup"]').click();
|
||||
cy.get('[data-cy="runjs-input-field"]').realClick();
|
||||
cy.wait(1000);
|
||||
cy.waitForAutoSave();
|
||||
|
|
@ -59,7 +59,7 @@ describe("runpy", () => {
|
|||
cy.apiDeleteApp();
|
||||
});
|
||||
|
||||
it.only("should verify actions", () => {
|
||||
it.skip("should verify actions", () => {
|
||||
const data = {};
|
||||
data.customText = randomString(12);
|
||||
|
||||
|
|
@ -120,18 +120,18 @@ actions.unsetPageVariable('pageVar')`
|
|||
cy.waitForAutoSave();
|
||||
addInputOnQueryField("runpy", "actions.showModal('modal1')");
|
||||
query("run");
|
||||
cy.get('[data-cy="modal-title"]').should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
cy.get('[data-cy="runpy-input-field"]').click({ force: true });
|
||||
|
||||
addInputOnQueryField("runpy", "actions.closeModal('modal1')");
|
||||
cy.wait(`@editQuery`);
|
||||
// cy.wait(`@editQuery`);
|
||||
cy.waitForAutoSave();
|
||||
query("run");
|
||||
waitForQueryAction("run");
|
||||
cy.notVisible('[data-cy="modal-title"]');
|
||||
|
||||
addInputOnQueryField("runpy", "actions.copyToClipboard('data from runpy')");
|
||||
cy.wait(`@editQuery`);
|
||||
// cy.wait(`@editQuery`);
|
||||
cy.waitForAutoSave();
|
||||
query("run");
|
||||
waitForQueryAction("run");
|
||||
|
|
@ -144,7 +144,7 @@ actions.unsetPageVariable('pageVar')`
|
|||
"runpy",
|
||||
"actions.setLocalStorage('localStorage','data from runpy')"
|
||||
);
|
||||
cy.wait(`@editQuery`);
|
||||
// cy.wait(`@editQuery`);
|
||||
cy.waitForAutoSave();
|
||||
query("run");
|
||||
waitForQueryAction("run");
|
||||
|
|
@ -155,17 +155,17 @@ actions.unsetPageVariable('pageVar')`
|
|||
);
|
||||
});
|
||||
|
||||
addInputOnQueryField(
|
||||
"runpy",
|
||||
"actions.generateFile('runpycsv', 'csv', [{ 'name': 'John', 'email': 'john@tooljet.com' }])"
|
||||
);
|
||||
query("run");
|
||||
// addInputOnQueryField( //Need fix asap
|
||||
// "runpy",
|
||||
// "actions.generateFile('runpycsv', 'csv', [{ 'name': 'John', 'email': 'john@tooljet.com' }])"
|
||||
// );
|
||||
// query("run");
|
||||
|
||||
cy.wait(3000);
|
||||
// cy.wait(3000);
|
||||
|
||||
cy.readFile("cypress/downloads/runpycsv.csv", "utf-8")
|
||||
.should("contain", "name,email")
|
||||
.and("contain", "John,john@tooljet.com");
|
||||
// cy.readFile("cypress/downloads/runpycsv.csv", "utf-8")
|
||||
// .should("contain", "name,email")
|
||||
// .and("contain", "John,john@tooljet.com");
|
||||
|
||||
// addInputOnQueryField(
|
||||
// "runpy",
|
||||
|
|
@ -174,7 +174,7 @@ actions.unsetPageVariable('pageVar')`
|
|||
// query("run");
|
||||
|
||||
addInputOnQueryField("runpy", "actions.logout()");
|
||||
cy.wait(`@editQuery`);
|
||||
// cy.wait(`@editQuery`);
|
||||
cy.wait(200);
|
||||
cy.waitForAutoSave();
|
||||
query("run");
|
||||
|
|
@ -184,7 +184,7 @@ actions.unsetPageVariable('pageVar')`
|
|||
);
|
||||
});
|
||||
|
||||
it("should verify global and page data", () => {
|
||||
it.skip("should verify global and page data", () => {
|
||||
const data = {};
|
||||
data.customText = randomString(12);
|
||||
|
||||
|
|
@ -273,20 +273,20 @@ actions.unsetPageVariable('pageVar')`
|
|||
"runpy",
|
||||
"actions.showAlert('success', 'alert from runpy');"
|
||||
);
|
||||
cy.get('[data-cy="query-tab-Settings"]').click();
|
||||
cy.wait("@editQuery");
|
||||
cy.get('[data-cy="query-tab-settings"]').click();
|
||||
// cy.wait("@editQuery");
|
||||
cy.wait(200);
|
||||
cy.waitForAutoSave();
|
||||
|
||||
changeQueryToggles("run-on-app-load");
|
||||
cy.wait("@editQuery");
|
||||
// cy.wait("@editQuery");
|
||||
cy.waitForAutoSave();
|
||||
cy.reload();
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, "alert from runpy");
|
||||
|
||||
cy.get('[data-cy="query-tab-Settings"]').click();
|
||||
cy.get('[data-cy="query-tab-settings"]').click();
|
||||
changeQueryToggles("confirmation-before-run");
|
||||
cy.wait("@editQuery");
|
||||
// cy.wait("@editQuery");
|
||||
cy.wait(200);
|
||||
cy.waitForAutoSave();
|
||||
cy.reload();
|
||||
|
|
@ -297,13 +297,13 @@ actions.unsetPageVariable('pageVar')`
|
|||
cy.get('[data-cy="modal-confirm-button"]').realClick();
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, "alert from runpy");
|
||||
|
||||
cy.get('[data-cy="query-tab-Settings"]').click();
|
||||
cy.get('[data-cy="query-tab-settings"]').click();
|
||||
changeQueryToggles("notification-on-success");
|
||||
cy.get('[data-cy="success-message-input-field"]').clearAndTypeOnCodeMirror(
|
||||
"Success alert"
|
||||
);
|
||||
cy.forceClickOnCanvas();
|
||||
cy.wait("@editQuery");
|
||||
// cy.wait("@editQuery");
|
||||
cy.wait(200);
|
||||
cy.waitForAutoSave();
|
||||
cy.reload();
|
||||
|
|
@ -26,7 +26,6 @@ describe("Data source amazon athena", () => {
|
|||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on amazon athena connection form", () => {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ describe("Data source amazon ses", () => {
|
|||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on amazonses connection form", () => {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ describe("Data source AppWrite", () => {
|
|||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on appwrite connection form", () => {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ describe("Data source AWS Lambda", () => {
|
|||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on AWS Lambda connection form", () => {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ describe("Data source AWS Textract", () => {
|
|||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on AWS Textract connection form", () => {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ data.customText = fake.randomSentence;
|
|||
describe("Data source Azure Blob Storage", () => {
|
||||
beforeEach(() => {
|
||||
cy.appUILogin();
|
||||
cy.intercept("GET", "/api/v2/data_sources");
|
||||
cy.defaultWorkspaceLogin();
|
||||
data.dataSourceName = fake.lastName
|
||||
.toLowerCase()
|
||||
.replaceAll("[^A-Za-z]", "");
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ describe("Data source baserow", () => {
|
|||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on baserow connection form", () => {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ describe("Data source BigQuery", () => {
|
|||
beforeEach(() => {
|
||||
cy.appUILogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("GET", "/api/v2/data_sources");
|
||||
data.dataSourceName = fake.lastName
|
||||
.toLowerCase()
|
||||
.replaceAll("[^A-Za-z]", "");
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { postgreSqlSelector } from "Selectors/postgreSql";
|
|||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { restAPISelector } from "Selectors/restAPI";
|
||||
import { restAPIText } from "Texts/restAPI";
|
||||
import { fillDataSourceTextField } from "Support/utils/postgreSql";
|
||||
import { createAndRunRestAPIQuery } from "Support/utils/restAPI";
|
||||
|
||||
const data = {};
|
||||
const authenticationDropdownSelector =
|
||||
|
|
@ -19,8 +19,8 @@ const clientAuthenticationDropdown =
|
|||
|
||||
describe("Data source Rest API", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("GET", "/api/v2/data_sources");
|
||||
data.dataSourceName = fake.lastName
|
||||
.toLowerCase()
|
||||
.replaceAll("[^A-Za-z]", "");
|
||||
|
|
@ -331,7 +331,8 @@ describe("Data source Rest API", () => {
|
|||
cy.verifyToastMessage(commonSelectors.toastMessage, "Data Source Saved");
|
||||
deleteDatasource(`cypress-${data.dataSourceName}-restapi`);
|
||||
});
|
||||
it("Should verify connection for Rest API", () => {
|
||||
it("Should verify basic connection for Rest API", () => {
|
||||
const storedId = Cypress.env("storedId");
|
||||
cy.apiCreateGDS(
|
||||
`${Cypress.env("server_host")}/api/data-sources`,
|
||||
`cypress-${data.dataSourceName}-restapi`,
|
||||
|
|
@ -366,18 +367,89 @@ describe("Data source Rest API", () => {
|
|||
]
|
||||
);
|
||||
cy.reload();
|
||||
// cy.apiCreateApp(`${fake.companyName}-restAPI-App`);
|
||||
// cy.apiAddQueryToApp(
|
||||
// "restapi1",
|
||||
// {
|
||||
// method: "get",
|
||||
// url: "",
|
||||
// url_params: [["", ""]],
|
||||
// headers: [["", ""]],
|
||||
// cookies: [["", ""]],
|
||||
// },
|
||||
// `cypress-${data.dataSourceName}-restapi`,
|
||||
// "restapi"
|
||||
// );
|
||||
|
||||
cy.apiCreateApp(`${fake.companyName}-restAPI-App`);
|
||||
cy.openApp();
|
||||
createAndRunRestAPIQuery(
|
||||
"get_restapi",
|
||||
`cypress-${data.dataSourceName}-restapi`,
|
||||
"GET",
|
||||
"/api/users"
|
||||
);
|
||||
createAndRunRestAPIQuery(
|
||||
"post_restapi",
|
||||
`cypress-${data.dataSourceName}-restapi`,
|
||||
"POST",
|
||||
"",
|
||||
[["Content-Type", "application/json"]],
|
||||
[],
|
||||
{
|
||||
price: 200,
|
||||
name: "Violin",
|
||||
},
|
||||
true,
|
||||
"/api/users"
|
||||
);
|
||||
cy.readFile("cypress/fixtures/restAPI/storedId.json").then(
|
||||
(postResponseID) => {
|
||||
const id1 = postResponseID.id;
|
||||
createAndRunRestAPIQuery(
|
||||
"put_restapi_id",
|
||||
`cypress-${data.dataSourceName}-restapi`,
|
||||
"PUT",
|
||||
"",
|
||||
[["Content-Type", "application/json"]],
|
||||
[],
|
||||
{
|
||||
price: 500,
|
||||
name: "Guitar",
|
||||
},
|
||||
true,
|
||||
`/api/users/${id1}`
|
||||
);
|
||||
}
|
||||
);
|
||||
cy.readFile("cypress/fixtures/restAPI/storedId.json").then(
|
||||
(putResponseID) => {
|
||||
const id2 = putResponseID.id;
|
||||
createAndRunRestAPIQuery(
|
||||
"patch_restapi_id",
|
||||
`cypress-${data.dataSourceName}-restapi`,
|
||||
"PATCH",
|
||||
"",
|
||||
[["Content-Type", "application/json"]],
|
||||
[],
|
||||
{ price: 999 },
|
||||
true,
|
||||
`/api/users/${id2}`
|
||||
);
|
||||
}
|
||||
);
|
||||
cy.readFile("cypress/fixtures/restAPI/storedId.json").then(
|
||||
(patchResponseID) => {
|
||||
const id3 = patchResponseID.id;
|
||||
createAndRunRestAPIQuery(
|
||||
"get_restapi_id",
|
||||
`cypress-${data.dataSourceName}-restapi`,
|
||||
"GET",
|
||||
"",
|
||||
[],
|
||||
[],
|
||||
true,
|
||||
`/api/users/${id3}`
|
||||
);
|
||||
|
||||
createAndRunRestAPIQuery(
|
||||
"delete_restapi_id",
|
||||
`cypress-${data.dataSourceName}-restapi`,
|
||||
"DELETE",
|
||||
"",
|
||||
[],
|
||||
[],
|
||||
true,
|
||||
`/api/users/${id3}`
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,219 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { commonSelectors } from "Selectors/common";
|
||||
import { importSelectors } from "Selectors/exportImport";
|
||||
import { commonText } from "Texts/common";
|
||||
|
||||
import { exportAppModalText } from "Texts/exportImport";
|
||||
import {
|
||||
clickOnExportButtonAndVerify,
|
||||
exportAllVersionsAndVerify,
|
||||
verifyElementsOfExportModal,
|
||||
} from "Support/utils/exportImport";
|
||||
import { selectAppCardOption, closeModal } from "Support/utils/common";
|
||||
|
||||
describe("App Export", () => {
|
||||
const TEST_DATA = {
|
||||
appFiles: {
|
||||
multiVersion: "cypress/fixtures/templates/three-versions.json",
|
||||
singleVersion: "cypress/fixtures/templates/one_version.json",
|
||||
},
|
||||
};
|
||||
|
||||
let data;
|
||||
|
||||
data = {
|
||||
workspaceName: fake.firstName,
|
||||
workspaceSlug: fake.firstName.toLowerCase().replace(/\s+/g, "-"),
|
||||
appName: `${fake.companyName}-IE-App`,
|
||||
appReName: `${fake.companyName}-${fake.companyName}-IE-App`,
|
||||
dsName: fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", ""),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
workspaceName: fake.firstName,
|
||||
workspaceSlug: fake.firstName.toLowerCase().replace(/\s+/g, "-"),
|
||||
appName: `${fake.companyName}-IE-App`,
|
||||
appReName: `${fake.companyName}-${fake.companyName}-IE-App`,
|
||||
dsName: fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", ""),
|
||||
};
|
||||
cy.exec("mkdir -p ./cypress/downloads/");
|
||||
cy.wait(3000);
|
||||
|
||||
cy.apiLogin();
|
||||
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
|
||||
cy.apiLogout();
|
||||
});
|
||||
|
||||
it("Verify the elements of export dialog box", () => {
|
||||
cy.window({ log: false }).then((win) => {
|
||||
win.localStorage.setItem("walkthroughCompleted", "true");
|
||||
});
|
||||
|
||||
cy.apiLogin();
|
||||
cy.visit(`${data.workspaceSlug}`);
|
||||
cy.get(importSelectors.importOptionInput)
|
||||
.eq(0)
|
||||
.selectFile(TEST_DATA.appFiles.multiVersion, {
|
||||
force: true,
|
||||
});
|
||||
cy.wait(1500);
|
||||
cy.clearAndType(commonSelectors.appNameInput, data.appName);
|
||||
cy.get(importSelectors.importAppButton).click();
|
||||
cy.wait(3000);
|
||||
cy.backToApps();
|
||||
|
||||
// Select the app card option to export the app
|
||||
selectAppCardOption(
|
||||
data.appName,
|
||||
commonSelectors.appCardOptions(commonText.exportAppOption)
|
||||
);
|
||||
|
||||
// Verify the elements of the export modal
|
||||
verifyElementsOfExportModal("v3", ["v2", "v1"], [true, false, false]);
|
||||
|
||||
// Close the modal
|
||||
closeModal(exportAppModalText.modalCloseButton);
|
||||
|
||||
// Ensure the modal title is no longer visible
|
||||
cy.get(
|
||||
commonSelectors.modalTitle(exportAppModalText.selectVersionTitle)
|
||||
).should("not.exist");
|
||||
|
||||
// Re-open the export modal and click the export button
|
||||
selectAppCardOption(
|
||||
data.appName,
|
||||
commonSelectors.appCardOptions(commonText.exportAppOption)
|
||||
);
|
||||
clickOnExportButtonAndVerify(exportAppModalText.exportAll, data.appName);
|
||||
|
||||
cy.exec("ls ./cypress/downloads/").then((result) => {
|
||||
const downloadedAppExportFileName = result.stdout.split("\n")[0];
|
||||
const filePath = `./cypress/downloads/${downloadedAppExportFileName}`;
|
||||
|
||||
// Ensure the file name contains the expected app export name
|
||||
expect(downloadedAppExportFileName).to.contain(
|
||||
data.appName.toLowerCase()
|
||||
);
|
||||
|
||||
// Read and validate the exported JSON file
|
||||
cy.readFile(filePath).then((appData) => {
|
||||
// Validate the app name
|
||||
const appNameFromFile = appData.app[0].definition.appV2.name;
|
||||
expect(appNameFromFile).to.equal(data.appName);
|
||||
|
||||
// Validate the schema for the student table in tooljetdb
|
||||
const tooljetDatabase = appData.tooljet_database.find(
|
||||
(db) => db.table_name === "student"
|
||||
);
|
||||
expect(tooljetDatabase).to.exist;
|
||||
expect(tooljetDatabase.schema).to.exist;
|
||||
|
||||
// Validate components and queries
|
||||
const components = appData.app[0].definition.appV2.components;
|
||||
|
||||
const text2Component = components.find(
|
||||
(component) => component.name === "text2"
|
||||
);
|
||||
expect(text2Component).to.exist;
|
||||
expect(text2Component.properties.text.value).to.equal(
|
||||
"{{constants.pageHeader}}"
|
||||
);
|
||||
|
||||
const textinput1 = components.find(
|
||||
(component) => component.name === "textinput1"
|
||||
);
|
||||
expect(textinput1).to.exist;
|
||||
expect(textinput1.properties.value.value).to.include("queries");
|
||||
|
||||
const textinput2 = components.find(
|
||||
(component) => component.name === "textinput2"
|
||||
);
|
||||
expect(textinput2).to.exist;
|
||||
expect(textinput2.properties.value.value).to.include("queries");
|
||||
|
||||
const textinput3 = components.find(
|
||||
(component) => component.name === "textinput3"
|
||||
);
|
||||
expect(textinput3).to.exist;
|
||||
expect(textinput3.properties.value.value).to.include("queries");
|
||||
|
||||
// Validate the data queries
|
||||
const dataQueries = appData.app[0].definition.appV2.dataQueries;
|
||||
|
||||
const postgresqlQuery = dataQueries.find(
|
||||
(query) => query.name === "postgresql1"
|
||||
);
|
||||
expect(postgresqlQuery).to.exist;
|
||||
expect(postgresqlQuery.options.query).to.include(
|
||||
"Select * from {{secrets.db_name}}"
|
||||
);
|
||||
|
||||
const restapiQuery = dataQueries.find(
|
||||
(query) => query.name === "restapi1"
|
||||
);
|
||||
expect(restapiQuery).to.exist;
|
||||
expect(restapiQuery.options.url).to.equal(
|
||||
"https://jsonplaceholder.typicode.com/users/1"
|
||||
);
|
||||
|
||||
const tooljetdbQuery = dataQueries.find(
|
||||
(query) => query.name === "tooljetdb1"
|
||||
);
|
||||
expect(tooljetdbQuery).to.exist;
|
||||
expect(tooljetdbQuery.options.operation).to.equal("list_rows");
|
||||
|
||||
// Ensure appVersions exists
|
||||
const appVersions = appData.app[0].definition.appV2.appVersions;
|
||||
expect(appVersions).to.exist;
|
||||
|
||||
// Map and verify app version names
|
||||
const versionNames = appVersions.map((version) => version.name);
|
||||
expect(versionNames).to.include.members(["v1", "v2", "v3"]);
|
||||
});
|
||||
});
|
||||
|
||||
cy.exec("cd ./cypress/downloads/ && rm -rf *");
|
||||
|
||||
selectAppCardOption(
|
||||
data.appName,
|
||||
commonSelectors.appCardOptions(commonText.exportAppOption)
|
||||
);
|
||||
cy.get(`[data-cy="v1-radio-button"]`).check();
|
||||
cy.get(
|
||||
commonSelectors.buttonSelector(exportAppModalText.exportSelectedVersion)
|
||||
).click();
|
||||
|
||||
cy.exec("ls ./cypress/downloads/").then((result) => {
|
||||
const downloadedAppExportFileName = result.stdout.split("\n")[0];
|
||||
const filePath = `./cypress/downloads/${downloadedAppExportFileName}`;
|
||||
|
||||
// Ensure the file name contains the expected app export name
|
||||
expect(downloadedAppExportFileName).to.contain(
|
||||
data.appName.toLowerCase()
|
||||
);
|
||||
|
||||
// Read and validate the exported JSON file
|
||||
cy.readFile(filePath).then((appData) => {
|
||||
// Validate the app name
|
||||
const appNameFromFile = appData.app[0].definition.appV2.name;
|
||||
expect(appNameFromFile).to.equal(data.appName);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it.skip("Verify 'Export app' functionality of an application inside app editor", () => {
|
||||
data.appName2 = `${fake.companyName}-App`;
|
||||
cy.apiCreateApp(data.appName2);
|
||||
cy.openApp(data.appName2);
|
||||
|
||||
cy.dragAndDropWidget("Text Input", 50, 50);
|
||||
|
||||
cy.get('[data-cy="left-sidebar-settings-button"]').click();
|
||||
cy.get('[data-cy="button-user-status-change"]').click();
|
||||
|
||||
verifyElementsOfExportModal("v1");
|
||||
|
||||
exportAllVersionsAndVerify(data.appName1, "v1");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,230 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
|
||||
import { appVersionSelectors, importSelectors } from "Selectors/exportImport";
|
||||
import { dashboardSelector } from "Selectors/dashboard";
|
||||
import { buttonText } from "Texts/button";
|
||||
|
||||
import { importText } from "Texts/exportImport";
|
||||
import { importAndVerifyApp } from "Support/utils/exportImport";
|
||||
import { switchVersionAndVerify } from "Support/utils/version";
|
||||
|
||||
describe("App Import Functionality", () => {
|
||||
const TEST_DATA = {
|
||||
toolJetImage: "cypress/fixtures/Image/tooljet.png",
|
||||
invalidApp: "cypress/fixtures/templates/invalid_app.json",
|
||||
invalidFile: "cypress/fixtures/templates/invalid_file.json",
|
||||
appFiles: {
|
||||
multiVersion: "cypress/fixtures/templates/three-versions.json",
|
||||
singleVersion: "cypress/fixtures/templates/one_version.json",
|
||||
},
|
||||
};
|
||||
|
||||
let data;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.viewport(1200, 1300);
|
||||
data = {
|
||||
workspaceName: fake.firstName,
|
||||
workspaceSlug: fake.firstName.toLowerCase().replace(/\s+/g, "-"),
|
||||
appName: `${fake.companyName}-IE-App`,
|
||||
appReName: `${fake.companyName}-${fake.companyName}-IE-App`,
|
||||
dsName: fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", ""),
|
||||
};
|
||||
|
||||
cy.apiLogin();
|
||||
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
|
||||
cy.apiLogout();
|
||||
});
|
||||
|
||||
it("should verify app import functionality", () => {
|
||||
cy.apiLogin();
|
||||
cy.visit(`${data.workspaceSlug}`);
|
||||
|
||||
// Test invalid file import
|
||||
cy.get(dashboardSelector.importAppButton).click();
|
||||
importAndVerifyApp(
|
||||
TEST_DATA.toolJetImage,
|
||||
importText.couldNotImportAppToastMessage
|
||||
);
|
||||
|
||||
cy.wait(500);
|
||||
cy.get(dashboardSelector.importAppButton).click();
|
||||
importAndVerifyApp(
|
||||
TEST_DATA.invalidApp,
|
||||
"Could not import: SyntaxError: Expected ',' or '}' after property value in JSON at position 246 (line 11 column 13)"
|
||||
);
|
||||
|
||||
cy.wait(500);
|
||||
|
||||
// Test valid app import
|
||||
cy.get(importSelectors.dropDownMenu).should("be.visible").click();
|
||||
cy.get(importSelectors.importOptionLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
importText.importOption
|
||||
);
|
||||
|
||||
cy.intercept("POST", "/api/v2/resources/import").as("importApp");
|
||||
cy.get(importSelectors.importOptionInput)
|
||||
.eq(0)
|
||||
.selectFile(TEST_DATA.appFiles.multiVersion, {
|
||||
force: true,
|
||||
});
|
||||
cy.wait(1500);
|
||||
|
||||
cy.get(importSelectors.importAppTitle).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Import app"
|
||||
);
|
||||
cy.get(commonSelectors.appNameLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"App name"
|
||||
);
|
||||
cy.get(commonSelectors.appNameInput)
|
||||
.should("be.visible")
|
||||
.and("have.value", "three-versions");
|
||||
cy.get(commonSelectors.appNameInfoLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"App name must be unique and max 50 characters"
|
||||
);
|
||||
cy.get(commonSelectors.cancelButton)
|
||||
.should("be.visible")
|
||||
.and("have.text", "Cancel");
|
||||
cy.get(commonSelectors.importAppButton).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Import app"
|
||||
);
|
||||
|
||||
cy.get(importSelectors.importAppButton).click();
|
||||
cy.get(".go3958317564")
|
||||
.should("be.visible")
|
||||
.and("have.text", importText.appImportedToastMessage);
|
||||
|
||||
// Verify imported app
|
||||
cy.get(".driver-close-btn").click();
|
||||
cy.wait(500);
|
||||
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
|
||||
"contain.value",
|
||||
"three-versions"
|
||||
);
|
||||
|
||||
// Configure app
|
||||
cy.skipEditorPopover();
|
||||
cy.dragAndDropWidget(buttonText.defaultWidgetText);
|
||||
cy.get(appVersionSelectors.appVersionLabel).should("be.visible");
|
||||
cy.get(commonWidgetSelector.draggableWidget("button1")).should(
|
||||
"be.visible"
|
||||
);
|
||||
|
||||
cy.renameApp(data.appName);
|
||||
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
|
||||
"contain.value",
|
||||
data.appName
|
||||
);
|
||||
cy.waitForAutoSave();
|
||||
|
||||
// Verify initial widget states
|
||||
|
||||
verifyCommonData({
|
||||
text2: "",
|
||||
textInput1: "",
|
||||
textInput2: "Leanne Graham",
|
||||
});
|
||||
|
||||
// cy.get(
|
||||
// commonWidgetSelector.draggableWidget("textInput3")
|
||||
// ).verifyVisibleElement("have.value", "");
|
||||
|
||||
// Setup database and data sources
|
||||
cy.visit(`${data.workspaceSlug}/database`);
|
||||
cy.get('[data-cy="student-table"]').verifyVisibleElement(
|
||||
"have.text",
|
||||
"student"
|
||||
);
|
||||
|
||||
// cy.apiAddDataToTable("student", {
|
||||
// name: "Paramu",
|
||||
// country: "India",
|
||||
// state: "Kerala",
|
||||
// });
|
||||
|
||||
cy.visit(`${data.workspaceSlug}/data-sources`);
|
||||
cy.get('[data-cy="postgresql-button"]').should("be.visible");
|
||||
cy.apiUpdateDataSource("postgresql", "production", {
|
||||
options: [
|
||||
{
|
||||
key: "password",
|
||||
value: `${Cypress.env("pg_password")}`,
|
||||
encrypted: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
cy.apiCreateWsConstant(
|
||||
"pageHeader",
|
||||
"Import and Export",
|
||||
["Global"],
|
||||
["production"]
|
||||
);
|
||||
cy.apiCreateWsConstant("db_name", "persons", ["Secret"], ["production"]);
|
||||
|
||||
// Verify app after setup
|
||||
cy.wait("@importApp").then((interception) => {
|
||||
const appId = interception.response.body.imports.app[0].id;
|
||||
cy.openApp(
|
||||
"",
|
||||
Cypress.env("workspaceId"),
|
||||
appId,
|
||||
commonWidgetSelector.draggableWidget("text2")
|
||||
);
|
||||
});
|
||||
|
||||
verifyCommonData({
|
||||
text2: "Import and Export",
|
||||
textInput1: "John",
|
||||
textInput2: "Leanne Graham",
|
||||
});
|
||||
// cy.get(
|
||||
// commonWidgetSelector.draggableWidget("textInput3")
|
||||
// ).verifyVisibleElement("have.value", "India");
|
||||
|
||||
switchVersionAndVerify("v3", "v1");
|
||||
|
||||
verifyCommonData({
|
||||
text2: "Import and Export",
|
||||
textInput1: "John",
|
||||
textInput2: "Leanne Graham",
|
||||
});
|
||||
|
||||
cy.wait(1000);
|
||||
cy.backToApps();
|
||||
|
||||
// Test single version import
|
||||
cy.get(importSelectors.dropDownMenu).click();
|
||||
importAndVerifyApp(TEST_DATA.appFiles.singleVersion);
|
||||
|
||||
// Verify final state
|
||||
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
|
||||
"contain.value",
|
||||
"one_version"
|
||||
);
|
||||
|
||||
verifyCommonData({
|
||||
text2: "Import and Export",
|
||||
textInput1: "John",
|
||||
textInput2: "Leanne Graham",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const verifyCommonData = (values) => {
|
||||
cy.get(commonWidgetSelector.draggableWidget("text2")).verifyVisibleElement(
|
||||
"have.text",
|
||||
values.text2
|
||||
);
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget("textInput1")
|
||||
).verifyVisibleElement("have.value", values.textInput1);
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget("textInput2")
|
||||
).verifyVisibleElement("have.value", values.textInput2);
|
||||
};
|
||||
|
|
@ -1,419 +0,0 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
|
||||
import { appVersionSelectors, importSelectors } from "Selectors/exportImport";
|
||||
import { commonText } from "Texts/common";
|
||||
import { dashboardSelector } from "Selectors/dashboard";
|
||||
import { buttonText } from "Texts/button";
|
||||
|
||||
import { exportAppModalText, importText } from "Texts/exportImport";
|
||||
import {
|
||||
clickOnExportButtonAndVerify,
|
||||
exportAllVersionsAndVerify,
|
||||
verifyElementsOfExportModal,
|
||||
importAndVerifyApp,
|
||||
} from "Support/utils/exportImport";
|
||||
import { selectAppCardOption, closeModal } from "Support/utils/common";
|
||||
import { switchVersionAndVerify } from "Support/utils/version";
|
||||
|
||||
describe("App Import Functionality", () => {
|
||||
const TEST_DATA = {
|
||||
toolJetImage: "cypress/fixtures/Image/tooljet.png",
|
||||
invalidApp: "cypress/fixtures/templates/invalid_app.json",
|
||||
invalidFile: "cypress/fixtures/templates/invalid_file.json",
|
||||
appFiles: {
|
||||
multiVersion: "cypress/fixtures/templates/three-versions.json",
|
||||
singleVersion: "cypress/fixtures/templates/one_version.json",
|
||||
},
|
||||
};
|
||||
|
||||
let data;
|
||||
|
||||
const initializeData = () => {
|
||||
const firstName = fake.firstName;
|
||||
return {
|
||||
workspaceName: firstName,
|
||||
workspaceSlug: firstName.toLowerCase().replace(/\s+/g, "-"),
|
||||
appName: `${fake.companyName}-IE-App`,
|
||||
appReName: `${fake.companyName}-${fake.companyName}-IE-App`,
|
||||
dsName: fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", ""),
|
||||
};
|
||||
};
|
||||
|
||||
data = initializeData();
|
||||
|
||||
before(() => {
|
||||
cy.exec("mkdir -p ./cypress/downloads/");
|
||||
cy.wait(3000);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.viewport(1200, 1300);
|
||||
cy.apiLogin();
|
||||
});
|
||||
|
||||
it("should verify app import functionality", () => {
|
||||
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
|
||||
cy.apiLogout();
|
||||
cy.apiLogin();
|
||||
cy.visit(`${data.workspaceSlug}`);
|
||||
|
||||
// Test invalid file import
|
||||
cy.get(dashboardSelector.importAppButton).click();
|
||||
importAndVerifyApp(
|
||||
TEST_DATA.toolJetImage,
|
||||
importText.couldNotImportAppToastMessage
|
||||
);
|
||||
|
||||
cy.wait(500);
|
||||
cy.get(dashboardSelector.importAppButton).click();
|
||||
importAndVerifyApp(
|
||||
TEST_DATA.invalidApp,
|
||||
"Could not import: SyntaxError: Expected ',' or '}' after property value in JSON at position 246 (line 11 column 13)"
|
||||
);
|
||||
|
||||
cy.wait(500);
|
||||
cy.get(dashboardSelector.importAppButton).click();
|
||||
cy.get(importSelectors.importOptionInput)
|
||||
.eq(0)
|
||||
.selectFile(TEST_DATA.invalidFile, {
|
||||
force: true,
|
||||
});
|
||||
cy.get(importSelectors.importAppTitle).should("be.visible");
|
||||
cy.get(importSelectors.importAppButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
"tooljet_version must be a string"
|
||||
);
|
||||
cy.wait(500);
|
||||
|
||||
// Test valid app import
|
||||
cy.get(importSelectors.dropDownMenu).should("be.visible").click();
|
||||
cy.get(importSelectors.importOptionLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
importText.importOption
|
||||
);
|
||||
|
||||
cy.intercept("POST", "/api/v2/resources/import").as("importApp");
|
||||
cy.get(importSelectors.importOptionInput)
|
||||
.eq(0)
|
||||
.selectFile(TEST_DATA.appFiles.multiVersion, {
|
||||
force: true,
|
||||
});
|
||||
cy.wait(1500);
|
||||
|
||||
cy.get(importSelectors.importAppTitle).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Import app"
|
||||
);
|
||||
cy.get(commonSelectors.appNameLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"App name"
|
||||
);
|
||||
cy.get(commonSelectors.appNameInput)
|
||||
.should("be.visible")
|
||||
.and("have.value", "three-versions");
|
||||
cy.get(commonSelectors.appNameInfoLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"App name must be unique and max 50 characters"
|
||||
);
|
||||
cy.get(commonSelectors.cancelButton)
|
||||
.should("be.visible")
|
||||
.and("have.text", "Cancel");
|
||||
cy.get(commonSelectors.importAppButton).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Import app"
|
||||
);
|
||||
|
||||
cy.get(importSelectors.importAppButton).click();
|
||||
cy.get(".go3958317564")
|
||||
.should("be.visible")
|
||||
.and("have.text", importText.appImportedToastMessage);
|
||||
|
||||
// Verify imported app
|
||||
cy.get(".driver-close-btn").click();
|
||||
cy.wait(500);
|
||||
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
|
||||
"contain.value",
|
||||
"three-versions"
|
||||
);
|
||||
|
||||
// Configure app
|
||||
cy.skipEditorPopover();
|
||||
cy.dragAndDropWidget(buttonText.defaultWidgetText);
|
||||
cy.get(appVersionSelectors.appVersionLabel).should("be.visible");
|
||||
cy.get(commonWidgetSelector.draggableWidget("button1")).should(
|
||||
"be.visible"
|
||||
);
|
||||
|
||||
cy.renameApp(data.appName);
|
||||
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
|
||||
"contain.value",
|
||||
data.appName
|
||||
);
|
||||
cy.waitForAutoSave();
|
||||
|
||||
// Verify initial widget states
|
||||
|
||||
verifyCommonData({
|
||||
text2: "",
|
||||
textInput1: "",
|
||||
textInput2: "Leanne Graham",
|
||||
});
|
||||
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget("textInput3")
|
||||
).verifyVisibleElement("have.value", "");
|
||||
|
||||
// Setup database and data sources
|
||||
cy.visit(`${data.workspaceSlug}/database`);
|
||||
cy.get('[data-cy="student-table"]').verifyVisibleElement(
|
||||
"have.text",
|
||||
"student"
|
||||
);
|
||||
|
||||
cy.apiAddDataToTable("student", {
|
||||
name: "Paramu",
|
||||
country: "India",
|
||||
state: "Kerala",
|
||||
});
|
||||
|
||||
cy.visit(`${data.workspaceSlug}/data-sources`);
|
||||
cy.get('[data-cy="postgresql-button"]').should("be.visible");
|
||||
cy.apiUpdateDataSource("postgresql", "production", {
|
||||
options: [
|
||||
{
|
||||
key: "password",
|
||||
value: `${Cypress.env("pg_password")}`,
|
||||
encrypted: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
cy.apiCreateWsConstant(
|
||||
"pageHeader",
|
||||
"Import and Export",
|
||||
["Global"],
|
||||
["production"]
|
||||
);
|
||||
cy.apiCreateWsConstant("db_name", "persons", ["Secret"], ["production"]);
|
||||
|
||||
// Verify app after setup
|
||||
cy.wait("@importApp").then((interception) => {
|
||||
const appId = interception.response.body.imports.app[0].id;
|
||||
cy.openApp(
|
||||
"",
|
||||
Cypress.env("workspaceId"),
|
||||
appId,
|
||||
commonWidgetSelector.draggableWidget("text2")
|
||||
);
|
||||
});
|
||||
|
||||
verifyCommonData({
|
||||
text2: "Import and Export",
|
||||
textInput1: "John",
|
||||
textInput2: "Leanne Graham",
|
||||
});
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget("textInput3")
|
||||
).verifyVisibleElement("have.value", "India");
|
||||
|
||||
switchVersionAndVerify("v3", "v1");
|
||||
|
||||
verifyCommonData({
|
||||
text2: "Import and Export",
|
||||
textInput1: "John",
|
||||
textInput2: "Leanne Graham",
|
||||
});
|
||||
|
||||
cy.wait(1000);
|
||||
cy.backToApps();
|
||||
|
||||
// Test single version import
|
||||
cy.get(importSelectors.dropDownMenu).click();
|
||||
importAndVerifyApp(TEST_DATA.appFiles.singleVersion);
|
||||
|
||||
// Verify final state
|
||||
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
|
||||
"contain.value",
|
||||
"one_version"
|
||||
);
|
||||
|
||||
verifyCommonData({
|
||||
text2: "Import and Export",
|
||||
textInput1: "John",
|
||||
textInput2: "Leanne Graham",
|
||||
});
|
||||
});
|
||||
|
||||
it("Verify the elements of export dialog box", () => {
|
||||
cy.exec("cd ./cypress/downloads/ && rm -rf *");
|
||||
|
||||
cy.visit(`${data.workspaceSlug}`);
|
||||
|
||||
// Select the app card option to export the app
|
||||
selectAppCardOption(
|
||||
data.appName,
|
||||
commonSelectors.appCardOptions(commonText.exportAppOption)
|
||||
);
|
||||
|
||||
// Verify the elements of the export modal
|
||||
verifyElementsOfExportModal("v3", ["v2", "v1"], [true, false, false]);
|
||||
|
||||
// Close the modal
|
||||
closeModal(exportAppModalText.modalCloseButton);
|
||||
|
||||
// Ensure the modal title is no longer visible
|
||||
cy.get(
|
||||
commonSelectors.modalTitle(exportAppModalText.selectVersionTitle)
|
||||
).should("not.exist");
|
||||
|
||||
// Re-open the export modal and click the export button
|
||||
selectAppCardOption(
|
||||
data.appName,
|
||||
commonSelectors.appCardOptions(commonText.exportAppOption)
|
||||
);
|
||||
clickOnExportButtonAndVerify(exportAppModalText.exportAll, data.appName);
|
||||
|
||||
cy.exec("ls ./cypress/downloads/").then((result) => {
|
||||
const downloadedAppExportFileName = result.stdout.split("\n")[0];
|
||||
const filePath = `./cypress/downloads/${downloadedAppExportFileName}`;
|
||||
|
||||
// Ensure the file name contains the expected app export name
|
||||
expect(downloadedAppExportFileName).to.contain(
|
||||
data.appName.toLowerCase()
|
||||
);
|
||||
|
||||
// Read and validate the exported JSON file
|
||||
cy.readFile(filePath).then((appData) => {
|
||||
// Validate the app name
|
||||
const appNameFromFile = appData.app[0].definition.appV2.name;
|
||||
expect(appNameFromFile).to.equal(data.appName);
|
||||
|
||||
// Validate the schema for the student table in tooljetdb
|
||||
const tooljetDatabase = appData.tooljet_database.find(
|
||||
(db) => db.table_name === "student"
|
||||
);
|
||||
expect(tooljetDatabase).to.exist;
|
||||
expect(tooljetDatabase.schema).to.exist;
|
||||
|
||||
// Validate components and queries
|
||||
const components = appData.app[0].definition.appV2.components;
|
||||
|
||||
const text2Component = components.find(
|
||||
(component) => component.name === "text2"
|
||||
);
|
||||
expect(text2Component).to.exist;
|
||||
expect(text2Component.properties.text.value).to.equal(
|
||||
"{{constants.pageHeader}}"
|
||||
);
|
||||
|
||||
const textinput1 = components.find(
|
||||
(component) => component.name === "textinput1"
|
||||
);
|
||||
expect(textinput1).to.exist;
|
||||
expect(textinput1.properties.value.value).to.include("queries");
|
||||
|
||||
const textinput2 = components.find(
|
||||
(component) => component.name === "textinput2"
|
||||
);
|
||||
expect(textinput2).to.exist;
|
||||
expect(textinput2.properties.value.value).to.include("queries");
|
||||
|
||||
const textinput3 = components.find(
|
||||
(component) => component.name === "textinput3"
|
||||
);
|
||||
expect(textinput3).to.exist;
|
||||
expect(textinput3.properties.value.value).to.include("queries");
|
||||
|
||||
// Validate the data queries
|
||||
const dataQueries = appData.app[0].definition.appV2.dataQueries;
|
||||
|
||||
const postgresqlQuery = dataQueries.find(
|
||||
(query) => query.name === "postgresql1"
|
||||
);
|
||||
expect(postgresqlQuery).to.exist;
|
||||
expect(postgresqlQuery.options.query).to.include(
|
||||
"Select * from {{secrets.db_name}}"
|
||||
);
|
||||
|
||||
const restapiQuery = dataQueries.find(
|
||||
(query) => query.name === "restapi1"
|
||||
);
|
||||
expect(restapiQuery).to.exist;
|
||||
expect(restapiQuery.options.url).to.equal(
|
||||
"https://jsonplaceholder.typicode.com/users/1"
|
||||
);
|
||||
|
||||
const tooljetdbQuery = dataQueries.find(
|
||||
(query) => query.name === "tooljetdb1"
|
||||
);
|
||||
expect(tooljetdbQuery).to.exist;
|
||||
expect(tooljetdbQuery.options.operation).to.equal("list_rows");
|
||||
|
||||
// Ensure appVersions exists
|
||||
const appVersions = appData.app[0].definition.appV2.appVersions;
|
||||
expect(appVersions).to.exist;
|
||||
|
||||
// Map and verify app version names
|
||||
const versionNames = appVersions.map((version) => version.name);
|
||||
expect(versionNames).to.include.members(["v1", "v2", "v3"]);
|
||||
});
|
||||
});
|
||||
|
||||
cy.exec("cd ./cypress/downloads/ && rm -rf *");
|
||||
|
||||
selectAppCardOption(
|
||||
data.appName,
|
||||
commonSelectors.appCardOptions(commonText.exportAppOption)
|
||||
);
|
||||
cy.get(`[data-cy="v1-radio-button"]`).check();
|
||||
cy.get(
|
||||
commonSelectors.buttonSelector(exportAppModalText.exportSelectedVersion)
|
||||
).click();
|
||||
|
||||
cy.exec("ls ./cypress/downloads/").then((result) => {
|
||||
const downloadedAppExportFileName = result.stdout.split("\n")[0];
|
||||
const filePath = `./cypress/downloads/${downloadedAppExportFileName}`;
|
||||
|
||||
// Ensure the file name contains the expected app export name
|
||||
expect(downloadedAppExportFileName).to.contain(
|
||||
data.appName.toLowerCase()
|
||||
);
|
||||
|
||||
// Read and validate the exported JSON file
|
||||
cy.readFile(filePath).then((appData) => {
|
||||
// Validate the app name
|
||||
const appNameFromFile = appData.app[0].definition.appV2.name;
|
||||
expect(appNameFromFile).to.equal(data.appName);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it.skip("Verify 'Export app' functionality of an application inside app editor", () => {
|
||||
data.appName2 = `${fake.companyName}-App`;
|
||||
cy.apiCreateApp(data.appName2);
|
||||
cy.openApp(data.appName2);
|
||||
|
||||
cy.dragAndDropWidget("Text Input", 50, 50);
|
||||
|
||||
cy.get('[data-cy="left-sidebar-settings-button"]').click();
|
||||
cy.get('[data-cy="button-user-status-change"]').click();
|
||||
|
||||
verifyElementsOfExportModal("v1");
|
||||
|
||||
exportAllVersionsAndVerify(data.appName1, "v1");
|
||||
});
|
||||
});
|
||||
|
||||
const verifyCommonData = (values) => {
|
||||
cy.get(commonWidgetSelector.draggableWidget("text2")).verifyVisibleElement(
|
||||
"have.text",
|
||||
values.text2
|
||||
);
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget("textInput1")
|
||||
).verifyVisibleElement("have.value", values.textInput1);
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget("textInput2")
|
||||
).verifyVisibleElement("have.value", values.textInput2);
|
||||
};
|
||||
|
|
@ -15,7 +15,6 @@ describe("App Slug", () => {
|
|||
beforeEach(() => {
|
||||
data.slug = `${fake.companyName.toLowerCase()}-app`;
|
||||
data.appName = `${fake.companyName} App`;
|
||||
cy.log(Cypress.env("workspaceId"));
|
||||
cy.defaultWorkspaceLogin();
|
||||
});
|
||||
|
||||
|
|
@ -25,133 +24,137 @@ describe("App Slug", () => {
|
|||
cy.apiCreateApp(data.appName);
|
||||
cy.wait(1000);
|
||||
cy.apiLogout();
|
||||
cy.log(Cypress.env("workspaceId"));
|
||||
|
||||
});
|
||||
|
||||
it("Verify app slug cases in global settings", () => {
|
||||
cy.apiLogin("dev@tooljet.io", "password").then(() => {
|
||||
const workspaceId = Cypress.env("workspaceId");
|
||||
const appId = Cypress.env("appId");
|
||||
cy.apiLogin();
|
||||
const workspaceId = Cypress.env("workspaceId");
|
||||
const appId = Cypress.env("appId");
|
||||
|
||||
cy.openApp("my-workspace");
|
||||
cy.get(commonSelectors.leftSideBarSettingsButton).click();
|
||||
cy.visit("/my-workspace");
|
||||
cy.wait(1000);
|
||||
|
||||
// Verify initial state
|
||||
cy.get(commonWidgetSelector.appSlugLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Unique app slug"
|
||||
);
|
||||
cy.get(commonWidgetSelector.appSlugInput).verifyVisibleElement(
|
||||
"have.value",
|
||||
Cypress.env("appId")
|
||||
);
|
||||
cy.get(commonWidgetSelector.appSlugInfoLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"URL-friendly 'slug' consists of lowercase letters, numbers, and hyphens"
|
||||
);
|
||||
|
||||
cy.get(commonWidgetSelector.appLinkLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"App link"
|
||||
);
|
||||
|
||||
cy.get(commonWidgetSelector.appLinkField).verifyVisibleElement(
|
||||
"have.text",
|
||||
`${host}/${workspaceId}/apps/${appId}`
|
||||
);
|
||||
|
||||
// Validate all error cases
|
||||
verifySlugValidations(commonWidgetSelector.appSlugInput);
|
||||
|
||||
// Verify successful slug update
|
||||
cy.clearAndType(commonWidgetSelector.appSlugInput, data.slug);
|
||||
verifySuccessfulSlugUpdate(workspaceId, data.slug);
|
||||
|
||||
// Verify persistence
|
||||
cy.get('[data-cy="left-sidebar-debugger-button"]').click();
|
||||
cy.get(commonSelectors.leftSideBarSettingsButton).click();
|
||||
cy.get(commonWidgetSelector.appSlugInput).should("have.value", data.slug);
|
||||
|
||||
// Release and verify URLs
|
||||
releaseApp();
|
||||
verifyURLs(workspaceId, data.slug, false);
|
||||
|
||||
// Verify duplicate slug validation
|
||||
cy.visit("/my-workspace");
|
||||
cy.apiCreateApp(data.slug);
|
||||
cy.openApp("my-workspace");
|
||||
cy.get(commonSelectors.leftSideBarSettingsButton).click();
|
||||
cy.get(commonWidgetSelector.appSlugInput).clear();
|
||||
cy.clearAndType(commonWidgetSelector.appSlugInput, data.slug);
|
||||
cy.get(commonWidgetSelector.appSlugErrorLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"This app slug is already taken."
|
||||
);
|
||||
cy.window({ log: false }).then((win) => {
|
||||
win.localStorage.setItem("walkthroughCompleted", "true");
|
||||
});
|
||||
cy.visit(`/${Cypress.env("workspaceId")}/apps/${Cypress.env("appId")}/`);
|
||||
cy.wait(1000);
|
||||
|
||||
cy.get(commonSelectors.leftSideBarSettingsButton).click();
|
||||
|
||||
// Verify initial state
|
||||
cy.get(commonWidgetSelector.appSlugLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Unique app slug"
|
||||
);
|
||||
cy.get(commonWidgetSelector.appSlugInput).verifyVisibleElement(
|
||||
"have.value",
|
||||
Cypress.env("appId")
|
||||
);
|
||||
cy.get(commonWidgetSelector.appSlugInfoLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"URL-friendly 'slug' consists of lowercase letters, numbers, and hyphens"
|
||||
);
|
||||
|
||||
cy.get(commonWidgetSelector.appLinkLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"App link"
|
||||
);
|
||||
|
||||
cy.get(commonWidgetSelector.appLinkField).verifyVisibleElement(
|
||||
"have.text",
|
||||
`${host}/${workspaceId}/apps/${appId}`
|
||||
);
|
||||
|
||||
// Validate all error cases
|
||||
verifySlugValidations(commonWidgetSelector.appSlugInput);
|
||||
|
||||
// Verify successful slug update
|
||||
cy.clearAndType(commonWidgetSelector.appSlugInput, data.slug);
|
||||
verifySuccessfulSlugUpdate(workspaceId, data.slug);
|
||||
|
||||
// Verify persistence
|
||||
cy.get('[data-cy="left-sidebar-debugger-button"]').click();
|
||||
cy.get(commonSelectors.leftSideBarSettingsButton).click();
|
||||
cy.get(commonWidgetSelector.appSlugInput).should("have.value", data.slug);
|
||||
|
||||
// Release and verify URLs
|
||||
releaseApp();
|
||||
verifyURLs(workspaceId, data.slug, false);
|
||||
|
||||
// Verify duplicate slug validation
|
||||
cy.visit("/my-workspace");
|
||||
cy.apiCreateApp(data.slug);
|
||||
cy.openApp("my-workspace");
|
||||
cy.get(commonSelectors.leftSideBarSettingsButton).click();
|
||||
cy.get(commonWidgetSelector.appSlugInput).clear();
|
||||
cy.clearAndType(commonWidgetSelector.appSlugInput, data.slug);
|
||||
cy.get(commonWidgetSelector.appSlugErrorLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"This app slug is already taken."
|
||||
);
|
||||
});
|
||||
|
||||
it("Verify app slug cases in share modal", () => {
|
||||
cy.apiLogin("dev@tooljet.io", "password").then(() => {
|
||||
const workspaceId = Cypress.env("workspaceId");
|
||||
cy.apiLogin();
|
||||
const workspaceId = Cypress.env("workspaceId");
|
||||
|
||||
cy.apiCreateApp(data.appName);
|
||||
cy.openApp("my-workspace");
|
||||
cy.apiCreateApp(data.appName);
|
||||
cy.openApp("my-workspace");
|
||||
|
||||
// Set up initial slug
|
||||
cy.get(commonSelectors.leftSideBarSettingsButton).click();
|
||||
cy.get(commonWidgetSelector.appSlugInput).clear();
|
||||
cy.clearAndType(commonWidgetSelector.appSlugInput, data.slug);
|
||||
// Set up initial slug
|
||||
cy.get(commonSelectors.leftSideBarSettingsButton).click();
|
||||
cy.get(commonWidgetSelector.appSlugInput).clear();
|
||||
cy.clearAndType(commonWidgetSelector.appSlugInput, data.slug);
|
||||
|
||||
releaseApp();
|
||||
releaseApp();
|
||||
|
||||
// Verify share modal
|
||||
cy.get(commonWidgetSelector.shareAppButton).click();
|
||||
cy.get(commonWidgetSelector.appLink).verifyVisibleElement(
|
||||
"have.text",
|
||||
`${host}/applications/`
|
||||
);
|
||||
cy.get(commonWidgetSelector.appNameSlugInput).should(
|
||||
"have.value",
|
||||
data.slug
|
||||
);
|
||||
// Verify share modal
|
||||
cy.get(commonWidgetSelector.shareAppButton).click();
|
||||
cy.get(commonWidgetSelector.appLink).verifyVisibleElement(
|
||||
"have.text",
|
||||
`${host}/applications/`
|
||||
);
|
||||
cy.get(commonWidgetSelector.appNameSlugInput).should(
|
||||
"have.value",
|
||||
data.slug
|
||||
);
|
||||
|
||||
// Validate all error cases in share modal
|
||||
verifySlugValidations(commonWidgetSelector.appNameSlugInput);
|
||||
// Validate all error cases in share modal
|
||||
verifySlugValidations(commonWidgetSelector.appNameSlugInput);
|
||||
|
||||
cy.wait(500);
|
||||
cy.clearAndType(commonWidgetSelector.appNameSlugInput, data.slug);
|
||||
cy.get('[data-cy="app-slug-info-label"]')
|
||||
.invoke("text")
|
||||
.then((text) => {
|
||||
expect(text.trim()).to.eq(
|
||||
"URL-friendly 'slug' consists of lowercase letters, numbers, and hyphens"
|
||||
);
|
||||
});
|
||||
cy.wait(500);
|
||||
cy.clearAndType(commonWidgetSelector.appNameSlugInput, data.slug);
|
||||
cy.get('[data-cy="app-slug-info-label"]')
|
||||
.invoke("text")
|
||||
.then((text) => {
|
||||
expect(text.trim()).to.eq(
|
||||
"URL-friendly 'slug' consists of lowercase letters, numbers, and hyphens"
|
||||
);
|
||||
});
|
||||
|
||||
// Verify successful slug update in share modal
|
||||
data.slug = `${fake.companyName.toLowerCase()}-app`;
|
||||
cy.clearAndType(commonWidgetSelector.appNameSlugInput, data.slug);
|
||||
cy.get('[data-cy="app-slug-accepted-label"]').verifyVisibleElement(
|
||||
"have.text",
|
||||
"Slug accepted!"
|
||||
);
|
||||
// Verify successful slug update in share modal
|
||||
data.slug = `${fake.companyName.toLowerCase()}-app`;
|
||||
cy.clearAndType(commonWidgetSelector.appNameSlugInput, data.slug);
|
||||
cy.get('[data-cy="app-slug-accepted-label"]').verifyVisibleElement(
|
||||
"have.text",
|
||||
"Slug accepted!"
|
||||
);
|
||||
|
||||
// Close modal and verify URLs
|
||||
cy.get(commonWidgetSelector.modalCloseButton).click();
|
||||
verifyURLs(workspaceId, data.slug, true);
|
||||
// Close modal and verify URLs
|
||||
cy.get(commonWidgetSelector.modalCloseButton).click();
|
||||
verifyURLs(workspaceId, data.slug, true);
|
||||
|
||||
// Verify duplicate slug validation in share modal
|
||||
cy.visit("/my-workspace");
|
||||
cy.apiCreateApp(data.slug);
|
||||
cy.openApp("my-workspace");
|
||||
releaseApp();
|
||||
cy.get(commonWidgetSelector.shareAppButton).click();
|
||||
cy.clearAndType(commonWidgetSelector.appNameSlugInput, data.slug);
|
||||
cy.get(commonWidgetSelector.appSlugErrorLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"This app slug is already taken."
|
||||
);
|
||||
});
|
||||
// Verify duplicate slug validation in share modal
|
||||
cy.visit("/my-workspace");
|
||||
cy.apiCreateApp(data.slug);
|
||||
cy.openApp("my-workspace");
|
||||
releaseApp();
|
||||
cy.get(commonWidgetSelector.shareAppButton).click();
|
||||
cy.clearAndType(commonWidgetSelector.appNameSlugInput, data.slug);
|
||||
cy.get(commonWidgetSelector.appSlugErrorLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
"This app slug is already taken."
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -20,20 +20,20 @@ import {
|
|||
describe("Private and Public apps", {
|
||||
retries: { runMode: 2 },
|
||||
}, () => {
|
||||
const data = {};
|
||||
let data;
|
||||
|
||||
beforeEach(() => {
|
||||
data.appName = `${fake.companyName} P P App`;
|
||||
data.slug = data.appName.toLowerCase().replace(/\s+/g, "-");
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase();
|
||||
data.workspaceName = fake.firstName;
|
||||
data.workspaceSlug = fake.firstName.toLowerCase().replace(/\s+/g, "-");
|
||||
data = {
|
||||
appName: `${fake.companyName} P P App`,
|
||||
slug: `${fake.companyName} P P App`.toLowerCase().replace(/\s+/g, "-"),
|
||||
firstName: fake.firstName,
|
||||
email: fake.email.toLowerCase(),
|
||||
workspaceName: fake.firstName,
|
||||
workspaceSlug: fake.firstName.toLowerCase().replace(/\s+/g, "-"),
|
||||
}
|
||||
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.skipWalkthrough();
|
||||
cy.log(data.appName, "text1")
|
||||
|
||||
});
|
||||
|
||||
it("Verify private and public app share functionality", () => {
|
||||
|
|
@ -85,9 +85,9 @@ describe("Private and Public apps", {
|
|||
});
|
||||
cy.get(onboardingSelectors.signInButton, { timeout: 20000 }).should("be.visible");
|
||||
cy.wait(2000);
|
||||
cy.loginWithCredentials("dev@tooljet.io", "password");
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
cy.appUILogin();
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
|
||||
|
||||
// Test public access
|
||||
cy.get(commonSelectors.viewerPageLogo).click();
|
||||
|
|
@ -106,8 +106,8 @@ describe("Private and Public apps", {
|
|||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -123,30 +123,30 @@ describe("Private and Public apps", {
|
|||
});
|
||||
|
||||
cy.wait(2000);
|
||||
cy.loginWithCredentials(data.email, "password");
|
||||
cy.appUILogin(data.email, "password");
|
||||
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible", { timeout: 20000 });
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
|
||||
// Test with private app valid session
|
||||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
|
||||
|
||||
cy.get(commonSelectors.viewerPageLogo).click();
|
||||
|
||||
// Test public access
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.wait(1000);
|
||||
cy.apiMakeAppPublic();
|
||||
logout();
|
||||
|
||||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
|
||||
|
||||
|
||||
// Test with public app with valid session
|
||||
|
|
@ -154,8 +154,8 @@ describe("Private and Public apps", {
|
|||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -180,8 +180,8 @@ describe("Private and Public apps", {
|
|||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
|
||||
|
||||
|
||||
// Verify public app with valid session
|
||||
|
|
@ -189,8 +189,8 @@ describe("Private and Public apps", {
|
|||
cy.visitSlug({
|
||||
actualUrl: `${Cypress.config("baseUrl")}/applications/${data.slug}`,
|
||||
});
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -224,8 +224,8 @@ describe("Private and Public apps", {
|
|||
// Process invitation
|
||||
onboardUserFromAppLink(data.email, data.slug);
|
||||
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
|
||||
|
||||
cy.get('[data-cy="viewer-page-logo"]').click();
|
||||
logout();
|
||||
|
|
@ -269,8 +269,8 @@ describe("Private and Public apps", {
|
|||
});
|
||||
|
||||
onboardUserFromAppLink(data.email, data.slug, data.workspaceName, false);
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
cy.get('.text-widget-section > div').should("be.visible");
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible");
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ describe("App Version", () => {
|
|||
cy.wait(3000);
|
||||
|
||||
// cy.reload();
|
||||
// cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible", { timeout: 10000 });
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).should("be.visible", { timeout: 10000 });
|
||||
|
||||
// Preview and release verification
|
||||
cy.openInCurrentTab(commonWidgetSelector.previewButton);
|
||||
|
|
@ -46,7 +46,7 @@ describe("Datasource Manager", () => {
|
|||
data.dsName1 = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.dsName2 = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
const allDataSources = host.includes("8082") ? "All data sources (42)" : "All data sources (44)";
|
||||
const allDataSources = host.includes("8082") ? "All data sources (43)" : "All data sources (45)";
|
||||
const allDatabase = host.includes("8082") ? "Databases (18)" : "Databases (20)";
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
|
|
@ -214,7 +214,7 @@ describe("Datasource Manager", () => {
|
|||
|
||||
cy.get(commonWidgetSelector.sidebarinspector).click();
|
||||
cy.get(dataSourceSelector.queryCreateAndRunButton).click();
|
||||
verifyValueOnInspector("table_preview", "7 items ");
|
||||
verifyValueOnInspector("table_preview", "10 items ");
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
|
||||
cy.get(".p-2 > .tj-base-btn")
|
||||
|
|
@ -275,7 +275,7 @@ describe("Datasource Manager", () => {
|
|||
pinInspector();
|
||||
|
||||
cy.get(dataSourceSelector.queryCreateAndRunButton).click();
|
||||
verifyValueOnInspector("table_preview", "7 items ");
|
||||
verifyValueOnInspector("table_preview", "10 items ");
|
||||
|
||||
//scope changing is pending
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,10 +18,17 @@ import { roleBasedOnboarding } from "Support/utils/onboarding";
|
|||
const data = {};
|
||||
data.groupName = fake.firstName.replaceAll("[^A-Za-z]", "");
|
||||
data.appName = `${fake.companyName}-App`;
|
||||
const workspaceName = fake.firstName;
|
||||
const workspaceSlug = fake.firstName.toLowerCase().replace(/[^A-Za-z]/g, "");
|
||||
|
||||
describe("Groups duplication", () => {
|
||||
beforeEach(() => {
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.apiCreateWorkspace(workspaceName, workspaceSlug);
|
||||
cy.visit(`${workspaceSlug}`);
|
||||
cy.apiLogout();
|
||||
cy.apiLogin();
|
||||
cy.visit(`${workspaceSlug}`);
|
||||
groupPermission(
|
||||
[
|
||||
"appsCreateCheck",
|
||||
|
|
@ -32,15 +39,18 @@ describe("Groups duplication", () => {
|
|||
"Admin"
|
||||
);
|
||||
cy.apiCreateApp(data.appName);
|
||||
|
||||
});
|
||||
|
||||
it("Should verify the group duplication feature", () => {
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
cy.visit(`${workspaceSlug}`);
|
||||
roleBasedOnboarding(data.firstName, data.email, "builder");
|
||||
cy.apiLogout();
|
||||
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.apiLogin();
|
||||
cy.visit(`${workspaceSlug}`);
|
||||
navigateToManageGroups();
|
||||
verifyGroupCardOptions("Admin");
|
||||
cy.wait(3000);
|
||||
|
|
@ -105,15 +115,19 @@ describe("Groups duplication", () => {
|
|||
cy.apiLogout();
|
||||
|
||||
cy.apiLogin(data.email, "password");
|
||||
cy.visit("/my-workspace");
|
||||
cy.visit(`${workspaceSlug}`);
|
||||
cy.wait(2000);
|
||||
cy.get(commonSelectors.appCreateButton).should("be.visible");
|
||||
cy.get(commonSelectors.createNewFolderButton).should("be.visible");
|
||||
cy.wait(2000);
|
||||
cy.reload();
|
||||
viewAppCardOptions(data.appName);
|
||||
cy.contains("Delete app").should("exist");
|
||||
cy.get(commonSelectors.workspaceConstantsIcon).should("be.visible");
|
||||
cy.apiLogout();
|
||||
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.apiLogin();
|
||||
cy.visit(`${workspaceSlug}`);
|
||||
navigateToManageGroups();
|
||||
OpenGroupCardOption(`${data.groupName}_copy`);
|
||||
cy.get(groupsSelector.deleteGroupOption).click();
|
||||
|
|
@ -121,7 +135,7 @@ describe("Groups duplication", () => {
|
|||
cy.apiLogout();
|
||||
|
||||
cy.apiLogin(data.email, "password");
|
||||
cy.visit("/my-workspace");
|
||||
cy.visit(`${workspaceSlug}`);
|
||||
cy.get(commonSelectors.appCreateButton).should("not.exist");
|
||||
cy.get(commonSelectors.createNewFolderButton).should("not.exist");
|
||||
cy.get(commonSelectors.workspaceConstantsIcon).should("not.exist");
|
||||
|
|
|
|||
|
|
@ -124,7 +124,8 @@ describe("Workspace constants", () => {
|
|||
|
||||
//verify global constant is resolved in static query url
|
||||
cy.get('[data-cy="list-query-restapistaticg"]').click();
|
||||
cy.get('.rest-api-methods-select-element-container .codehinter-container').click();
|
||||
cy.get('.rest-api-methods-select-element-container .codehinter-container').eq(0).click();
|
||||
cy.wait(500)
|
||||
cy.get('.text-secondary').should('have.text', Cypress.env("constants_host"));
|
||||
|
||||
//Verify global constant is resolved in static query preview
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ describe("user invite flow cases", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it.skip("Should verify the user onboarding with groups", () => {
|
||||
it("Should verify the user onboarding with groups", () => {
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.groupName1 = fake.firstName.replaceAll("[^A-Za-z]", "");
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ describe("inviteflow edge cases", () => {
|
|||
cy.verifyToastMessage(commonSelectors.toastMessage, usersText.inviteToast);
|
||||
logout();
|
||||
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.apiLogin();
|
||||
cy.visit(workspaceName);
|
||||
navigateToManageUsers();
|
||||
searchUser(data.email);
|
||||
cy.contains("td", data.email)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { importText } from "Texts/exportImport";
|
|||
|
||||
describe("App creation", () => {
|
||||
const data = {};
|
||||
const appFile = "cypress/fixtures/templates/test-app.json";
|
||||
const appFile = "cypress/fixtures/templates/one_version.json";
|
||||
|
||||
beforeEach(() => {
|
||||
cy.defaultWorkspaceLogin();
|
||||
|
|
@ -200,7 +200,7 @@ describe("App creation", () => {
|
|||
force: true,
|
||||
});
|
||||
|
||||
cy.get(commonSelectors.importAppTitle).verifyVisibleElement(
|
||||
cy.get(importSelectors.importAppTitle).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Import app"
|
||||
);
|
||||
|
|
@ -210,7 +210,7 @@ describe("App creation", () => {
|
|||
);
|
||||
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
|
||||
"have.value",
|
||||
"test-app"
|
||||
"one_version"
|
||||
);
|
||||
cy.get(commonSelectors.appNameInfoLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
|
|
@ -236,7 +236,7 @@ describe("App creation", () => {
|
|||
});
|
||||
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
|
||||
"have.value",
|
||||
"test-app"
|
||||
"one_version"
|
||||
);
|
||||
cy.clearAndType(commonSelectors.appNameInput, data.appName);
|
||||
cy.get(commonSelectors.cancelButton).click();
|
||||
|
|
@ -247,7 +247,7 @@ describe("App creation", () => {
|
|||
});
|
||||
cy.get(commonSelectors.appNameInput).verifyVisibleElement(
|
||||
"have.value",
|
||||
"test-app"
|
||||
"one_version"
|
||||
);
|
||||
cy.clearAndType(commonSelectors.appNameInput, data.appName);
|
||||
cy.get(commonSelectors.importAppButton).should("be.enabled").click();
|
||||
|
|
@ -2,7 +2,6 @@ import { fake } from "Fixtures/fake";
|
|||
import {
|
||||
createFolder,
|
||||
deleteFolder,
|
||||
deleteDownloadsFolder,
|
||||
navigateToAppEditor,
|
||||
viewAppCardOptions,
|
||||
verifyModal,
|
||||
|
|
@ -14,49 +13,38 @@ import {
|
|||
} from "Support/utils/common";
|
||||
import {
|
||||
modifyAndVerifyAppCardIcon,
|
||||
login,
|
||||
verifyAppDelete,
|
||||
} from "Support/utils/dashboard";
|
||||
import { profileSelector } from "Selectors/profile";
|
||||
import { profileText } from "Texts/profile";
|
||||
import { commonSelectors } from "Selectors/common";
|
||||
import { dashboardSelector } from "Selectors/dashboard";
|
||||
import { commonText } from "Texts/common";
|
||||
import { dashboardText } from "Texts/dashboard";
|
||||
import {
|
||||
navigateToManageUsers,
|
||||
logout,
|
||||
searchUser,
|
||||
navigateToManageGroups,
|
||||
} from "Support/utils/common";
|
||||
import { roleBasedOnboarding } from "Support/utils/onboarding";
|
||||
import { logout } from "Support/utils/common";
|
||||
|
||||
describe("dashboard", () => {
|
||||
const data = {};
|
||||
data.appName = `${fake.companyName}-App`;
|
||||
data.folderName = `${fake.companyName.toLowerCase()}-folder`;
|
||||
data.cloneAppName = `cloned-${data.appName}`;
|
||||
data.updatedFolderName = `new-${data.folderName}`;
|
||||
data.firstName = fake.firstName;
|
||||
data.email = fake.email.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.workspaceName = fake.firstName;
|
||||
data.workspaceSlug = fake.firstName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
let data = {};
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
appName: `${fake.companyName}-App`,
|
||||
folderName: `${fake.companyName.toLowerCase()}-folder`,
|
||||
cloneAppName: `cloned-${fake.companyName}-App`,
|
||||
updatedFolderName: `new-${fake.companyName.toLowerCase()}-folder`,
|
||||
workspaceName: fake.firstName,
|
||||
workspaceSlug: fake.firstName.toLowerCase().replaceAll("[^A-Za-z]", ""),
|
||||
};
|
||||
cy.intercept("GET", "/api/library_apps").as("appLibrary");
|
||||
cy.intercept("DELETE", "/api/folders/*").as("folderDeleted");
|
||||
cy.skipWalkthrough();
|
||||
|
||||
cy.apiLogin();
|
||||
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
|
||||
cy.apiLogout();
|
||||
cy.apiLogin();
|
||||
cy.visit(`${data.workspaceSlug}`);
|
||||
});
|
||||
|
||||
it("should verify the elements on empty dashboard", () => {
|
||||
cy.intercept("GET", "/api/apps?page=1&folder=&searchKey=&type=front-end", {
|
||||
fixture: "intercept/emptyDashboard.json",
|
||||
}).as("emptyDashboard");
|
||||
|
||||
cy.intercept("GET", "/api/folder-apps?searchKey=&type=front-end", {
|
||||
body: { folders: [] },
|
||||
}).as("folders");
|
||||
|
||||
cy.intercept("GET", "/api/metadata", {
|
||||
body: {
|
||||
installed_version: "2.9.2",
|
||||
|
|
@ -64,15 +52,10 @@ describe("dashboard", () => {
|
|||
},
|
||||
}).as("version");
|
||||
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.wait("@emptyDashboard");
|
||||
cy.wait("@folders");
|
||||
cy.wait("@version");
|
||||
|
||||
cy.get(commonSelectors.homePageLogo).should("be.visible");
|
||||
cy.get(commonSelectors.workspaceName).verifyVisibleElement(
|
||||
"have.text",
|
||||
"My workspace"
|
||||
data.workspaceName
|
||||
);
|
||||
cy.get(commonSelectors.workspaceName).click();
|
||||
// cy.get(commonSelectors.editRectangleIcon).should("be.visible");
|
||||
|
|
@ -188,12 +171,12 @@ describe("dashboard", () => {
|
|||
verifyTooltip(dashboardSelector.modeToggle, "Mode");
|
||||
});
|
||||
|
||||
it("Should verify app card elements and app card operations", () => {
|
||||
it.skip("Should verify app card elements and app card operations", () => {
|
||||
const customLayout = {
|
||||
desktop: { top: 100, left: 20 },
|
||||
mobile: { width: 8, height: 50 },
|
||||
};
|
||||
cy.apiLogin();
|
||||
|
||||
cy.apiCreateApp(data.appName);
|
||||
cy.openApp();
|
||||
cy.apiAddComponentToApp(data.appName, "text1", customLayout);
|
||||
|
|
@ -276,6 +259,7 @@ describe("dashboard", () => {
|
|||
|
||||
cancelModal(commonText.cancelButton);
|
||||
|
||||
cy.wait(3000);
|
||||
viewAppCardOptions(data.appName);
|
||||
cy.get(
|
||||
commonSelectors.appCardOptions(commonText.removeFromFolderOption)
|
||||
|
|
@ -296,6 +280,7 @@ describe("dashboard", () => {
|
|||
|
||||
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();
|
||||
|
|
@ -312,7 +297,10 @@ describe("dashboard", () => {
|
|||
|
||||
cy.get(commonSelectors.appCard(data.cloneAppName)).should("be.visible");
|
||||
|
||||
cy.wait(3000)
|
||||
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();
|
||||
|
|
@ -322,6 +310,7 @@ describe("dashboard", () => {
|
|||
expect(downloadedAppExportFileName).to.contain.string("app");
|
||||
});
|
||||
|
||||
cy.wait(3000);
|
||||
cy.reloadAppForTheElement(data.cloneAppName);
|
||||
viewAppCardOptions(data.cloneAppName);
|
||||
cy.get(commonSelectors.deleteAppOption).click();
|
||||
|
|
@ -337,6 +326,7 @@ describe("dashboard", () => {
|
|||
).verifyVisibleElement("have.text", commonText.modalYesButton);
|
||||
cancelModal(commonText.cancelButton);
|
||||
|
||||
cy.wait(3000);
|
||||
cy.reloadAppForTheElement(data.cloneAppName);
|
||||
viewAppCardOptions(data.cloneAppName);
|
||||
cy.get(commonSelectors.deleteAppOption).click();
|
||||
|
|
@ -362,9 +352,6 @@ describe("dashboard", () => {
|
|||
mobile: { width: 8, height: 50 },
|
||||
};
|
||||
|
||||
cy.skipWalkthrough();
|
||||
data.appName = `${fake.companyName}-App`;
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.createApp(data.appName);
|
||||
cy.apiAddComponentToApp(data.appName, "text1", customLayout);
|
||||
|
||||
|
|
@ -395,12 +382,8 @@ describe("dashboard", () => {
|
|||
mobile: { width: 8, height: 50 },
|
||||
};
|
||||
|
||||
data.appName = `${fake.companyName}-App`;
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.createApp(data.appName);
|
||||
|
||||
cy.apiAddComponentToApp(data.appName, "text1", customLayout);
|
||||
|
||||
cy.backToApps();
|
||||
|
||||
cy.get(commonSelectors.createNewFolderButton).click();
|
||||
|
|
@ -517,13 +500,4 @@ describe("dashboard", () => {
|
|||
verifyAppDelete(data.appName);
|
||||
logout();
|
||||
});
|
||||
|
||||
it("should verify the elements on empty dashboard for end user", () => {
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("GET", "/api/apps?page=1&folder=&searchKey=&type=front-end", {
|
||||
fixture: "intercept/emptyDashboard.json",
|
||||
}).as("emptyDashboard")
|
||||
roleBasedOnboarding(data.firstName, data.email, "end-user");
|
||||
cy.get(commonSelectors.dashboardAppCreateButton).should("be.disabled");
|
||||
});
|
||||
});
|
||||
3
cypress-tests/cypress/fixtures/restAPI/storedId.json
Normal file
3
cypress-tests/cypress/fixtures/restAPI/storedId.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"id": "bff6583db942c77249ba"
|
||||
}
|
||||
|
|
@ -2127,7 +2127,7 @@
|
|||
"encrypted": false
|
||||
},
|
||||
"host": {
|
||||
"value": "35.202.183.199",
|
||||
"value": "35.238.9.114",
|
||||
"encrypted": false
|
||||
},
|
||||
"port": {
|
||||
|
|
|
|||
|
|
@ -585,7 +585,7 @@
|
|||
"encrypted": false
|
||||
},
|
||||
"host": {
|
||||
"value": "35.202.183.199",
|
||||
"value": "35.238.9.114",
|
||||
"encrypted": false
|
||||
},
|
||||
"port": {
|
||||
|
|
|
|||
|
|
@ -1701,7 +1701,7 @@
|
|||
]
|
||||
},
|
||||
"list_rows": {},
|
||||
"runOnPageLoad": true
|
||||
"runOnPageLoad": false
|
||||
},
|
||||
"dataSourceId": "f4cf0089-aec2-4713-800e-3560e678220b",
|
||||
"appVersionId": "b74fcff1-8cf1-40f8-a13d-c2d2a0b1ebf1",
|
||||
|
|
@ -1862,7 +1862,7 @@
|
|||
"encrypted": false
|
||||
},
|
||||
"host": {
|
||||
"value": "35.202.183.199",
|
||||
"value": "35.238.9.114",
|
||||
"encrypted": false
|
||||
},
|
||||
"port": {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,10 @@ export const verifySuccessfulSlugUpdate = (workspaceId, slug) => {
|
|||
"have.text",
|
||||
"Slug accepted!"
|
||||
);
|
||||
cy.get(commonWidgetSelector.appLinkSucessLabel).verifyVisibleElement(
|
||||
|
||||
cy.wait(500);
|
||||
// cy.get(commonWidgetSelector.appLinkSucessLabel).should('be.visible');
|
||||
cy.get(commonWidgetSelector.appLinkSucessLabel).should(
|
||||
"have.text",
|
||||
"Link updated successfully!"
|
||||
);
|
||||
|
|
|
|||
|
|
@ -32,10 +32,10 @@ export const deleteComponentAndVerify = (widgetName) => {
|
|||
.last()
|
||||
.realClick();
|
||||
});
|
||||
cy.verifyToastMessage(
|
||||
`[class=go3958317564]`,
|
||||
"Component deleted! (Ctrl + Z to undo)"
|
||||
);
|
||||
// cy.verifyToastMessage(
|
||||
// `[class=go3958317564]`,
|
||||
// "Component deleted! (Ctrl + Z to undo)"
|
||||
// );
|
||||
cy.notVisible(commonWidgetSelector.draggableWidget(widgetName));
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,7 @@ export const navigateToProfile = () => {
|
|||
export const logout = () => {
|
||||
cy.get(commonSelectors.settingsIcon).click();
|
||||
cy.get(commonSelectors.logoutLink).click();
|
||||
cy.intercept("GET", "/api/metadata").as("publicConfig");
|
||||
cy.wait("@publicConfig");
|
||||
cy.wait(500);
|
||||
cy.wait(1000);
|
||||
};
|
||||
|
||||
export const navigateToManageUsers = () => {
|
||||
|
|
@ -183,10 +181,9 @@ export const manageUsersPagination = (email) => {
|
|||
|
||||
export const searchUser = (email) => {
|
||||
cy.clearAndType(commonSelectors.inputUserSearch, email);
|
||||
cy.wait(1000)
|
||||
cy.wait(1000);
|
||||
};
|
||||
|
||||
|
||||
export const selectAppCardOption = (appName, appCardOption) => {
|
||||
viewAppCardOptions(appName);
|
||||
cy.get(appCardOption).should("be.visible").click({ force: true });
|
||||
|
|
@ -221,7 +218,6 @@ export const pinInspector = () => {
|
|||
}
|
||||
});
|
||||
cy.hideTooltip();
|
||||
|
||||
};
|
||||
|
||||
export const navigateToworkspaceConstants = () => {
|
||||
|
|
@ -243,24 +239,3 @@ export const verifyTooltipDisabled = (selector, message) => {
|
|||
cy.get(".tooltip-inner").last().should("have.text", message);
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteAllGroupChips = () => {
|
||||
cy.get('body').then(($body) => {
|
||||
if ($body.find('[data-cy="group-chip"]').length > 0) {
|
||||
cy.get('[data-cy="group-chip"]').then(($groupChip) => {
|
||||
if ($groupChip.is(':visible')) {
|
||||
cy.get('[data-cy="group-chip"]').first().click();
|
||||
cy.get('[data-cy="delete-button"]').click();
|
||||
cy.get('[data-cy="yes-button"]').click();
|
||||
|
||||
cy.wait(2000);
|
||||
deleteAllGroupChips(); // Recursive call to delete next chip
|
||||
} else {
|
||||
cy.log("Group chip is present but not visible, skipping deletion");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cy.log("No group chips left to delete");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ export const verifyValue = (node, type, children, index = 0) => {
|
|||
};
|
||||
export const deleteComponentFromInspector = (node) => {
|
||||
cy.get('[data-cy="inspector-node-components"] > .node-key').click();
|
||||
cy.get(`[data-cy="inspector-node-${node}"] > .node-key`).realHover().parent().find('[style="height: 13px; width: 13px;"] > img').click();
|
||||
cy.get(`[data-cy="inspector-node-${node}"] > .node-key`).realHover().parent().find('[style="height: 13px; width: 13px;"] > img').last().click();
|
||||
};
|
||||
|
||||
export const verifyfunctions = (node, type, index = 0) => {
|
||||
|
|
|
|||
|
|
@ -646,7 +646,7 @@ export const createGroupAddAppAndUserToGroup = (groupName, email) => {
|
|||
|
||||
cy.request({
|
||||
method: "POST",
|
||||
url: `${Cypress.env("server_host")}/api/v2/group_permissions`,
|
||||
url: `${Cypress.env("server_host")}/api/v2/group-permissions`,
|
||||
headers: headers,
|
||||
body: {
|
||||
name: groupName,
|
||||
|
|
@ -658,14 +658,14 @@ export const createGroupAddAppAndUserToGroup = (groupName, email) => {
|
|||
|
||||
cy.request({
|
||||
method: "POST",
|
||||
url: `${Cypress.env("server_host")}/api/v2/group_permissions/granular-permissions`,
|
||||
url: `${Cypress.env("server_host")}/api/v2/group-permissions/${groupId}/granular-permissions`,
|
||||
headers: headers,
|
||||
body: {
|
||||
name: "Apps",
|
||||
type: "app",
|
||||
groupId: groupId,
|
||||
isAll: false,
|
||||
createAppsPermissionsObject: {
|
||||
createResourcePermissionObject: {
|
||||
canEdit: true,
|
||||
canView: false,
|
||||
hideFromDashboard: false,
|
||||
|
|
@ -676,19 +676,22 @@ export const createGroupAddAppAndUserToGroup = (groupName, email) => {
|
|||
],
|
||||
},
|
||||
},
|
||||
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(201);
|
||||
});
|
||||
|
||||
cy.wait(2000);
|
||||
cy.task("dbConnection", {
|
||||
dbconfig: Cypress.env("app_db"),
|
||||
sql: `select id from users where email='${email}';`,
|
||||
}).then((resp) => {
|
||||
const userId = resp.rows[0].id;
|
||||
cy.log(userId);
|
||||
|
||||
cy.request({
|
||||
method: "POST",
|
||||
url: `${Cypress.env("server_host")}/api/v2/group_permissions/group-user`,
|
||||
url: `${Cypress.env("server_host")}/api/v2/group-permissions/${groupId}/users`,
|
||||
headers: headers,
|
||||
body: {
|
||||
userIds: [userId],
|
||||
|
|
@ -720,7 +723,7 @@ export const OpenGroupCardOption = (groupName) => {
|
|||
export const duplicateMultipleGroups = (groupNames) => {
|
||||
groupNames.forEach((groupName) => {
|
||||
OpenGroupCardOption(groupName);
|
||||
cy.wait(3000);
|
||||
cy.wait(2000);
|
||||
cy.get(commonSelectors.duplicateOption).click(); // Click on the duplicate option
|
||||
cy.get(commonSelectors.confirmDuplicateButton).click(); // Confirm duplication if needed
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export const generalSettings = () => {
|
|||
|
||||
cy.get(ssoSelector.workspaceLoginPage.defaultSSO).click();
|
||||
cy.get(ssoSelector.defaultGoogle).verifyVisibleElement("have.text", "Google");
|
||||
cy.get(ssoSelector.defaultGithub).verifyVisibleElement("have.text", "Github");
|
||||
cy.get(ssoSelector.defaultGithub).verifyVisibleElement("have.text", "Git");
|
||||
|
||||
cy.clearAndType(ssoSelector.allowedDomainInput, ssoText.allowedDomain);
|
||||
cy.get(ssoSelector.saveButton).click();
|
||||
|
|
@ -416,7 +416,7 @@ export const resetDomain = () => {
|
|||
cy.request(
|
||||
{
|
||||
method: "PATCH",
|
||||
url: `${Cypress.env("server_host")}/api/organizations`,
|
||||
url: `${Cypress.env("server_host")}/api/login-configs/organization-general`,
|
||||
headers: {
|
||||
"Tj-Workspace-Id": Cypress.env("workspaceId"),
|
||||
Cookie: `tj_auth_token=${cookie.value}`,
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export const setHomePage = (pageName) => {
|
|||
|
||||
export const addNewPage = (pageName) => {
|
||||
cy.get(multipageSelector.addPageIcon).click();
|
||||
cy.get(".col-12 > .form-control").type(`{selectAll}{backspace}${pageName}`);
|
||||
cy.get('[role="button"] > div > .form-control').type(`{selectAll}{backspace}${pageName}`);
|
||||
cy.get(multipageSelector.addPageIcon).click();
|
||||
cy.get(`[data-cy="pages-name-${pageName.toLowerCase()}"]`).click();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ export const waitForQueryAction = (action) => {
|
|||
|
||||
export const chainQuery = (currentQuery, trigger) => {
|
||||
cy.get(`[data-cy="list-query-${currentQuery}"]`).click();
|
||||
cy.wait(1000);
|
||||
cy.get('[data-cy="query-tab-settings"]').click();
|
||||
selectEvent("Query Success", "Run Query");
|
||||
cy.get('[data-cy="query-selection-field"]')
|
||||
.click()
|
||||
|
|
@ -55,8 +57,16 @@ export const chainQuery = (currentQuery, trigger) => {
|
|||
};
|
||||
|
||||
export const addSuccessNotification = (notification) => {
|
||||
changeQueryToggles("notification-on-success");
|
||||
cy.get('[data-cy="success-message-input-field"]').clearAndTypeOnCodeMirror(
|
||||
notification
|
||||
);
|
||||
cy.get('[data-cy="query-tab-settings"]').click();
|
||||
cy.get('body').then(($body) => {
|
||||
if (!$body.find('[data-cy="success-message-input-field"]').is(':visible')) {
|
||||
changeQueryToggles("notification-on-success");
|
||||
// cy.get('[data-cy="success-message-input-field"]').then(($input) => {
|
||||
// cy.wrap($input).clearAndTypeOnCodeMirror(notification);
|
||||
// });
|
||||
}
|
||||
});
|
||||
cy.get('[data-cy="success-message-input-field"]').clearAndTypeOnCodeMirror(notification);
|
||||
cy.get('[data-cy="query-tab-setup"]').click();
|
||||
cy.wait(300);
|
||||
};
|
||||
|
|
|
|||
97
cypress-tests/cypress/support/utils/restAPI.js
Normal file
97
cypress-tests/cypress/support/utils/restAPI.js
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
export const createAndRunRestAPIQuery = (
|
||||
queryName,
|
||||
dsName,
|
||||
method = "GET",
|
||||
url = "",
|
||||
headersList = [],
|
||||
bodyList = [],
|
||||
jsonBody = null,
|
||||
run = true,
|
||||
urlSuffix = ""
|
||||
) => {
|
||||
cy.getCookie("tj_auth_token").then((cookie) => {
|
||||
const headers = {
|
||||
"Tj-Workspace-Id": Cypress.env("workspaceId"),
|
||||
Cookie: `tj_auth_token=${cookie.value}`,
|
||||
};
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url: `${Cypress.env("server_host")}/api/apps/${Cypress.env("appId")}`,
|
||||
headers,
|
||||
}).then((response) => {
|
||||
const editingVersionId = response.body.editing_version.id;
|
||||
const data_source_id = Cypress.env(`${dsName}-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({
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
@ -70,12 +70,13 @@ COPY --from=builder /app/frontend/build ./app/frontend/build
|
|||
# copy server build
|
||||
COPY --from=builder /app/server/package.json ./app/server/package.json
|
||||
COPY --from=builder /app/server/.version ./app/server/.version
|
||||
COPY --from=builder /app/server/entrypoint.sh ./app/server/entrypoint.sh
|
||||
COPY --from=builder /app/server/node_modules ./app/server/node_modules
|
||||
COPY --from=builder /app/server/templates ./app/server/templates
|
||||
COPY --from=builder /app/server/scripts ./app/server/scripts
|
||||
COPY --from=builder /app/server/dist ./app/server/dist
|
||||
|
||||
COPY ./docker/ce-entrypoint.sh ./app/server/entrypoint.sh
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# ENV defaults
|
||||
|
|
|
|||
|
|
@ -99,12 +99,13 @@ COPY --from=builder /app/frontend/build ./app/frontend/build
|
|||
COPY --from=builder /app/server/package.json ./app/server/package.json
|
||||
COPY --from=builder /app/server/.version ./app/server/.version
|
||||
COPY --from=builder /app/server/ee/keys ./app/server/ee/keys
|
||||
COPY --from=builder /app/server/entrypoint.sh ./app/server/entrypoint.sh
|
||||
COPY --from=builder /app/server/node_modules ./app/server/node_modules
|
||||
COPY --from=builder /app/server/templates ./app/server/templates
|
||||
COPY --from=builder /app/server/scripts ./app/server/scripts
|
||||
COPY --from=builder /app/server/dist ./app/server/dist
|
||||
|
||||
COPY ./docker/ee/ee-entrypoint.sh ./app/server/ee-entrypoint.sh
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# ENV defaults
|
||||
|
|
|
|||
2
frontend/assets/csv/sample_upload_ce.csv
Normal file
2
frontend/assets/csv/sample_upload_ce.csv
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
First Name,Last Name,Email,User Role,Group
|
||||
test,user,test@gmail.com,"Assign each user a role: Admin, Builder or End User. User role value should be exact same","For multiple groups separate using pipe (|) operator e.g. Groups1|Group2 or leave blank if no group assign"
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit dcd948d284b5f14a868480830e09b90496db8572
|
||||
Subproject commit 518f3334b12a83785fd37dd53b0245d72848211a
|
||||
|
|
@ -41,6 +41,8 @@ import {
|
|||
import { shallow } from 'zustand/shallow';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
import { checkIfToolJetCloud } from '@/_helpers/utils';
|
||||
import { BasicPlanMigrationBanner } from '@/HomePage/BasicPlanMigrationBanner/BasicPlanMigrationBanner';
|
||||
import { licenseService } from '@/_services';
|
||||
|
||||
const AppWrapper = (props) => {
|
||||
const { isAppDarkMode } = useAppDarkMode();
|
||||
|
|
@ -68,12 +70,24 @@ class AppComponent extends React.Component {
|
|||
currentUser: null,
|
||||
fetchedMetadata: false,
|
||||
darkMode: localStorage.getItem('darkMode') === 'true',
|
||||
showBanner: false,
|
||||
// isEditorOrViewer: '',
|
||||
};
|
||||
}
|
||||
updateSidebarNAV = (val) => {
|
||||
this.setState({ sidebarNav: val });
|
||||
};
|
||||
updateMargin() {
|
||||
const isAdmin = authenticationService?.currentSessionValue?.admin;
|
||||
const isBuilder = authenticationService?.currentSessionValue?.is_builder;
|
||||
const setupDate = authenticationService?.currentSessionValue?.consultation_banner_date;
|
||||
const showBannerCondition =
|
||||
(isAdmin || isBuilder) && setupDate && this.isExistingPlanUser(setupDate) && this.state.showBanner;
|
||||
const marginValue = showBannerCondition ? '25' : '0';
|
||||
const marginValueLayout = showBannerCondition ? '35' : '0';
|
||||
document.documentElement.style.setProperty('--dynamic-margin', `${marginValue}px`);
|
||||
document.documentElement.style.setProperty('--dynamic-margin-2', `${marginValueLayout}px`);
|
||||
}
|
||||
|
||||
fetchMetadata = () => {
|
||||
tooljetService.fetchMetaData().then((data) => {
|
||||
|
|
@ -89,11 +103,15 @@ class AppComponent extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
async componentDidMount() {
|
||||
setFaviconAndTitle();
|
||||
authorizeWorkspace();
|
||||
this.fetchMetadata();
|
||||
setInterval(this.fetchMetadata, 1000 * 60 * 60 * 1);
|
||||
this.updateMargin(); // Set initial margin
|
||||
const featureAccess = await licenseService.getFeatureAccess();
|
||||
const isBasicPlan = !featureAccess?.licenseStatus?.isLicenseValid || featureAccess?.licenseStatus?.isExpired;
|
||||
this.setState({ showBanner: isBasicPlan });
|
||||
}
|
||||
// check if its getting routed from editor
|
||||
checkPreviousRoute = (route) => {
|
||||
|
|
@ -114,6 +132,8 @@ class AppComponent extends React.Component {
|
|||
// Reload the page for clearing already set intervals
|
||||
window.location.reload();
|
||||
}
|
||||
// Update margin when showBanner changes
|
||||
this.updateMargin();
|
||||
}
|
||||
|
||||
switchDarkMode = (newMode) => {
|
||||
|
|
@ -130,8 +150,14 @@ class AppComponent extends React.Component {
|
|||
}
|
||||
return '';
|
||||
};
|
||||
closeBasicPlanMigrationBanner = () => {
|
||||
this.setState({ showBanner: false });
|
||||
};
|
||||
isExistingPlanUser = (date) => {
|
||||
return new Date(date) < new Date('2025-04-24'); //show banner if user created before 2 april (24 for testing)
|
||||
};
|
||||
render() {
|
||||
const { updateAvailable, darkMode, isEditorOrViewer } = this.state;
|
||||
const { updateAvailable, darkMode, isEditorOrViewer, showBanner } = this.state;
|
||||
const mergedProps = {
|
||||
...this.props,
|
||||
switchDarkMode: this.switchDarkMode,
|
||||
|
|
@ -156,220 +182,236 @@ class AppComponent extends React.Component {
|
|||
}
|
||||
const { sidebarNav } = this.state;
|
||||
const { updateSidebarNAV } = this;
|
||||
const isApplicationsPath = window.location.pathname.includes('/applications/');
|
||||
const isAdmin = authenticationService?.currentSessionValue?.admin;
|
||||
const isBuilder = authenticationService?.currentSessionValue?.is_builder;
|
||||
const setupDate = authenticationService?.currentSessionValue?.consultation_banner_date;
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={cx('main-wrapper', {
|
||||
'theme-dark dark-theme': !this.isEditorOrViewerFromPath() && darkMode,
|
||||
})}
|
||||
data-cy="main-wrapper"
|
||||
>
|
||||
{updateAvailable && (
|
||||
<div className="alert alert-info alert-dismissible" role="alert">
|
||||
<h3 className="mb-1">Update available</h3>
|
||||
<p>A new version of ToolJet has been released.</p>
|
||||
<div className="btn-list">
|
||||
<a
|
||||
href="https://docs.tooljet.io/docs/setup/updating"
|
||||
target="_blank"
|
||||
className="btn btn-info"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Read release notes & update
|
||||
</a>
|
||||
<a
|
||||
onClick={() => {
|
||||
tooljetService.skipVersion();
|
||||
this.setState({ updateAvailable: false });
|
||||
}}
|
||||
className="btn"
|
||||
>
|
||||
Skip this version
|
||||
</a>
|
||||
<div className={!isApplicationsPath && (isAdmin || isBuilder) ? 'banner-layout-wrapper' : ''}>
|
||||
{!isApplicationsPath &&
|
||||
(isAdmin || isBuilder) &&
|
||||
showBanner &&
|
||||
setupDate &&
|
||||
this.isExistingPlanUser(setupDate) && (
|
||||
<BasicPlanMigrationBanner darkMode={darkMode} closeBanner={this.closeBasicPlanMigrationBanner} />
|
||||
)}
|
||||
<div
|
||||
className={cx('main-wrapper', {
|
||||
'theme-dark dark-theme': !this.isEditorOrViewerFromPath() && darkMode,
|
||||
})}
|
||||
data-cy="main-wrapper"
|
||||
>
|
||||
{updateAvailable && (
|
||||
<div className="alert alert-info alert-dismissible" role="alert">
|
||||
<h3 className="mb-1">Update available</h3>
|
||||
<p>A new version of ToolJet has been released.</p>
|
||||
<div className="btn-list">
|
||||
<a
|
||||
href="https://docs.tooljet.io/docs/setup/updating"
|
||||
target="_blank"
|
||||
className="btn btn-info"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Read release notes & update
|
||||
</a>
|
||||
<a
|
||||
onClick={() => {
|
||||
tooljetService.skipVersion();
|
||||
this.setState({ updateAvailable: false });
|
||||
}}
|
||||
className="btn"
|
||||
>
|
||||
Skip this version
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<BreadCrumbContext.Provider value={{ sidebarNav, updateSidebarNAV }}>
|
||||
<Routes>
|
||||
{onboarding(this.props)}
|
||||
{auth(this.props)}
|
||||
<Route path="/sso/:origin/:configId" exact element={<Oauth {...this.props} />} />
|
||||
<Route path="/sso/:origin" exact element={<Oauth {...this.props} />} />
|
||||
<Route
|
||||
exact
|
||||
path="/:workspaceId/apps/:slug/:pageHandle?/*"
|
||||
element={
|
||||
<AppsRoute componentType="editor">
|
||||
<AppLoader switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</AppsRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/:workspaceId/workspace-constants"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<WorkspaceConstants switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/applications/:slug/:pageHandle?"
|
||||
element={
|
||||
<AppsRoute componentType="viewer">
|
||||
<Viewer switchDarkMode={this.switchDarkMode} darkMode={this.props.isAppDarkMode} />
|
||||
</AppsRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/applications/:slug/versions/:versionId/environments/:environmentId/:pageHandle?"
|
||||
element={
|
||||
<AppsRoute componentType="viewer">
|
||||
<Viewer switchDarkMode={this.switchDarkMode} darkMode={this.props.isAppDarkMode} />
|
||||
</AppsRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/oauth2/authorize"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Authorize switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
{window.public_config?.ENABLE_WORKFLOWS_FEATURE === 'true' && (
|
||||
)}
|
||||
<BreadCrumbContext.Provider value={{ sidebarNav, updateSidebarNAV }}>
|
||||
<Routes>
|
||||
{onboarding(this.props)}
|
||||
{auth(this.props)}
|
||||
<Route path="/sso/:origin/:configId" exact element={<Oauth {...this.props} />} />
|
||||
<Route path="/sso/:origin" exact element={<Oauth {...this.props} />} />
|
||||
<Route
|
||||
exact
|
||||
path="/:workspaceId/workflows/*"
|
||||
path="/:workspaceId/apps/:slug/:pageHandle?/*"
|
||||
element={
|
||||
<AdminRoute {...this.props}>
|
||||
<Workflows switchDarkMode={this.switchDarkMode} darkMode={this.darkMode} />
|
||||
</AdminRoute>
|
||||
<AppsRoute componentType="editor">
|
||||
<AppLoader switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</AppsRoute>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Route path="/:workspaceId/workspace-settings/*" element={<WorkspaceSettings {...mergedProps} />}></Route>
|
||||
<Route path="settings/*" element={<InstanceSettings {...this.props} />}></Route>
|
||||
<Route path="/:workspaceId/settings/*" element={<Settings {...this.props} />}></Route>
|
||||
|
||||
{getAuditLogsRoutes(this.props)}
|
||||
<Route
|
||||
exact
|
||||
path="/:workspaceId/profile-settings"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<SettingsPage switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
{getDataSourcesRoutes(mergedProps)}
|
||||
<Route
|
||||
exact
|
||||
path="/applications/:id/versions/:versionId/:pageHandle?"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Viewer switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/applications/:slug/:pageHandle?"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Viewer switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
exact
|
||||
path="/:workspaceId/database"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<TooljetDatabase switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
|
||||
{this.state.tooljetVersion && !checkIfToolJetCloud(this.state.tooljetVersion) && (
|
||||
<Route
|
||||
exact
|
||||
path="/integrations"
|
||||
path="/:workspaceId/workspace-constants"
|
||||
element={
|
||||
<AdminRoute {...this.props}>
|
||||
<MarketplacePage switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</AdminRoute>
|
||||
<PrivateRoute>
|
||||
<WorkspaceConstants switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
>
|
||||
<Route path="installed" element={<InstalledPlugins />} />
|
||||
<Route path="marketplace" element={<MarketplacePlugins />} />/
|
||||
</Route>
|
||||
)}
|
||||
|
||||
<Route exact path="/" element={<Navigate to="/:workspaceId" />} />
|
||||
<Route
|
||||
exact
|
||||
path="/error/:errorType"
|
||||
element={<ErrorPage switchDarkMode={this.switchDarkMode} darkMode={darkMode} />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/app-url-archived"
|
||||
element={
|
||||
<SwitchWorkspacePage
|
||||
switchDarkMode={this.switchDarkMode}
|
||||
darkMode={darkMode}
|
||||
archived={true}
|
||||
isAppUrl={true}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/applications/:slug/:pageHandle?"
|
||||
element={
|
||||
<AppsRoute componentType="viewer">
|
||||
<Viewer switchDarkMode={this.switchDarkMode} darkMode={this.props.isAppDarkMode} />
|
||||
</AppsRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/applications/:slug/versions/:versionId/environments/:environmentId/:pageHandle?"
|
||||
element={
|
||||
<AppsRoute componentType="viewer">
|
||||
<Viewer switchDarkMode={this.switchDarkMode} darkMode={this.props.isAppDarkMode} />
|
||||
</AppsRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/oauth2/authorize"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Authorize switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
{window.public_config?.ENABLE_WORKFLOWS_FEATURE === 'true' && (
|
||||
<Route
|
||||
exact
|
||||
path="/:workspaceId/workflows/*"
|
||||
element={
|
||||
<AdminRoute {...this.props}>
|
||||
<Workflows switchDarkMode={this.switchDarkMode} darkMode={this.darkMode} />
|
||||
</AdminRoute>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/switch-workspace"
|
||||
element={
|
||||
<SwitchWorkspaceRoute>
|
||||
<SwitchWorkspacePage switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</SwitchWorkspaceRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/switch-workspace-archived"
|
||||
element={
|
||||
<SwitchWorkspaceRoute>
|
||||
<SwitchWorkspacePage switchDarkMode={this.switchDarkMode} darkMode={darkMode} archived={true} />
|
||||
</SwitchWorkspaceRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/:workspaceId"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<HomePage switchDarkMode={this.switchDarkMode} darkMode={darkMode} appType={'front-end'} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="*"
|
||||
render={() => {
|
||||
if (authenticationService?.currentSessionValue?.current_organization_id) {
|
||||
return <Navigate to="/:workspaceId" />;
|
||||
}
|
||||
return <Navigate to="/login" />;
|
||||
}}
|
||||
/>
|
||||
</Routes>
|
||||
</BreadCrumbContext.Provider>
|
||||
<div id="modal-div"></div>
|
||||
</div>
|
||||
)}
|
||||
<Route
|
||||
path="/:workspaceId/workspace-settings/*"
|
||||
element={<WorkspaceSettings {...mergedProps} />}
|
||||
></Route>
|
||||
<Route path="settings/*" element={<InstanceSettings {...this.props} />}></Route>
|
||||
<Route path="/:workspaceId/settings/*" element={<Settings {...this.props} />}></Route>
|
||||
|
||||
<Toast toastOptions={toastOptions} />
|
||||
{getAuditLogsRoutes(this.props)}
|
||||
<Route
|
||||
exact
|
||||
path="/:workspaceId/profile-settings"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<SettingsPage switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
{getDataSourcesRoutes(mergedProps)}
|
||||
<Route
|
||||
exact
|
||||
path="/applications/:id/versions/:versionId/:pageHandle?"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Viewer switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/applications/:slug/:pageHandle?"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Viewer switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
exact
|
||||
path="/:workspaceId/database"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<TooljetDatabase switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
|
||||
{this.state.tooljetVersion && !checkIfToolJetCloud(this.state.tooljetVersion) && (
|
||||
<Route
|
||||
exact
|
||||
path="/integrations"
|
||||
element={
|
||||
<AdminRoute {...this.props}>
|
||||
<MarketplacePage switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</AdminRoute>
|
||||
}
|
||||
>
|
||||
<Route path="installed" element={<InstalledPlugins />} />
|
||||
<Route path="marketplace" element={<MarketplacePlugins />} />/
|
||||
</Route>
|
||||
)}
|
||||
|
||||
<Route exact path="/" element={<Navigate to="/:workspaceId" />} />
|
||||
<Route
|
||||
exact
|
||||
path="/error/:errorType"
|
||||
element={<ErrorPage switchDarkMode={this.switchDarkMode} darkMode={darkMode} />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/app-url-archived"
|
||||
element={
|
||||
<SwitchWorkspacePage
|
||||
switchDarkMode={this.switchDarkMode}
|
||||
darkMode={darkMode}
|
||||
archived={true}
|
||||
isAppUrl={true}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/switch-workspace"
|
||||
element={
|
||||
<SwitchWorkspaceRoute>
|
||||
<SwitchWorkspacePage switchDarkMode={this.switchDarkMode} darkMode={darkMode} />
|
||||
</SwitchWorkspaceRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/switch-workspace-archived"
|
||||
element={
|
||||
<SwitchWorkspaceRoute>
|
||||
<SwitchWorkspacePage switchDarkMode={this.switchDarkMode} darkMode={darkMode} archived={true} />
|
||||
</SwitchWorkspaceRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/:workspaceId"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<HomePage switchDarkMode={this.switchDarkMode} darkMode={darkMode} appType={'front-end'} />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="*"
|
||||
render={() => {
|
||||
if (authenticationService?.currentSessionValue?.current_organization_id) {
|
||||
return <Navigate to="/:workspaceId" />;
|
||||
}
|
||||
return <Navigate to="/login" />;
|
||||
}}
|
||||
/>
|
||||
</Routes>
|
||||
</BreadCrumbContext.Provider>
|
||||
<div id="modal-div"></div>
|
||||
</div>
|
||||
|
||||
<Toast toastOptions={toastOptions} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ const CreateVersionModal = ({
|
|||
canCommit,
|
||||
orgGit,
|
||||
fetchingOrgGit,
|
||||
handleCommitOnVersionCreation = () => {},
|
||||
handleCommitOnVersionCreation = () => { },
|
||||
}) => {
|
||||
const [isCreatingVersion, setIsCreatingVersion] = useState(false);
|
||||
const [versionName, setVersionName] = useState('');
|
||||
|
|
@ -94,12 +94,15 @@ const CreateVersionModal = ({
|
|||
handleCommitOnVersionCreation(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log({ error });
|
||||
toast.error(error);
|
||||
});
|
||||
},
|
||||
(error) => {
|
||||
toast.error(error?.error);
|
||||
if (error?.data?.code === "23505") {
|
||||
toast.error("Version name already exists.");
|
||||
} else {
|
||||
toast.error(error?.error);
|
||||
}
|
||||
setIsCreatingVersion(false);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -150,11 +150,7 @@ export const CustomSelect = ({ currentEnvironment, onSelectVersion, ...props })
|
|||
{/* When we merge this code to EE update the defaultAppEnvironments object with rest of default environments (then delete this comment)*/}
|
||||
<ConfirmDialog
|
||||
show={deleteVersion.showModal}
|
||||
message={`${
|
||||
defaultAppEnvironments.length > 1
|
||||
? 'Deleting a version will permanently remove it from all environments.'
|
||||
: ''
|
||||
}Are you sure you want to delete this version - ${decodeEntities(deleteVersion.versionName)}?`}
|
||||
message={`Are you sure you want to delete this version - ${decodeEntities(deleteVersion.versionName)}?`}
|
||||
onConfirm={() => deleteAppVersion(deleteVersion.versionId, deleteVersion.versionName)}
|
||||
onCancel={resetDeleteModal}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,63 +0,0 @@
|
|||
import React, { useState } from 'react';
|
||||
import { ButtonSolid } from '@/_ui/AppButton/AppButton';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import { ToolTip } from '@/_components/ToolTip';
|
||||
import PromoteConfirmationModal from './PromoteConfirmationModal';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
|
||||
const PromoteVersionButton = () => {
|
||||
const [promoteModalData, setPromoteModalData] = useState(null);
|
||||
const { isSaving, editingVersion, appVersionEnvironment, environments, selectedEnvironment } = useStore(
|
||||
(state) => ({
|
||||
isSaving: state.app.isSaving,
|
||||
editingVersion: state.currentVersionId,
|
||||
selectedEnvironment: state.selectedEnvironment,
|
||||
environments: state.environments,
|
||||
appVersionEnvironment: state.appVersionEnvironment,
|
||||
}),
|
||||
shallow
|
||||
);
|
||||
|
||||
const shouldDisablePromote = isSaving || selectedEnvironment?.priority < appVersionEnvironment?.priority;
|
||||
|
||||
const handlePromote = () => {
|
||||
const curentEnvIndex = environments.findIndex((env) => env.id === appVersionEnvironment.id);
|
||||
setPromoteModalData({
|
||||
current: appVersionEnvironment,
|
||||
target: environments[curentEnvIndex + 1],
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ButtonSolid
|
||||
variant="primary"
|
||||
onClick={handlePromote}
|
||||
size="md"
|
||||
disabled={shouldDisablePromote}
|
||||
data-cy="promote-button"
|
||||
>
|
||||
<ToolTip message="Promote this version to the next environment" placement="bottom" show={!shouldDisablePromote}>
|
||||
<div style={{ fontSize: '14px' }}>Promote </div>
|
||||
</ToolTip>
|
||||
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M0.276332 7.02113C0.103827 7.23676 0.138788 7.55141 0.354419 7.72391C0.57005 7.89642 0.884696 7.86146 1.0572 7.64583L3.72387 4.31249C3.86996 4.12988 3.86996 3.87041 3.72387 3.6878L1.0572 0.354464C0.884696 0.138833 0.57005 0.103872 0.354419 0.276377C0.138788 0.448881 0.103827 0.763528 0.276332 0.979158L2.69312 4.00014L0.276332 7.02113ZM4.27633 7.02113C4.10383 7.23676 4.13879 7.55141 4.35442 7.72391C4.57005 7.89642 4.8847 7.86146 5.0572 7.64583L7.72387 4.31249C7.86996 4.12988 7.86996 3.87041 7.72387 3.6878L5.0572 0.354463C4.8847 0.138832 4.57005 0.103871 4.35442 0.276377C4.13879 0.448881 4.10383 0.763527 4.27633 0.979158L6.69312 4.00014L4.27633 7.02113Z"
|
||||
fill={shouldDisablePromote ? '#C1C8CD' : '#FDFDFE'}
|
||||
/>
|
||||
</svg>
|
||||
</ButtonSolid>
|
||||
|
||||
<PromoteConfirmationModal
|
||||
data={promoteModalData}
|
||||
editingVersion={editingVersion}
|
||||
onClose={() => setPromoteModalData(null)}
|
||||
fetchEnvironments={() => {}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PromoteVersionButton;
|
||||
|
|
@ -31,6 +31,7 @@ export const PageGroupMenu = ({ darkMode, isLicensed, disabled }) => {
|
|||
if (!isLicensed) {
|
||||
return (
|
||||
<button
|
||||
data-cy="add-page-button"
|
||||
disabled={disabled}
|
||||
onClick={(event) => {
|
||||
if (disabled) return;
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ export const PageMenuItem = withRouter(
|
|||
) : (
|
||||
<>
|
||||
{' '}
|
||||
<div className="left">
|
||||
<div className="left" data-cy={`pages-name-${page.name.toLowerCase()}`}>
|
||||
{icon()}
|
||||
<OverflowTooltip childrenClassName="page-name" style={{ ...computedStyles?.text }}>
|
||||
{page.name}
|
||||
|
|
|
|||
|
|
@ -36,16 +36,23 @@ function DataSourcePicker({ darkMode }) {
|
|||
(gds) => gds.type === DATA_SOURCE_TYPE.STATIC
|
||||
);
|
||||
//StaicDataSources DIDNT HAVE ID
|
||||
const updatedStaticDataSources = staticDataSources.map((source) => {
|
||||
// Find a matching object from staticDataSourcesFullObject based on the 'kind' field
|
||||
const matchingObject = staticDataSourcesFullObject?.find((gds) => gds.kind === source.kind);
|
||||
const updatedStaticDataSources = staticDataSources
|
||||
.filter((source) => {
|
||||
if (source.kind === 'workflows') {
|
||||
return staticDataSourcesFullObject?.some((gds) => gds.kind === 'workflows');
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map((source) => {
|
||||
// Find a matching object from staticDataSourcesFullObject based on the 'kind' field
|
||||
const matchingObject = staticDataSourcesFullObject?.find((gds) => gds.kind === source.kind);
|
||||
|
||||
// Replace the 'id' with the one from the matching object, or keep the existing one if no match
|
||||
return {
|
||||
...source,
|
||||
id: matchingObject?.id || source.id,
|
||||
};
|
||||
});
|
||||
// Replace the 'id' with the one from the matching object, or keep the existing one if no match
|
||||
return {
|
||||
...source,
|
||||
id: matchingObject?.id || source.id,
|
||||
};
|
||||
});
|
||||
|
||||
const docLink = 'sampledb.com';
|
||||
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ export const BaseQueryManagerBody = ({ darkMode, activeTab, renderCopilot = () =
|
|||
const renderChangeDataSource = () => {
|
||||
const selectableDataSources = [...dataSources, ...globalDataSources, !!sampleDataSource && sampleDataSource]
|
||||
.filter(Boolean)
|
||||
.filter((ds) => ds.kind === selectedQuery?.kind);
|
||||
.filter((ds) => ds.kind === selectedQuery?.kind && ds.type !== DATA_SOURCE_TYPE.STATIC);
|
||||
if (isEmpty(selectableDataSources)) {
|
||||
return '';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ export const QueryManagerHeader = forwardRef(({ darkMode, setActiveTab, activeTa
|
|||
(tab.condition === undefined || tab.condition) && (
|
||||
<p
|
||||
key={tab.id}
|
||||
data-cy={`query-tab-${tab.label.toLowerCase()}`}
|
||||
className="m-0 d-flex align-items-center h-100"
|
||||
onClick={() => setActiveTab(tab.id)}
|
||||
style={{
|
||||
|
|
@ -151,8 +152,8 @@ const NameInput = ({ onInput, value, darkMode, isDiabled, selectedQuery }) => {
|
|||
const hasPermissions =
|
||||
selectedDataSourceScope === 'global'
|
||||
? canUpdateDataSource(selectedQuery?.data_source_id) ||
|
||||
canReadDataSource(selectedQuery?.data_source_id) ||
|
||||
canDeleteDataSource()
|
||||
canReadDataSource(selectedQuery?.data_source_id) ||
|
||||
canDeleteDataSource()
|
||||
: true;
|
||||
const inputRef = useRef();
|
||||
|
||||
|
|
@ -274,8 +275,8 @@ const PreviewButton = ({ buttonLoadingState, onClick }) => {
|
|||
const hasPermissions =
|
||||
selectedDataSource?.scope === 'global' && selectedDataSource?.type !== DATA_SOURCE_TYPE.SAMPLE
|
||||
? canUpdateDataSource(selectedQuery?.data_source_id) ||
|
||||
canReadDataSource(selectedQuery?.data_source_id) ||
|
||||
canDeleteDataSource()
|
||||
canReadDataSource(selectedQuery?.data_source_id) ||
|
||||
canDeleteDataSource()
|
||||
: true;
|
||||
const isPreviewQueryLoading = useStore((state) => state.queryPanel.isPreviewQueryLoading);
|
||||
const { t } = useTranslation();
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ export const QueryPanel = ({ darkMode }) => {
|
|||
}}
|
||||
>
|
||||
<button
|
||||
data-cy="query-manager-toggle-button"
|
||||
className="d-flex items-center justify-start mb-0 font-weight-500 text-dark select-none query-manager-toggle-button gap-1"
|
||||
onClick={toggleQueryEditor}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const TooljetBanner = ({ isDarkMode }) => {
|
|||
<div
|
||||
className="powered-with-tj"
|
||||
onClick={() => {
|
||||
const url = `https://tooljet.com/?utm_source=powered_by_banner&utm_medium=${instanceId}&utm_campaign=self_hosted`;
|
||||
const url = `https://tooljet.com`;
|
||||
window.open(url, '_blank');
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@ export const formConfig = {
|
|||
accessorKey: 'text',
|
||||
styles: ['fontWeight', 'textSize', 'textColor'],
|
||||
defaultValue: {
|
||||
text: 'Form',
|
||||
text: 'Form title',
|
||||
textSize: 16,
|
||||
textColor: '#000',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -29,8 +30,9 @@ export const formConfig = {
|
|||
slotName: 'footer',
|
||||
layout: {
|
||||
top: 12,
|
||||
left: 32,
|
||||
left: 29,
|
||||
height: 36,
|
||||
width: 13,
|
||||
},
|
||||
properties: ['text'],
|
||||
defaultValue: {
|
||||
|
|
@ -42,9 +44,9 @@ export const formConfig = {
|
|||
componentName: 'TextInput',
|
||||
layout: {
|
||||
top: 20,
|
||||
left: 5,
|
||||
left: 1,
|
||||
height: 40,
|
||||
width: 31,
|
||||
width: 41,
|
||||
},
|
||||
properties: ['placeholder', 'label'],
|
||||
styles: ['alignment', 'width', 'auto', 'padding', 'direction'],
|
||||
|
|
@ -62,9 +64,9 @@ export const formConfig = {
|
|||
componentName: 'NumberInput',
|
||||
layout: {
|
||||
top: 80,
|
||||
left: 5,
|
||||
left: 1,
|
||||
height: 40,
|
||||
width: 31,
|
||||
width: 41,
|
||||
},
|
||||
properties: ['placeholder', 'label'],
|
||||
styles: ['alignment', 'width', 'auto', 'padding', 'direction'],
|
||||
|
|
@ -78,26 +80,6 @@ export const formConfig = {
|
|||
padding: 'default',
|
||||
},
|
||||
},
|
||||
{
|
||||
componentName: 'TextInput',
|
||||
layout: {
|
||||
top: 140,
|
||||
left: 5,
|
||||
height: 40,
|
||||
width: 31,
|
||||
},
|
||||
properties: ['placeholder', 'label'],
|
||||
styles: ['alignment', 'width', 'auto', 'padding', 'direction'],
|
||||
defaultValue: {
|
||||
placeholder: 'Tomy',
|
||||
label: 'Pet name',
|
||||
width: '{{60}}',
|
||||
alignment: 'side',
|
||||
direction: 'left',
|
||||
auto: '{{false}}',
|
||||
padding: 'default',
|
||||
},
|
||||
},
|
||||
],
|
||||
component: 'Form',
|
||||
others: {
|
||||
|
|
@ -289,6 +271,8 @@ export const formConfig = {
|
|||
backgroundColor: { value: '#fff' },
|
||||
borderRadius: { value: '0' },
|
||||
borderColor: { value: '#fff' },
|
||||
headerBackgroundColor: { value: '#fff' },
|
||||
footerBackgroundColor: { value: '#fff' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -90,9 +90,9 @@ export const Modal = function Modal({
|
|||
const onHideSideEffects = () => {
|
||||
const canvasElement = document.querySelector('.page-container.canvas-container');
|
||||
const realCanvasEl = document.getElementsByClassName('real-canvas')[0];
|
||||
const allModalContainers = realCanvasEl.querySelectorAll('.modal');
|
||||
const modalContainer = allModalContainers[allModalContainers.length - 1];
|
||||
const hasManyModalsOpen = allModalContainers.length > 1;
|
||||
const allModalContainers = realCanvasEl?.querySelectorAll('.modal');
|
||||
const modalContainer = allModalContainers?.[allModalContainers.length - 1];
|
||||
const hasManyModalsOpen = allModalContainers?.length > 1;
|
||||
|
||||
if (canvasElement && realCanvasEl && modalContainer) {
|
||||
modalContainer.style.height = ``;
|
||||
|
|
|
|||
|
|
@ -267,6 +267,11 @@ export const DropdownV2 = ({
|
|||
setExposedVariable('isMandatory', isMandatory);
|
||||
}, [isMandatory]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('value', currentValue);
|
||||
}, [currentValue]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
const validationStatus = validate(currentValue);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,14 @@ export const getInputBackgroundColor = ({ fieldBackgroundColor, darkMode, isLoad
|
|||
};
|
||||
|
||||
export const highlightText = (text = '', highlight) => {
|
||||
const parts = text?.split(new RegExp(`(${highlight})`, 'gi'));
|
||||
// Escape special regex characters in the highlight string
|
||||
const escapeRegExp = (string) => {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
};
|
||||
|
||||
const safeHighlight = highlight ? escapeRegExp(highlight) : '';
|
||||
const parts = text?.split(new RegExp(`(${safeHighlight})`, 'gi'));
|
||||
|
||||
return (
|
||||
<span>
|
||||
{parts.map((part, index) =>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,11 @@ import './multiselectV2.scss';
|
|||
|
||||
const CustomValueContainer = ({ children, ...props }) => {
|
||||
const selectProps = props.selectProps;
|
||||
const values = Array.isArray(selectProps?.value) && selectProps?.value?.map((option) => option.label);
|
||||
const values =
|
||||
Array.isArray(selectProps?.value) &&
|
||||
selectProps?.value
|
||||
?.filter((option) => option.value !== 'multiselect-custom-menulist-select-all') //Remove the Select all option if selected
|
||||
?.map((option) => option.label);
|
||||
const isAllOptionsSelected = selectProps?.value.length === selectProps.options.length;
|
||||
const valueContainerWidth = selectProps?.containerRef?.current?.offsetWidth;
|
||||
// eslint-disable-next-line import/namespace
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ export const MultiselectV2 = ({
|
|||
if (action.option?.value === SELECT_ALL) {
|
||||
// Case 1 - If select all is selected
|
||||
if (action.action === 'select-option') {
|
||||
setInputValue(modifiedSelectOptions);
|
||||
setInputValue(selectOptions);
|
||||
} else {
|
||||
setInputValue([]);
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ export const MultiselectV2 = ({
|
|||
setInputValue(items.filter((item) => item.value !== SELECT_ALL));
|
||||
} else if (selectOptions?.length === items?.length) {
|
||||
// Case 3 - If all options are selected except select all
|
||||
setInputValue(modifiedSelectOptions);
|
||||
setInputValue(selectOptions);
|
||||
} else {
|
||||
// Case 4 - Normal selection
|
||||
setInputValue(items);
|
||||
|
|
@ -503,7 +503,7 @@ export const MultiselectV2 = ({
|
|||
ref={selectRef}
|
||||
menuId={id}
|
||||
isDisabled={isMultiSelectDisabled}
|
||||
value={selected}
|
||||
value={selectOptions?.length === selected?.length ? modifiedSelectOptions : selected}
|
||||
onChange={onChangeHandler}
|
||||
options={modifiedSelectOptions}
|
||||
styles={customStyles}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const TooljetBanner = ({ isDarkMode }) => {
|
|||
<div
|
||||
className="powered-with-tj"
|
||||
onClick={() => {
|
||||
const url = `https://tooljet.com/?utm_source=powered_by_banner&utm_medium=${instanceId}&utm_campaign=self_hosted`;
|
||||
const url = `https://tooljet.com`;
|
||||
window.open(url, '_blank');
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@ export const formConfig = {
|
|||
accessorKey: 'text',
|
||||
styles: ['fontWeight', 'textSize', 'textColor'],
|
||||
defaultValue: {
|
||||
text: 'Form',
|
||||
text: 'Form title',
|
||||
textSize: 16,
|
||||
textColor: '#000',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -29,8 +30,9 @@ export const formConfig = {
|
|||
slotName: 'footer',
|
||||
layout: {
|
||||
top: 12,
|
||||
left: 32,
|
||||
left: 29,
|
||||
height: 36,
|
||||
width: 13,
|
||||
},
|
||||
properties: ['text'],
|
||||
defaultValue: {
|
||||
|
|
@ -42,9 +44,9 @@ export const formConfig = {
|
|||
componentName: 'TextInput',
|
||||
layout: {
|
||||
top: 20,
|
||||
left: 5,
|
||||
left: 1,
|
||||
height: 40,
|
||||
width: 31,
|
||||
width: 41,
|
||||
},
|
||||
properties: ['placeholder', 'label'],
|
||||
styles: ['alignment', 'width', 'auto', 'padding', 'direction'],
|
||||
|
|
@ -62,9 +64,9 @@ export const formConfig = {
|
|||
componentName: 'NumberInput',
|
||||
layout: {
|
||||
top: 80,
|
||||
left: 5,
|
||||
left: 1,
|
||||
height: 40,
|
||||
width: 31,
|
||||
width: 41,
|
||||
},
|
||||
properties: ['placeholder', 'label'],
|
||||
styles: ['alignment', 'width', 'auto', 'padding', 'direction'],
|
||||
|
|
@ -78,26 +80,6 @@ export const formConfig = {
|
|||
padding: 'default',
|
||||
},
|
||||
},
|
||||
{
|
||||
componentName: 'TextInput',
|
||||
layout: {
|
||||
top: 140,
|
||||
left: 5,
|
||||
height: 40,
|
||||
width: 31,
|
||||
},
|
||||
properties: ['placeholder', 'label'],
|
||||
styles: ['alignment', 'width', 'auto', 'padding', 'direction'],
|
||||
defaultValue: {
|
||||
placeholder: 'Tomy',
|
||||
label: 'Pet name',
|
||||
width: '{{60}}',
|
||||
alignment: 'side',
|
||||
direction: 'left',
|
||||
auto: '{{false}}',
|
||||
padding: 'default',
|
||||
},
|
||||
},
|
||||
],
|
||||
component: 'Form',
|
||||
others: {
|
||||
|
|
@ -289,6 +271,8 @@ export const formConfig = {
|
|||
backgroundColor: { value: '#fff' },
|
||||
borderRadius: { value: '0' },
|
||||
borderColor: { value: '#fff' },
|
||||
headerBackgroundColor: { value: '#fff' },
|
||||
footerBackgroundColor: { value: '#fff' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
import React, { useState } from 'react';
|
||||
import './BasicPlanMigrationBanner.scss';
|
||||
import CloseIcon from '@/_ui/Icon/bulkIcons/CloseIcon';
|
||||
|
||||
export const BasicPlanMigrationBanner = ({ closeBanner, darkMode }) => {
|
||||
return (
|
||||
<div className={`${darkMode ? 'theme-dark dark-theme' : ''} basic-plan-migration-banner`}>
|
||||
<div style={{ marginLeft: 'auto' }}>
|
||||
<p className="banner-text">
|
||||
We've updated your plan limits to align with our{' '}
|
||||
<a href="https://www.tooljet.ai/pricing" className="banner-link" target="_blank" rel="noopener noreferrer">
|
||||
new pricing.
|
||||
</a>{' '}
|
||||
For help in retrieving data or any inquiries,{' '}
|
||||
<a
|
||||
href="https://docs.tooljet.ai/docs/tj-setup/licensing/self-hosted/"
|
||||
className="banner-link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
read docs
|
||||
</a>{' '}
|
||||
or{' '}
|
||||
<a href="mailto:hello@tooljet.com" className="banner-link" target="_blank" rel="noopener noreferrer">
|
||||
contact us
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div onClick={closeBanner} type="button">
|
||||
<CloseIcon width="12" fill="#3E63DD" opacity="1" secondaryFill="#ffffff" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
.basic-plan-migration-banner {
|
||||
background-color: var(--background-accent-weak);
|
||||
padding: 12px 16px;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.banner-text {
|
||||
color: var(--text-accent, #4368E3);
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.banner-text{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.banner-link {
|
||||
color: var(--primary-brand);
|
||||
text-decoration: underline;
|
||||
font-weight: 500;
|
||||
|
||||
&:hover {
|
||||
color: var(--indigo-100);
|
||||
}
|
||||
}
|
||||
|
||||
div[type="button"] {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
// banner css changes
|
||||
.banner-layout-wrapper {
|
||||
height: 100vh !important;
|
||||
overflow: hidden;
|
||||
/* prevents scrolling beyond this height */
|
||||
position: relative;
|
||||
background-color: var(--background-accent-weak);
|
||||
/* content background */
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ export const BlankPage = function BlankPage({
|
|||
viewTemplateLibraryModal,
|
||||
appType,
|
||||
canCreateApp,
|
||||
workflowsLimit,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const whiteLabelText = retrieveWhiteLabelText();
|
||||
|
|
@ -43,6 +44,8 @@ export const BlankPage = function BlankPage({
|
|||
}
|
||||
|
||||
const appCreationDisabled = !canCreateApp() || (!appsLimit?.canAddUnlimited && appsLimit?.percentage >= 100);
|
||||
const workflowsCreationDisabled =
|
||||
!canCreateApp() || (!workflowsLimit?.canAddUnlimited && workflowsLimit?.percentage >= 100);
|
||||
|
||||
const templateOptionsView = (
|
||||
<>
|
||||
|
|
@ -133,12 +136,12 @@ export const BlankPage = function BlankPage({
|
|||
<div className="row mt-4">
|
||||
<div className="col-6">
|
||||
<ButtonSolid
|
||||
disabled={appCreationDisabled}
|
||||
leftIcon="plus"
|
||||
onClick={openCreateAppModal}
|
||||
isLoading={creatingApp}
|
||||
data-cy="button-new-app-from-scratch"
|
||||
className="col"
|
||||
disabled={appType !== 'workflow' ? appCreationDisabled : workflowsCreationDisabled}
|
||||
fill={'#FDFDFE'}
|
||||
>
|
||||
Create new {appType !== 'workflow' ? 'application' : 'workflow'}
|
||||
|
|
|
|||
|
|
@ -511,7 +511,12 @@ class HomePageComponent extends React.Component {
|
|||
this.state.currentFolder.id
|
||||
);
|
||||
this.fetchFolders();
|
||||
this.fetchAppsLimit();
|
||||
if (this.props.appType === 'workflow') {
|
||||
this.fetchWorkflowsInstanceLimit();
|
||||
this.fetchWorkflowsWorkspaceLimit();
|
||||
} else {
|
||||
this.fetchAppsLimit();
|
||||
}
|
||||
})
|
||||
.catch(({ error }) => {
|
||||
toast.error('Could not delete the app.');
|
||||
|
|
@ -522,6 +527,10 @@ class HomePageComponent extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
isExistingPlanUser = (date) => {
|
||||
return new Date(date) < new Date('2025-04-01');
|
||||
};
|
||||
|
||||
pageCount = () => {
|
||||
return this.state.currentFolder.id ? this.state.meta.folder_count : this.state.meta.total_count;
|
||||
};
|
||||
|
|
@ -928,6 +937,8 @@ class HomePageComponent extends React.Component {
|
|||
dependentPlugins: dependentPlugins,
|
||||
},
|
||||
};
|
||||
const isAdmin = authenticationService?.currentSessionValue?.admin;
|
||||
const isBuilder = authenticationService?.currentSessionValue?.is_builder;
|
||||
return (
|
||||
<Layout switchDarkMode={this.props.switchDarkMode} darkMode={this.props.darkMode}>
|
||||
<div className="wrapper home-page">
|
||||
|
|
@ -1231,31 +1242,6 @@ class HomePageComponent extends React.Component {
|
|||
</Dropdown>
|
||||
</div>
|
||||
</LicenseTooltip>
|
||||
{this.props.appType === 'front-end' && (
|
||||
<LicenseBanner classes="mb-3 small" limits={appsLimit} type="apps" size="small" />
|
||||
)}
|
||||
{this.props.appType === 'workflow' &&
|
||||
(workflowInstanceLevelLimit.current >= workflowInstanceLevelLimit.total ||
|
||||
100 > workflowInstanceLevelLimit.percentage >= 90 ||
|
||||
workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1 ||
|
||||
workflowWorkspaceLevelLimit.current >= workflowWorkspaceLevelLimit.total ||
|
||||
100 > workflowWorkspaceLevelLimit.percentage >= 90 ||
|
||||
workflowWorkspaceLevelLimit.current === workflowWorkspaceLevelLimit.total - 1) && (
|
||||
<>
|
||||
<LicenseBanner
|
||||
classes="mb-3 small"
|
||||
limits={
|
||||
workflowInstanceLevelLimit.current >= workflowInstanceLevelLimit.total ||
|
||||
100 > workflowInstanceLevelLimit.percentage >= 90 ||
|
||||
workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1
|
||||
? workflowInstanceLevelLimit
|
||||
: workflowWorkspaceLevelLimit
|
||||
}
|
||||
type="workflow"
|
||||
size="small"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<Folders
|
||||
|
|
@ -1271,6 +1257,31 @@ class HomePageComponent extends React.Component {
|
|||
canCreateApp={this.canCreateApp()}
|
||||
appType={this.props.appType}
|
||||
/>
|
||||
{this.props.appType === 'front-end' && (
|
||||
<LicenseBanner classes="mb-3 small" limits={appsLimit} type="apps" size="small" />
|
||||
)}
|
||||
{this.props.appType === 'workflow' &&
|
||||
(workflowInstanceLevelLimit.current >= workflowInstanceLevelLimit.total ||
|
||||
100 > workflowInstanceLevelLimit.percentage >= 90 ||
|
||||
workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1 ||
|
||||
workflowWorkspaceLevelLimit.current >= workflowWorkspaceLevelLimit.total ||
|
||||
100 > workflowWorkspaceLevelLimit.percentage >= 90 ||
|
||||
workflowWorkspaceLevelLimit.current === workflowWorkspaceLevelLimit.total - 1) && (
|
||||
<>
|
||||
<LicenseBanner
|
||||
classes="mb-3 small"
|
||||
limits={
|
||||
workflowInstanceLevelLimit.current >= workflowInstanceLevelLimit.total ||
|
||||
100 > workflowInstanceLevelLimit.percentage >= 90 ||
|
||||
workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1
|
||||
? workflowInstanceLevelLimit
|
||||
: workflowWorkspaceLevelLimit
|
||||
}
|
||||
type="workflow"
|
||||
size="small"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{authenticationService.currentSessionValue?.super_admin &&
|
||||
this.isWithinSevenDaysOfSignUp(authenticationService.currentSessionValue?.consultation_banner_date) && (
|
||||
<ConsultationBanner
|
||||
|
|
@ -1284,7 +1295,7 @@ class HomePageComponent extends React.Component {
|
|||
/>
|
||||
)}
|
||||
|
||||
<OrganizationList />
|
||||
<OrganizationList customStyle={{ marginBottom: isAdmin || isBuilder ? '' : '0px' }} />
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
|
@ -1359,6 +1370,13 @@ class HomePageComponent extends React.Component {
|
|||
viewTemplateLibraryModal={this.showTemplateLibraryModal}
|
||||
hideTemplateLibraryModal={this.hideTemplateLibraryModal}
|
||||
appType={this.props.appType}
|
||||
workflowsLimit={
|
||||
workflowInstanceLevelLimit.current >= workflowInstanceLevelLimit.total ||
|
||||
100 > workflowInstanceLevelLimit.percentage >= 90 ||
|
||||
workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1
|
||||
? workflowInstanceLevelLimit
|
||||
: workflowWorkspaceLevelLimit
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{!isLoading && apps?.length === 0 && appSearchKey && (
|
||||
|
|
|
|||
|
|
@ -88,10 +88,11 @@ function SettingsPage(props) {
|
|||
|
||||
const handlePasswordInput = (input) => {
|
||||
setNewPassword(input);
|
||||
if (input.length > 100) {
|
||||
const trimmedInput = input.trim();
|
||||
if (trimmedInput.length > 100) {
|
||||
setHelperText('Password should be Max 100 characters');
|
||||
setValidPassword(false);
|
||||
} else if (input.length < 5 && input.length > 0) {
|
||||
} else if (trimmedInput.length < 5 && trimmedInput.length > 0) {
|
||||
setHelperText('Password should be at least 5 characters');
|
||||
setValidPassword(false);
|
||||
} else {
|
||||
|
|
@ -100,11 +101,19 @@ function SettingsPage(props) {
|
|||
}
|
||||
};
|
||||
|
||||
const handleConfirmPasswordInput = (input) => {
|
||||
setConfirmPassword(input);
|
||||
};
|
||||
|
||||
const changePassword = async () => {
|
||||
const trimmedCurrentPassword = currentpassword.trim();
|
||||
const trimmedNewPassword = newPassword.trim();
|
||||
const trimmedConfirmPassword = confirmPassword.trim();
|
||||
|
||||
const errorMsg =
|
||||
(currentpassword.match(/^ *$/) !== null && 'Current password') ||
|
||||
(newPassword.match(/^ *$/) !== null && 'New password') ||
|
||||
(confirmPassword.match(/^ *$/) !== null && 'Confirm new password');
|
||||
(trimmedCurrentPassword.length === 0 && 'Current password') ||
|
||||
(trimmedNewPassword.length === 0 && 'New password') ||
|
||||
(trimmedConfirmPassword.length === 0 && 'Confirm new password');
|
||||
|
||||
if (errorMsg) {
|
||||
toast.error(errorMsg + " can't be empty!", {
|
||||
|
|
@ -112,13 +121,13 @@ function SettingsPage(props) {
|
|||
});
|
||||
return;
|
||||
}
|
||||
if (currentpassword === newPassword) {
|
||||
if (trimmedCurrentPassword === trimmedNewPassword) {
|
||||
toast.error("New password can't be the same as the current one!", {
|
||||
duration: 3000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (newPassword !== confirmPassword) {
|
||||
if (trimmedNewPassword !== trimmedConfirmPassword) {
|
||||
toast.error('New password and confirm new password should be same', {
|
||||
duration: 3000,
|
||||
});
|
||||
|
|
@ -127,7 +136,7 @@ function SettingsPage(props) {
|
|||
|
||||
setPasswordChangeInProgress(true);
|
||||
try {
|
||||
await userService.changePassword(currentpassword, newPassword);
|
||||
await userService.changePassword(trimmedCurrentPassword, trimmedNewPassword);
|
||||
toast.success('Password updated successfully', {
|
||||
duration: 3000,
|
||||
});
|
||||
|
|
@ -293,7 +302,7 @@ function SettingsPage(props) {
|
|||
placeholder={t('header.profileSettingPage.confirmNewPassword', 'Confirm new password')}
|
||||
value={confirmPassword}
|
||||
ref={focusRef}
|
||||
onChange={(event) => setConfirmPassword(event.target.value)}
|
||||
onChange={(event) => handleConfirmPasswordInput(event.target.value)}
|
||||
onKeyPress={confirmPasswordKeyPressHandler}
|
||||
data-cy="confirm-password-input"
|
||||
/>
|
||||
|
|
@ -301,7 +310,7 @@ function SettingsPage(props) {
|
|||
</div>
|
||||
<ButtonSolid
|
||||
isLoading={passwordChangeInProgress}
|
||||
disabled={newPassword.length < 5 || confirmPassword.length < 5 || !validPassword}
|
||||
disabled={newPassword.trim().length < 5 || confirmPassword.trim().length < 5 || !validPassword}
|
||||
onClick={changePassword}
|
||||
data-cy="change-password-button"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ const LegalReasonsErrorModal = ({
|
|||
<Button className="upgrade-btn" autoFocus onClick={() => {}}>
|
||||
<a
|
||||
style={{ color: 'white', textDecoration: 'none' }}
|
||||
href={`https://www.tooljet.com/pricing?utm_source=banner&utm_medium=plg&utm_campaign=none&payment=onpremise&instance_id=${currentUser?.instance_id}`}
|
||||
href={`https://www.tooljet.com/pricing`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
data-cy="upgrade-button"
|
||||
|
|
|
|||
|
|
@ -192,8 +192,21 @@ export const returnWorkspaceIdIfNeed = (path) => {
|
|||
};
|
||||
export const getRedirectURL = (path) => {
|
||||
let redirectLoc = '/';
|
||||
const instanceLevelRoutes = [
|
||||
'/all-users',
|
||||
'/all-workspaces',
|
||||
'/manage-instance-settings',
|
||||
'/white-labelling',
|
||||
'/instance-login',
|
||||
'/smtp',
|
||||
'/license',
|
||||
];
|
||||
if (path) {
|
||||
redirectLoc = `${returnWorkspaceIdIfNeed(path)}${path !== '/' ? path : ''}`;
|
||||
if (instanceLevelRoutes.includes(path)) {
|
||||
redirectLoc = `/settings${path}`;
|
||||
} else {
|
||||
redirectLoc = `${returnWorkspaceIdIfNeed(path)}${path !== '/' ? path : ''}`;
|
||||
}
|
||||
} else {
|
||||
const redirectTo = getRedirectTo();
|
||||
const { from } = redirectTo ? { from: { pathname: redirectTo } } : { from: { pathname: '/' } };
|
||||
|
|
|
|||
|
|
@ -2,16 +2,21 @@ import HttpClient from '@/_helpers/http-client';
|
|||
|
||||
const adapter = new HttpClient();
|
||||
|
||||
//Uncomment when Comment Notifications Module is ready
|
||||
|
||||
function findAll(isRead = false) {
|
||||
return adapter.get(`/comment_notifications?isRead=${isRead}`);
|
||||
return { data: [] };
|
||||
// return adapter.get(`/comment_notifications?isRead=${isRead}`);
|
||||
}
|
||||
|
||||
function updateAll(isRead) {
|
||||
return adapter.patch(`/comment_notifications`, { isRead });
|
||||
return;
|
||||
// return adapter.patch(`/comment_notifications`, { isRead });
|
||||
}
|
||||
|
||||
function update(id, isRead) {
|
||||
return adapter.patch(`/comment_notifications/${id}`, { isRead });
|
||||
return;
|
||||
// return adapter.patch(`/comment_notifications/${id}`, { isRead });
|
||||
}
|
||||
|
||||
export const commentNotificationsService = {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export const organizationService = {
|
|||
|
||||
function getUsersByValue(searchInput) {
|
||||
const requestOptions = { method: 'GET', headers: authHeader(), credentials: 'include' };
|
||||
return fetch(`${config.apiUrl}/organizations/users/suggest?input=${searchInput}`, requestOptions).then(
|
||||
return fetch(`${config.apiUrl}/organization-users/users/suggest?input=${searchInput}`, requestOptions).then(
|
||||
handleResponse
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
border-top: 1px solid var(--slate5);
|
||||
margin-bottom: var(--dynamic-margin, 0px); //please Remove after Basicplan banner is removed..
|
||||
}
|
||||
|
||||
.tj-org-select {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue