diff --git a/.github/workflows/cypress-appbuilder.yml b/.github/workflows/cypress-appbuilder.yml index 3e9be3f560..67eb0ae432 100644 --- a/.github/workflows/cypress-appbuilder.yml +++ b/.github/workflows/cypress-appbuilder.yml @@ -2,7 +2,7 @@ name: Cypress App-Builder on: pull_request_target: - types: [labeled, unlabeled, closed] + types: [labeled] workflow_dispatch: env: @@ -12,22 +12,18 @@ env: jobs: Cypress-App-Builder: runs-on: ubuntu-22.04 - if: | - github.event.action == 'labeled' && - ( - github.event.label.name == 'run-cypress' || - github.event.label.name == 'run-ce-app-builder' || - github.event.label.name == 'run-ee-app-builder' - ) + contains(github.event.pull_request.labels.*.name, 'run-ce-app-builder') || + contains(github.event.pull_request.labels.*.name, 'run-ee-app-builder') || + contains(github.event.pull_request.labels.*.name, 'run-cypress') strategy: matrix: edition: >- ${{ - contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') || contains(github.event.pull_request.labels.*.name, 'run-ce-app-builder') && fromJson('["ce"]') || contains(github.event.pull_request.labels.*.name, 'run-ee-app-builder') && fromJson('["ee"]') || + contains(github.event.pull_request.labels.*.name, 'run-cypress') && fromJson('["ce", "ee"]') || fromJson('[]') }} @@ -164,8 +160,8 @@ jobs: Cypress-App-builder-Subpath: runs-on: ubuntu-22.04 - - if: ${{ github.event.action == 'labeled' && github.event.label.name == 'run-cypress-app-builder-subpath' }} + if: contains(github.event.pull_request.labels.*.name, 'run-cypress') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-app-builder-subpath') steps: - name: Checkout @@ -173,82 +169,6 @@ jobs: with: ref: ${{ github.event.pull_request.head.ref }} - # Create Docker Buildx builder with platform configuration - - name: Set up Docker Buildx - run: | - mkdir -p ~/.docker/cli-plugins - curl -SL https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-amd64 -o ~/.docker/cli-plugins/docker-buildx - chmod a+x ~/.docker/cli-plugins/docker-buildx - docker buildx create --name mybuilder --platform linux/arm64,linux/amd64,linux/amd64/v2,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6 - docker buildx use mybuilder - - - name: Set DOCKER_CLI_EXPERIMENTAL - run: echo "DOCKER_CLI_EXPERIMENTAL=enabled" >> $GITHUB_ENV - - - name: use mybuilder buildx - run: docker buildx use mybuilder - - - name: Build docker image - run: docker buildx build --platform=linux/amd64 -f docker/production.Dockerfile . -t tooljet/tj-osv:cypressplaform - - - name: Set up environment variables - run: | - echo "TOOLJET_HOST=http://localhost:3000" >> .env - echo "LOCKBOX_MASTER_KEY=cd97331a419c09387bef49787f7da8d2a81d30733f0de6bed23ad8356d2068b2" >> .env - echo "SECRET_KEY_BASE=7073b9a35a15dd20914ae17e36a693093f25b74b96517a5fec461fc901c51e011cd142c731bee48c5081ec8bac321c1f259ef097ef2a16f25df17a3798c03426" >> .env - echo "PG_DB=tooljet_development" >> .env - echo "PG_USER=postgres" >> .env - echo "PG_HOST=postgres" >> .env - echo "PG_PASS=postgres" >> .env - echo "PG_PORT=5432" >> .env - echo "ENABLE_TOOLJET_DB=true" >> .env - echo "TOOLJET_DB=tooljet_db" >> .env - echo "TOOLJET_DB_USER=postgres" >> .env - echo "TOOLJET_DB_HOST=postgres" >> .env - echo "TOOLJET_DB_PASS=postgres" >> .env - echo "PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj" >> .env - echo "PGRST_HOST=postgrest" >> .env - echo "PGRST_DB_URI=postgres://postgres:postgres@postgres/tooljet_db" >> .env - echo "SSO_GIT_OAUTH2_CLIENT_ID=dummy" >> .env - echo "SSO_GIT_OAUTH2_CLIENT_SECRET=dummy" >> .env - echo "SSO_GIT_OAUTH2_HOST=dummy" >> .env - echo "SSO_GOOGLE_OAUTH2_CLIENT_ID=dummy" >> .env - echo "SUB_PATH=/apps/tooljet/" >> .env - echo "NODE_ENV=production" >> .env - echo "SERVE_CLIENT=true" >> .env - echo "ENABLE_PRIVATE_APP_EMBED=true" >> .env - - - 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: Run docker-compose file - run: docker-compose up -d - - - name: Checking containers - run: docker ps -a - - - name: docker logs - run: sudo docker logs Tooljet-app - - - name: Wait for the server to be ready - run: | - timeout 1500 bash -c ' - until curl --silent --fail http://localhost:80/apps/tooljet/; do - 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: Create Cypress environment file id: create-json uses: jsdaniell/create-json@1.1.2 diff --git a/.github/workflows/cypress-marketplace.yml b/.github/workflows/cypress-marketplace.yml index 19368195a6..4d34523219 100644 --- a/.github/workflows/cypress-marketplace.yml +++ b/.github/workflows/cypress-marketplace.yml @@ -2,7 +2,7 @@ name: Cypress Marketplace on: pull_request_target: - types: [labeled, unlabeled, closed] + types: [labeled] workflow_dispatch: @@ -14,13 +14,9 @@ jobs: Cypress-Marketplace: runs-on: ubuntu-22.04 - if: | - github.event.action == 'labeled' && - ( - github.event.label.name == 'run-cypress' || - github.event.label.name == 'run-ce-cypress-marketplace' || - github.event.label.name == 'run-ee-cypress-marketplace' - ) + if: contains(github.event.pull_request.labels.*.name, 'run-cypress') || + contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-marketplace') || + contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-marketplace') strategy: matrix: @@ -44,7 +40,7 @@ jobs: mkdir -p ~/.docker/cli-plugins curl -SL https://github.com/docker/buildx/releases/download/v0.11.0/buildx-v0.11.0.linux-amd64 -o ~/.docker/cli-plugins/docker-buildx chmod a+x ~/.docker/cli-plugins/docker-buildx - docker buildx create --name mybuilder --platform linux/arm64,linux/amd64,linux/amd64/v2,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6 + docker buildx create --name mybuilder --platform linux/arm64,linux/amd64 docker buildx use mybuilder - name: Set DOCKER_CLI_EXPERIMENTAL @@ -189,7 +185,8 @@ jobs: Cypress-Marketplace-Subpath: runs-on: ubuntu-22.04 - if: ${{ github.event.action == 'labeled' && github.event.label.name == 'run-cypress-marketplace-subpath' }} + if: contains(github.event.pull_request.labels.*.name, 'run-cypress') || + contains(github.event.pull_request.labels.*.name, 'run-cypress-marketplace-subpath') steps: - name: Checkout diff --git a/.github/workflows/cypress-platform.yml b/.github/workflows/cypress-platform.yml index 3dbacafc06..0480db39f9 100644 --- a/.github/workflows/cypress-platform.yml +++ b/.github/workflows/cypress-platform.yml @@ -2,7 +2,7 @@ name: Cypress Platform on: pull_request_target: - types: [labeled, unlabeled, closed] + types: [labeled] workflow_dispatch: env: @@ -12,14 +12,9 @@ env: jobs: Cypress-Platform: runs-on: ubuntu-22.04 - if: | - github.event.action == 'labeled' && - ( - github.event.label.name == 'run-cypress' || - github.event.label.name == 'run-ce-cypress-platform' || - github.event.label.name == 'run-ee-cypress-platform' - ) - + if: contains(github.event.pull_request.labels.*.name, 'run-cypress') || + contains(github.event.pull_request.labels.*.name, 'run-ce-cypress-platform') || + contains(github.event.pull_request.labels.*.name, 'run-ee-cypress-platform') strategy: matrix: edition: >- diff --git a/.github/workflows/render-preview-deploy.yml b/.github/workflows/render-preview-deploy.yml index 203ee88150..d1ca481d02 100644 --- a/.github/workflows/render-preview-deploy.yml +++ b/.github/workflows/render-preview-deploy.yml @@ -12,7 +12,7 @@ permissions: jobs: -# Community Edition +# Community Edition CE create-ce-review-app: if: ${{ github.event.action == 'labeled' && (github.event.label.name == 'create-ce-review-app' || github.event.label.name == 'review-app') }} runs-on: ubuntu-latest @@ -72,7 +72,7 @@ jobs: "envVars": [ { "key": "PG_HOST", - "value": "${{ secrets.RENDER_PG_HOST }}" + "value": "localhost" }, { "key": "PG_PORT", @@ -80,11 +80,11 @@ jobs: }, { "key": "PG_USER", - "value": "${{ secrets.RENDER_PG_USER }}" + "value": "tooljet" }, { "key": "PG_PASS", - "value": "${{ secrets.RENDER_PG_PASS }}" + "value": "postgres" }, { "key": "PG_DB", @@ -96,15 +96,15 @@ jobs: }, { "key": "TOOLJET_DB_HOST", - "value": "${{ secrets.RENDER_PG_HOST }}" + "value": "localhost" }, { "key": "TOOLJET_DB_USER", - "value": "${{ secrets.RENDER_PG_USER }}" + "value": "tooljet" }, { "key": "TOOLJET_DB_PASS", - "value": "${{ secrets.RENDER_PG_PASS }}" + "value": "postgres" }, { "key": "TOOLJET_DB_PORT", @@ -116,7 +116,7 @@ jobs: }, { "key": "PGRST_DB_URI", - "value": "postgres://${{ secrets.RENDER_PG_USER }}:${{ secrets.RENDER_PG_PASS }}@${{ secrets.RENDER_PG_HOST }}/${{ env.PR_NUMBER }}-ce-tjdb" + "value": "postgres://tooljet:postgres@localhost/${{ env.PR_NUMBER }}-ce-tjdb" }, { "key": "PGRST_HOST", @@ -162,18 +162,6 @@ jobs: "key": "SMTP_PASSWORD", "value": "${{ secrets.RENDER_SMTP_PASSWORD }}" }, - { - "key": "TEMPORAL_SERVER_ADDRESS", - "value": "https://auto-setup-1-25-1.onrender.com" - }, - { - "key": "TEMPORAL_TASK_QUEUE_NAME_FOR_WORKFLOWS", - "value": "tooljet-ce-pr-${{ env.PR_NUMBER }}" - }, - { - "key": "TOOLJET_WORKFLOWS_TEMPORAL_NAMESPACE", - "value": "default" - }, { "key": "TOOLJET_MARKETPLACE_URL", "value": "${{ secrets.MARKETPLACE_BUCKET }}" @@ -424,7 +412,7 @@ jobs: "envVars": [ { "key": "PG_HOST", - "value": "${{ secrets.RENDER_PG_HOST }}" + "value": "localhost" }, { "key": "PG_PORT", @@ -432,11 +420,11 @@ jobs: }, { "key": "PG_USER", - "value": "${{ secrets.RENDER_PG_USER }}" + "value": "tooljet" }, { "key": "PG_PASS", - "value": "${{ secrets.RENDER_PG_PASS }}" + "value": "postgres" }, { "key": "PG_DB", @@ -448,15 +436,15 @@ jobs: }, { "key": "TOOLJET_DB_HOST", - "value": "${{ secrets.RENDER_PG_HOST }}" + "value": "localhost" }, { "key": "TOOLJET_DB_USER", - "value": "${{ secrets.RENDER_PG_USER }}" + "value": "tooljet" }, { "key": "TOOLJET_DB_PASS", - "value": "${{ secrets.RENDER_PG_PASS }}" + "value": "postgres" }, { "key": "TOOLJET_DB_PORT", @@ -468,7 +456,7 @@ jobs: }, { "key": "PGRST_DB_URI", - "value": "postgres://${{ secrets.RENDER_PG_USER }}:${{ secrets.RENDER_PG_PASS }}@${{ secrets.RENDER_PG_HOST }}/${{ env.PR_NUMBER }}-ee-tjdb" + "value": "postgres://tooljet:postgres@localhost/${{ env.PR_NUMBER }}-ee-tjdb" }, { "key": "PGRST_HOST", @@ -1124,4 +1112,3 @@ jobs: # } catch (e) { # console.log(e) # } - diff --git a/cypress-tests/cypress/commands/apiCommands.js b/cypress-tests/cypress/commands/apiCommands.js index b5d91ff88d..e9891c962e 100644 --- a/cypress-tests/cypress/commands/apiCommands.js +++ b/cypress-tests/cypress/commands/apiCommands.js @@ -192,6 +192,7 @@ Cypress.Commands.add("apiCreateWorkspace", (workspaceName, workspaceSlug) => { { log: false } ).then((response) => { expect(response.status).to.equal(201); + return response; }); }); }); diff --git a/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/permissions.cy.js b/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/permissions.cy.js index bdf3593e5c..22b6c6b6a5 100644 --- a/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/permissions.cy.js +++ b/cypress-tests/cypress/e2e/happyPath/platform/commonTestcases/workspace/groups/permissions.cy.js @@ -522,10 +522,8 @@ describe("Manage Groups", () => { commonSelectors.buttonSelector(exportAppModalText.exportSelectedVersion) ).click(); cy.exec("ls ./cypress/downloads/").then((result) => { - cy.log(result); const downloadedAppExportFileName = result.stdout.split("\n")[0]; exportedFilePath = `cypress/downloads/${downloadedAppExportFileName}`; - cy.log(exportedFilePath); cy.get(importSelectors.dropDownMenu).should("be.visible").click(); cy.get(importSelectors.importOptionInput).selectFile(exportedFilePath, { force: true, diff --git a/cypress-tests/cypress/e2e/happyPath/platform/externalApi/apiUsers.cy.js b/cypress-tests/cypress/e2e/happyPath/platform/externalApi/apiUsers.cy.js new file mode 100644 index 0000000000..b95970d349 --- /dev/null +++ b/cypress-tests/cypress/e2e/happyPath/platform/externalApi/apiUsers.cy.js @@ -0,0 +1,382 @@ +import { fake } from "Fixtures/fake"; +import { + createUser, getAllUsers, getUser, updateUser, createGroup, validateUserInGroup, updateUserRole, + getAllWorkspaces, replaceUserWorkspace, replaceUserWorkspacesRelations +} from 'Support/utils/api'; +import { groupsSelector } from "Selectors/manageGroups"; +import { commonSelectors } from 'Selectors/common'; +import { searchUser, navigateToManageUsers, logout, navigateToManageGroups } from 'Support/utils/common'; +describe("API Test", () => { + + const sanitize = (str) => str.toLowerCase().replace(/[^A-Za-z]/g, ""); + let userId; + let workspaceId; + const data = { + firstName: fake.firstName, + lastName: fake.lastName, + firstName1: fake.firstName, + lastName1: fake.lastName, + firstName2: fake.firstName, + lastName2: fake.lastName, + email: fake.email.toLowerCase().replaceAll("[^A-Za-z]", ""), + email1: fake.email.toLowerCase().replaceAll("[^A-Za-z]", ""), + email2: fake.email.toLowerCase().replaceAll("[^A-Za-z]", ""), + workspaceName: sanitize(fake.lastName), + workspaceSlug: sanitize(fake.lastName), + workspaceName1: sanitize(fake.firstName), + workspaceSlug1: sanitize(fake.firstName), + group1: sanitize(fake.firstName), + group2: sanitize(fake.firstName), + group3: sanitize(fake.firstName), + group4: sanitize(fake.firstName), + group5: sanitize(fake.firstName), + appName: fake.companyName + }; + + //user with all valid details + const userData = { + name: `${data.firstName} ${data.lastName}`, + email: data.email, + password: "password", + status: "active", + workspaces: [ + { + name: "My workspace", + status: "active", + groups: [ + { name: data.group1 }, + { name: data.group2 } + ] + }, + { + name: data.workspaceName, + status: "active", + role: "builder", + groups: [{ name: data.group3 }] + }, + { + name: data.workspaceName1, + status: "archived", + role: "admin", + groups: [{ name: data.group4 }] + } + ] + }; + + beforeEach(() => { + cy.defaultWorkspaceLogin(); + }); + + it("Create user with valid details", () => { + // create multiple groups in different workspaces + navigateToManageGroups(); + [data.group1, data.group2, data.group5].forEach(createGroup); + + //builder group + cy.get(groupsSelector.groupLink(data.group5)).click(); + cy.get(groupsSelector.permissionsLink).click(); + cy.get(groupsSelector.appsCreateCheck).check(); + + [ + { name: data.workspaceName, slug: data.workspaceSlug, group: data.group3 }, + { name: data.workspaceName1, slug: data.workspaceSlug1, group: data.group4 } + ].forEach(({ name, slug, group }) => { + cy.apiCreateWorkspace(name, slug); + cy.visit(slug); + navigateToManageGroups(); + createGroup(group); + }); + + // Added valid user and logged-in in the workpsace + cy.visit("/my-workspace"); + cy.wait(500); + createUser(userData).then((response) => { + expect(response.status).to.eq(201); + userId = response.body.id; + workspaceId = response.body.workspaces[0].id; + navigateToManageUsers(); + searchUser(data.email); + cy.contains("td", data.email) + .parent() + .within(() => { + cy.get("td small").should("have.text", "active"); + }); + + validateUserInGroup(data.email, "my-workspace", "end-user"); + validateUserInGroup(data.email, data.workspaceSlug, "builder"); + validateUserInGroup(data.email, data.workspaceSlug1, "admin", false); + cy.apiLogout(); + + cy.apiLogin(data.email, "password"); + cy.visit("/my-workspace"); + cy.get(commonSelectors.workspaceName).should("have.text", "My workspace"); + logout(); + + //Retrieve all users, a specific user by ID, and all workspaces + cy.defaultWorkspaceLogin(); + navigateToManageUsers(); + let number = 0; + cy.get('[data-cy="title-users-page"]').invoke('text').then((text) => { + number = parseInt(text.match(/\d+/)[0], 10); + }); + + getAllUsers().then((response) => { + expect(response.status).to.eq(200); + //expect(response.body.length).to.eq(number); //error due to removal of user from instance + }); + + getUser(userId).then((response) => { + expect(response.status).to.eq(200); + expect(response.body.name).to.eq(`${data.firstName} ${data.lastName}`); + }); + + getAllWorkspaces().then((response) => { + expect(response.status).to.eq(200); + }); + }); + }); + + it('Handles user creation errors', () => { + const invalidUserData = [ + { // Duplicate user + data: { ...userData }, + expectedStatus: 422, + expectedMessage: 'Already exists!' + }, + { // Invalid email and long password + data: { + ...userData, + name: `${data.firstName1} ${data.lastName1}`, + email: 'invalid-email', + password: 'a'.repeat(101) + }, + expectedStatus: 400, + expectedMessages: ['email must be an email', 'password must be shorter than or equal to 100 characters'] + }, + { // Non-existing group + data: { + ...userData, + name: `${data.firstName1} ${data.lastName1}`, + email: `${data.email1}`, + workspaces: [{ name: 'My workspace', status: 'active', groups: [{ name: 'NonExistingGroup' }] }] + }, + expectedStatus: 400, + expectedMessage: 'Group permission id or name not found:' + }, + { // Non-existing workspace + data: { + ...userData, + name: `${data.firstName1} ${data.lastName1}`, + email: `${data.email1}`, + workspaces: [{ name: 'NonExistingWorkspace', status: 'active' }] + }, + expectedStatus: 400, + expectedMessage: 'The workspaces id or name do not exist:' + } + ]; + + invalidUserData.forEach(({ data, expectedStatus, expectedMessages, expectedMessage }) => { + createUser(data).then((response) => { + expect(response.status).to.eq(expectedStatus); + if (expectedMessages) { + expectedMessages.forEach(msg => expect(response.body.message).to.include(msg)); + } else { + expect(response.body.message).to.include(expectedMessage); + } + }); + }); + //Conflict permission + const enduserData = { + ...userData, + name: `${data.firstName1} ${data.lastName1}`, + email: `${data.email1}`, + workspaces: [{ name: 'My workspace', status: 'active', groups: [{ name: data.group5 }] }] + } + createUser(enduserData).then((response) => { + expect(response.status).to.eq(400); + expect(response.body.message.title).to.include("Conflicting permissions"); + }) + }); + + it("Update user details and workspaces relations", () => { + const updatedUserData = { + name: `${data.firstName1} ${data.lastName1}`, + email: data.email1, + password: "updatedpassword" + } + updateUser(userId, updatedUserData).then((response) => { + expect(response.status).to.eq(200); + }) + cy.apiLogout(); + cy.apiLogin(updatedUserData.email, updatedUserData.password); + cy.apiLogout(); + + // Replace user workspaces relations + cy.apiLogin(); + validateUserInGroup(updatedUserData.email, "my-workspace", data.group2); + validateUserInGroup(updatedUserData.email, data.workspaceSlug, data.group3); + cy.visit(data.workspaceSlug1); + navigateToManageUsers(); + searchUser(updatedUserData.email); + cy.contains("td", updatedUserData.email); + + replaceUserWorkspacesRelations(userId, [ + { name: "My workspace", status: "active", role: "end-user", groups: [{ name: data.group1 }] }, + { name: data.workspaceName, status: "active", role: "builder", groups: [] } + ]).then((response) => { + expect(response.status).to.eq(200); + }); + navigateToManageUsers(); + validateUserInGroup(updatedUserData.email, "my-workspace", data.group2, false); + validateUserInGroup(updatedUserData.email, data.workspaceSlug, data.group3, false); + + cy.visit(data.workspaceSlug1); + navigateToManageUsers(); + searchUser(updatedUserData.email); + cy.get('[data-cy="text-no-result-found"]').contains("No result found"); + replaceUserWorkspacesRelations(userId, []).then((response) => { + expect(response.status).to.eq(200); + }); + cy.visit("my-workspace"); + navigateToManageUsers(); + searchUser(updatedUserData.email); + cy.get('[data-cy="text-no-result-found"]').contains("No result found"); + }); + + it("update user role", () => { + const userData2 = { + name: `${data.firstName} ${data.lastName}`, + email: data.email, + password: "password", + status: "active", + workspaces: [ + { + name: "My workspace", + status: "active" + } + ] + } + let userId1; + let workspaceId1; + createUser(userData2).then((response) => { + expect(response.status).to.eq(201); + userId1 = response.body.id; + workspaceId1 = response.body.workspaces[0].id; + //update role to builder and validate user in builder's group + updateUserRole(workspaceId1, { newRole: "builder", userId: userId1 }) + .then((response) => { + expect(response.status).to.eq(200); + }); + validateUserInGroup(userData2.email, "my-workspace", "builder"); + + //update role to end-user and validate user is removed from builder's group + updateUserRole(workspaceId1, { newRole: "end-user", userId: userId1 }) + .then((response) => { + expect(response.status).to.eq(200); + }); + validateUserInGroup(userData2.email, "my-workspace", data.group5, false); + + // update role to builders and validate app's owner role can't be updated + updateUserRole(workspaceId1, { newRole: "builder", userId: userId1 }) + .then((response) => { + expect(response.status).to.eq(200); + }); + cy.apiLogout(); + cy.apiLogin(userData2.email, userData2.password); + cy.apiCreateApp(data.appName); + cy.apiLogout(); + cy.defaultWorkspaceLogin(); + updateUserRole(workspaceId1, { newRole: "end-user", userId: userId1 }) + .then((response) => { + expect(response.status).to.eq(400); + expect(response.body.message.title).to.include("Can not change user role"); + }); + + }); + }); + const userData3 = { + name: `${data.firstName2} ${data.lastName2}`, + email: data.email2, + password: "password", + status: "active", + workspaces: [ + { + name: "My workspace", + status: "active", + groups: [ + { name: data.group1 }, + { name: data.group2 } + ] + }, + { + name: data.workspaceName, + status: "active", + role: "builder", + groups: [{ name: data.group3 }] + }, + { + name: data.workspaceName1, + status: "archived", + role: "admin", + groups: [{ name: data.group4 }] + } + ] + }; + it("Replace user workspace", () => { + let userId1, workspaceId1; + createUser(userData3).then((response) => { + expect(response.status).to.eq(201); + userId1 = response.body.id; + workspaceId1 = response.body.workspaces[0].id; + + // Helper function to replace user workspace and validate response + const replaceAndValidate = (payload, expectedStatus = 200) => { + return replaceUserWorkspace(userId1, workspaceId1, payload).then((response) => { + expect(response.status).to.eq(expectedStatus); + }); + }; + + // No change if empty request body + replaceAndValidate({}).then(() => { + validateUserInGroup(userData3.email, "my-workspace", data.group1); + validateUserInGroup(userData3.email, "my-workspace", data.group2); + }); + + // Archive the user and verify status + replaceAndValidate({ status: "archived" }).then(() => { + navigateToManageUsers(); + searchUser(userData3.email); + cy.contains("td", userData3.email) + .parent() + .within(() => { + cy.get("td small").should("have.text", "archived"); + }); + }); + + // Reactivate user and validate groups + replaceAndValidate({ status: "active" }).then(() => { + validateUserInGroup(userData3.email, "my-workspace", data.group1); + validateUserInGroup(userData3.email, "my-workspace", data.group2); + }); + + // Update groups and validate removal + replaceAndValidate({ groups: [{ name: data.group1 }] }).then(() => { + validateUserInGroup(userData3.email, "my-workspace", data.group2, false); + }); + + //Empty group array, user removed from groups + replaceAndValidate({ groups: [] }).then(() => { + validateUserInGroup(userData3.email, "my-workspace", data.group1, false); + }); + + //Conflict permission + replaceAndValidate({ groups: [{ name: data.group5 }] }, 400); + + //Add user in groups and validate + replaceAndValidate({ groups: [{ name: data.group1 }, { name: data.group2 }] }); + validateUserInGroup(userData3.email, "my-workspace", data.group1); + validateUserInGroup(userData3.email, "my-workspace", data.group2); + }); + }); +}); + diff --git a/cypress-tests/cypress/e2e/happyPath/platform/externalApi/appImportAndExportAPI.cy.js b/cypress-tests/cypress/e2e/happyPath/platform/externalApi/appImportAndExportAPI.cy.js new file mode 100644 index 0000000000..f2e522b22a --- /dev/null +++ b/cypress-tests/cypress/e2e/happyPath/platform/externalApi/appImportAndExportAPI.cy.js @@ -0,0 +1,160 @@ +import { importApp, exportApp, allAppsDetails } from 'Support/utils/api'; +import { fake } from "Fixtures/fake"; + +describe("Export and Import API ", () => { + + const sanitize = (str) => str.toLowerCase().replace(/[^A-Za-z]/g, ""); + const data = { + workspaceName: sanitize(fake.lastName), + workspaceSlug: sanitize(fake.lastName), + } + + const fixtureFiles = { + requestData: "templates/import_unnamed_file.json", + requestData2: "templates/import_named_file.json", + requestData3: "templates/three-versions.json", + }; + let requestData, requestData2, requestData3; + + beforeEach(() => { + cy.defaultWorkspaceLogin(); + + const fixturePromises = Object.entries(fixtureFiles).map(([key, file]) => + cy.fixture(file).then((data) => ({ key, data })) + ); + + // Assign loaded data to respective variables + return Promise.all(fixturePromises).then((results) => { + results.forEach(({ key, data }) => { + ({ requestData, requestData2, requestData3 }[key] = data); + }); + }); + + }); + it("Import App API", () => { + const workspaceId = Cypress.env("workspaceId"); + + importApp(workspaceId, requestData).then((response) => { + expect(response.status).to.eq(201); + expect(response.body.message).to.include("App imported successfully into workspace"); + }); + + //Invalid access token and workspace + importApp(workspaceId, requestData, { + Authorization: "Basic xyz", + "Content-Type": "application/json" + }).then((response) => { + expect(response.status).to.eq(403); + }); + + importApp(workspaceId, requestData, { + Authorization: "", + "Content-Type": "application/json" + }).then((response) => { + expect(response.status).to.eq(403); + }); + + importApp(`${workspaceId}ee`, requestData).then((response) => { + expect(response.status).to.eq(400); + }); + + //Import named file + importApp(workspaceId, requestData2).then((response) => { + expect(response.status).to.eq(201); + expect(response.body.message).to.include("App imported successfully into workspace"); + }); + cy.reload(); + cy.get('[data-cy="app_json-title"]').should("exist"); + + //duplicate app + importApp(workspaceId, requestData2).then((response) => { + expect(response.status).to.eq(409); + expect(response.body.message).to.include("App with app_json already exists in the workspace"); + }); + cy.deleteApp("app_json"); + cy.get('[data-cy="app_json-title"]').should("not.exist"); + + //Import app in another workpsace + let newWorkspaceId; + cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug).then((res) => { + newWorkspaceId = res.body.organization_id; + cy.visit(data.workspaceSlug); + + importApp(newWorkspaceId, requestData).then((response) => { + expect(response.status).to.eq(201); + expect(response.body.message).to.include("App imported successfully into workspace"); + }); + }); + }); + + it("Export App API", () => { + const workspaceId = Cypress.env("workspaceId"); + let appId; + importApp(workspaceId, requestData3).then((response) => { + expect(response.status).to.eq(201); + expect(response.body.message).to.include("App imported successfully into workspace"); + }).then(() => { + cy.get('[data-cy^="import-export-app"]') + .first() + .find('[data-cy="edit-button"]') + .click({ force: true }); + cy.skipWalkthrough(); + }); + + cy.get('[data-cy="left-sidebar-settings-button"]').click(); + cy.get('[data-cy="app-slug-input-field"]').invoke('val').then((value) => { + appId = value; + + //export last created version + exportApp(workspaceId, appId, "").then((response) => { + expect(response.status).to.eq(201); + expect(response.body.app[0].definition.appV2.appVersions.length).to.eq(1); + expect(response.body.app[0].definition.appV2.appVersions[0].name).to.eq("v3"); + }); + //export specific versions + exportApp(workspaceId, appId, "?appVersion=v2").then((response) => { + expect(response.status).to.eq(201); + expect(response.body.app[0].definition.appV2.appVersions.length).to.eq(1); + expect(response.body.app[0].definition.appV2.appVersions[0].name).to.eq("v2"); + }); + //export all versions + exportApp(workspaceId, appId, "?exportAllVersions=true").then((response) => { + expect(response.status).to.eq(201); + expect(response.body.app[0].definition.appV2.appVersions.length).to.eq(3); + }); + + //Invalid access token and workspace + /* exportApp(workspaceId, appId, "", { + Authorization: "", + "Content-Type": "application/json" + }).then((response) => { + expect(response.status).to.eq(403); + }); + + exportApp(workspaceId, appId, "", { + Authorization: "", + "Content-Type": "application/json" + }).then((response) => { + expect(response.status).to.eq(403); + }); + + exportApp(`${workspaceId}ee`, appId, "").then((response) => { + expect(response.status).to.eq(400); + }); + */ + //with and without TJDB -x.tooljet_database + exportApp(workspaceId, appId, "?exportTJDB=false").then((response) => { + expect(response.status).to.eq(201); + expect(response.body).not.to.have.property("tooljet_database"); + }); + exportApp(workspaceId, appId, "?exportTJDB=true").then((response) => { + expect(response.status).to.eq(201); + expect(response.body).to.have.property("tooljet_database"); + }); + }); + //All Apps details + allAppsDetails(workspaceId).then((response) => { + expect(response.status).to.eq(200); + }); + }); +}); \ No newline at end of file diff --git a/cypress-tests/cypress/fixtures/templates/import_named_file.json b/cypress-tests/cypress/fixtures/templates/import_named_file.json new file mode 100644 index 0000000000..0636a8b3b3 --- /dev/null +++ b/cypress-tests/cypress/fixtures/templates/import_named_file.json @@ -0,0 +1,1198 @@ +{ + "app": [ + { + "definition": { + "appV2": { + "type": "front-end", + "id": "8819afae-57b6-447d-93dd-6dc108169bfe", + "name": "AI powered code explainer", + "slug": "8819afae-57b6-447d-93dd-6dc108169bfe", + "isPublic": false, + "isMaintenanceOn": false, + "icon": "apps", + "organizationId": "a51da635-3a28-4b10-a6f4-7ba34e254987", + "currentVersionId": null, + "userId": "988bb9f5-e577-4065-8d3c-4fcf731ee15d", + "workflowApiToken": null, + "workflowEnabled": false, + "createdAt": "2025-02-27T07:28:52.129Z", + "creationMode": "DEFAULT", + "updatedAt": "2025-02-27T07:28:52.281Z", + "editingVersion": { + "id": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "name": "v1", + "definition": null, + "globalSettings": { + "hideHeader": true, + "appInMaintenance": false, + "canvasMaxWidth": 100, + "canvasMaxWidthType": "%", + "canvasMaxHeight": 2400, + "canvasBackgroundColor": "#edeff5", + "backgroundFxQuery": "", + "appMode": "auto" + }, + "pageSettings": { + "properties": { + "disableMenu": { + "value": "{{true}}", + "fxActive": false + } + } + }, + "showViewerNavigation": false, + "homePageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "appId": "8819afae-57b6-447d-93dd-6dc108169bfe", + "currentEnvironmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "promotedFrom": null, + "createdAt": "2025-02-27T07:28:52.144Z", + "updatedAt": "2025-02-27T07:28:52.274Z" + }, + "components": [ + { + "id": "7bf37542-4eaa-42d8-9827-1cf1f1649791", + "name": "container1", + "type": "Container", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": null, + "properties": {}, + "general": {}, + "styles": { + "backgroundColor": { + "value": "#ffffffff" + }, + "borderRadius": { + "value": "10" + }, + "borderColor": { + "value": "#ffffff00", + "fxActive": false + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "7367ab91-9541-4bd9-96f7-32da8bb61cf5", + "type": "desktop", + "top": 20, + "left": 1, + "width": 41, + "height": 70, + "componentId": "7bf37542-4eaa-42d8-9827-1cf1f1649791", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "9b1d3bec-c586-4f2b-acdf-09cea7addecc", + "name": "text1", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "7bf37542-4eaa-42d8-9827-1cf1f1649791", + "properties": { + "text": { + "value": "B R A N D" + } + }, + "general": {}, + "styles": { + "textColor": { + "value": "#000", + "fxActive": false + }, + "textSize": { + "value": "{{24}}" + }, + "fontWeight": { + "value": "bold" + }, + "boxShadow": { + "value": "0px 0px 0px 0px #00000040" + }, + "isScrollRequired": { + "value": "disabled" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "8c07e506-b1f5-4715-ab02-718fcce9295b", + "type": "desktop", + "top": 10, + "left": 1, + "width": 6, + "height": 40, + "componentId": "9b1d3bec-c586-4f2b-acdf-09cea7addecc", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "38100944-4325-49b7-8c70-de75cf5ce63d", + "name": "text2", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "7bf37542-4eaa-42d8-9827-1cf1f1649791", + "properties": { + "text": { + "value": "
AI Code Explainer
" + } + }, + "general": {}, + "styles": { + "textColor": { + "value": "#000", + "fxActive": false + }, + "textSize": { + "value": "{{20}}" + }, + "textAlign": { + "value": "right" + }, + "boxShadow": { + "value": "0px 0px 0px 0px #00000040" + }, + "isScrollRequired": { + "value": "disabled" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "129e63b6-9456-4cb7-94b0-7379743fec88", + "type": "desktop", + "top": 10, + "left": 25, + "width": 17, + "height": 40, + "componentId": "38100944-4325-49b7-8c70-de75cf5ce63d", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "name": "container2", + "type": "Container", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": null, + "properties": {}, + "general": {}, + "styles": { + "borderRadius": { + "value": "10" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "14b7706c-cebf-45dc-a555-3a60fdf01f3b", + "type": "desktop", + "top": 110, + "left": 1, + "width": 41, + "height": 620, + "componentId": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "ef46f35d-bf64-4ea0-8c9b-c525b87d6120", + "type": "mobile", + "top": 110, + "left": 1, + "width": 5, + "height": 200, + "componentId": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "fbdab782-4a3b-4811-9f43-35f6dfae8735", + "name": "text3", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "text": { + "value": "Code to be explained" + } + }, + "general": {}, + "styles": { + "textSize": { + "value": "24" + }, + "fontWeight": { + "value": "bold" + }, + "isScrollRequired": { + "value": "disabled" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "cfc25680-87fe-45d1-8431-f009ba351ae2", + "type": "desktop", + "top": 20, + "left": 1, + "width": 20, + "height": 40, + "componentId": "fbdab782-4a3b-4811-9f43-35f6dfae8735", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "bbb13f33-25ee-4c97-8c08-7d7df99ab431", + "type": "mobile", + "top": 20, + "left": 9, + "width": 13.953488372093023, + "height": 40, + "componentId": "fbdab782-4a3b-4811-9f43-35f6dfae8735", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "dca350e6-c9f8-44aa-94d5-e6245cfb0ae2", + "name": "dropdown1", + "type": "DropDown", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "label": { + "value": "" + }, + "value": { + "value": "" + }, + "values": { + "value": "{{queries.32ff6874-7da0-4b88-ae05-3c9cda4a07dc.data.models.map(item => item.name)}}" + }, + "display_values": { + "value": "{{queries.32ff6874-7da0-4b88-ae05-3c9cda4a07dc.data.models.map(item => item.displayName)}}" + }, + "loadingState": { + "value": "{{queries.32ff6874-7da0-4b88-ae05-3c9cda4a07dc.isLoading}}", + "fxActive": true + }, + "placeholder": { + "value": "Select a model" + } + }, + "general": {}, + "styles": { + "borderRadius": { + "value": "5" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.267Z", + "layouts": [ + { + "id": "91cae02e-6d00-48ad-9750-1ae74bc9fd7f", + "type": "mobile", + "top": 10, + "left": 27, + "width": 18.6046511627907, + "height": 30, + "componentId": "dca350e6-c9f8-44aa-94d5-e6245cfb0ae2", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "bb56cbd1-57f7-4917-8a32-046a8e77ed33", + "type": "desktop", + "top": 480, + "left": 1, + "width": 20, + "height": 40, + "componentId": "dca350e6-c9f8-44aa-94d5-e6245cfb0ae2", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "98a7f66e-d446-4be5-b2e8-6bde808e9461", + "name": "textarea1", + "type": "TextArea", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "value": { + "value": "function addNumbers(a, b) {\n return a + b;\n}\n\nconst sum = addNumbers(5, 3);\nconsole.log(sum);" + }, + "placeholder": { + "value": "function addNumbers(a, b) {\n return a + b;\n}\n\nconst sum = addNumbers(5, 3);\nconsole.log(sum);" + } + }, + "general": {}, + "styles": { + "borderRadius": { + "value": "{{5}}" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "db411aca-2e7e-46ae-8bf6-75f664a636ea", + "type": "mobile", + "top": 100, + "left": 3, + "width": 13.953488372093023, + "height": 100, + "componentId": "98a7f66e-d446-4be5-b2e8-6bde808e9461", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "abdc0362-e37b-48d6-9cad-ccbdfcf6fd55", + "type": "desktop", + "top": 70, + "left": 1, + "width": 20, + "height": 270, + "componentId": "98a7f66e-d446-4be5-b2e8-6bde808e9461", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "37fbb9ed-5ac6-439b-82cb-35e276c89f49", + "name": "button1", + "type": "Button", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "text": { + "value": "Generate explanation >>" + }, + "loadingState": { + "value": "{{false}}", + "fxActive": false + }, + "disabledState": { + "value": "{{components.dca350e6-c9f8-44aa-94d5-e6245cfb0ae2.value == undefined || queries.getCodeExplanation.isLoading}}", + "fxActive": true + } + }, + "general": {}, + "styles": { + "backgroundColor": { + "value": "#ffffff00" + }, + "textColor": { + "value": "#3e63ddff" + }, + "loaderColor": { + "value": "#3e63ddff" + }, + "borderRadius": { + "value": "{{5}}" + }, + "borderColor": { + "value": "#3e63ddff" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.267Z", + "layouts": [ + { + "id": "c110426c-5994-4d04-901d-883aafb9d2eb", + "type": "mobile", + "top": 420, + "left": 7, + "width": 6.976744186046512, + "height": 30, + "componentId": "37fbb9ed-5ac6-439b-82cb-35e276c89f49", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "a6a6b92e-0984-4e21-87fc-462a307e06dd", + "type": "desktop", + "top": 550, + "left": 1, + "width": 20, + "height": 40, + "componentId": "37fbb9ed-5ac6-439b-82cb-35e276c89f49", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "b56cb989-9b4f-4dcf-a6c4-70dcfe6aac1a", + "name": "dropdown2", + "type": "DropDown", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "values": { + "value": "{{[\n \"\",\n \"C#\",\n \"C++\",\n \"Dart\",\n \"Elixir\",\n \"Erlang\",\n \"F#\",\n \"Go\",\n \"Groovy\",\n \"Haskell\",\n \"Java\",\n \"JavaScript\",\n \"Kotlin\",\n \"Lua\",\n \"MATLAB\",\n \"Objective-C\",\n \"Perl\",\n \"PHP\",\n \"Python\",\n \"R\",\n \"Ruby\",\n \"Rust\",\n \"Scala\",\n \"Shell\",\n \"SQL\",\n \"Swift\",\n \"TypeScript\"\n]}}" + }, + "display_values": { + "value": "{{[\n \"Any language\",\n \"C#\",\n \"C++\",\n \"Dart\",\n \"Elixir\",\n \"Erlang\",\n \"F#\",\n \"Go\",\n \"Groovy\",\n \"Haskell\",\n \"Java\",\n \"JavaScript\",\n \"Kotlin\",\n \"Lua\",\n \"MATLAB\",\n \"Objective-C\",\n \"Perl\",\n \"PHP\",\n \"Python\",\n \"R\",\n \"Ruby\",\n \"Rust\",\n \"Scala\",\n \"Shell\",\n \"SQL\",\n \"Swift\",\n \"TypeScript\"\n]}}" + }, + "value": { + "value": "" + }, + "placeholder": { + "value": "Select a language" + }, + "label": { + "value": "" + } + }, + "general": {}, + "styles": {}, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "553e50a3-c9d4-4ae7-9b8d-da129cb2f32d", + "type": "mobile", + "top": 420, + "left": 2, + "width": 8, + "height": 30, + "componentId": "b56cb989-9b4f-4dcf-a6c4-70dcfe6aac1a", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "abeda4d6-0111-4b9a-bfb1-234c986ee777", + "type": "desktop", + "top": 390, + "left": 1, + "width": 20, + "height": 40, + "componentId": "b56cb989-9b4f-4dcf-a6c4-70dcfe6aac1a", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "7112d3b6-f7d5-4da8-84ad-f2db9ab962d8", + "name": "text6", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "text": { + "value": "Language" + } + }, + "general": {}, + "styles": { + "fontWeight": { + "value": "bold" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "3b6ce6c5-bb8b-4145-991b-b4dc659ac9ae", + "type": "desktop", + "top": 360, + "left": 1, + "width": 14, + "height": 30, + "componentId": "7112d3b6-f7d5-4da8-84ad-f2db9ab962d8", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "d907a75f-162c-4e89-8bef-8ad4a6b10f6a", + "type": "mobile", + "top": 70, + "left": 4, + "width": 13.953488372093023, + "height": 40, + "componentId": "7112d3b6-f7d5-4da8-84ad-f2db9ab962d8", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "052d73d1-c415-4720-8963-36c94ce54b19", + "name": "text7", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "text": { + "value": "{{`
${queries.getCodeExplanation.data.candidates ? queries.getCodeExplanation.data.candidates[0].content.parts[0].text : \"\"}
`}}" + }, + "textFormat": { + "value": "html" + }, + "loadingState": { + "fxActive": true, + "value": "{{queries.5774aa01-0931-4036-8bfa-4d12e0b6bc8b.isLoading}}" + } + }, + "general": {}, + "styles": { + "borderColor": { + "value": "#ddddddff" + }, + "borderRadius": { + "value": "5" + }, + "verticalAlignment": { + "value": "top" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.267Z", + "layouts": [ + { + "id": "388a36e0-95ac-49f3-a97b-ad413efafb3a", + "type": "desktop", + "top": 70, + "left": 22, + "width": 20, + "height": 520, + "componentId": "052d73d1-c415-4720-8963-36c94ce54b19", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "1f2da6ab-3493-4ace-b5ae-ceadbd3e2fb0", + "type": "mobile", + "top": 290, + "left": 23, + "width": 6, + "height": 40, + "componentId": "052d73d1-c415-4720-8963-36c94ce54b19", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "3c5278e8-8cc5-442a-bc70-19d4cd72cec7", + "name": "text8", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "text": { + "value": "Gemini Model" + } + }, + "general": {}, + "styles": { + "fontWeight": { + "value": "bold" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "e41fd57d-29e6-49e2-b3ee-75b3769f6d27", + "type": "mobile", + "top": 70, + "left": 4, + "width": 13.953488372093023, + "height": 40, + "componentId": "3c5278e8-8cc5-442a-bc70-19d4cd72cec7", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "7a1d68a9-e9f5-496e-9947-3d6e12c55b0c", + "type": "desktop", + "top": 450, + "left": 1, + "width": 14, + "height": 30, + "componentId": "3c5278e8-8cc5-442a-bc70-19d4cd72cec7", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "521f0268-02d8-4571-9efe-030c9816bdea", + "name": "text9", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "text": { + "value": "Explanation" + } + }, + "general": {}, + "styles": { + "textSize": { + "value": "24" + }, + "fontWeight": { + "value": "bold" + }, + "isScrollRequired": { + "value": "disabled" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "81f9d6a1-90c4-422c-8602-1675a76f6de4", + "type": "desktop", + "top": 20, + "left": 22, + "width": 20, + "height": 40, + "componentId": "521f0268-02d8-4571-9efe-030c9816bdea", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "da2abfa1-769b-4784-87fb-5020e6610fed", + "type": "mobile", + "top": 20, + "left": 9, + "width": 13.953488372093023, + "height": 40, + "componentId": "521f0268-02d8-4571-9efe-030c9816bdea", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + } + ], + "pages": [ + { + "id": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "name": "Home", + "handle": "home", + "index": 1, + "disabled": false, + "hidden": false, + "icon": null, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.366Z", + "autoComputeLayout": true, + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "pageGroupIndex": 1, + "pageGroupId": null, + "isPageGroup": false + } + ], + "events": [ + { + "id": "9417716e-b415-4532-aea4-8a2afa224f10", + "name": "onClick", + "index": 0, + "event": { + "eventId": "onClick", + "message": "Hello world!", + "queryId": "5774aa01-0931-4036-8bfa-4d12e0b6bc8b", + "actionId": "run-query", + "alertType": "info", + "queryName": "getCodeExplanation", + "parameters": {} + }, + "sourceId": "37fbb9ed-5ac6-439b-82cb-35e276c89f49", + "target": "component", + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.260Z" + } + ], + "dataQueries": [ + { + "id": "5774aa01-0931-4036-8bfa-4d12e0b6bc8b", + "name": "getCodeExplanation", + "options": { + "method": "post", + "url": "https://generativelanguage.googleapis.com/v1beta/{{components.dropdown1.value}}:generateContent", + "url_params": [ + [ + "key", + "{{constants.GEMINI_API_KEY}}" + ], + [ + "", + "" + ] + ], + "headers": [ + [ + "Content-Type", + "application/json" + ], + [ + "", + "" + ] + ], + "body": [ + [ + "", + "" + ] + ], + "json_body": "{\n \"contents\": [\n {\n \"parts\": [\n {\n \"text\": \"{{components.textarea1.value.replaceAll('\\n','\\\\n')}} - Generate a point-wise line by line explanation of this code in html formatting only. Keep only the explanation, and nothing else. {{components.dropdown2.value ? `The code is in ${components.dropdown2.value} language.` : 'Also identify the language of the code.'}}\"\n }\n ]\n }\n ]\n}", + "body_toggle": true, + "transformationLanguage": "javascript", + "enableTransformation": false, + "arrayValuesChanged": false, + "transformation": "// write your code here\n// return value will be set as data and the original data will be available as rawData\nreturn data.filter(row => row.amount > 1000);\n " + }, + "dataSourceId": "489072da-3239-4bd5-91b9-dee5f5da5335", + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "32ff6874-7da0-4b88-ae05-3c9cda4a07dc", + "name": "getGeminiModels", + "options": { + "method": "get", + "url": "https://generativelanguage.googleapis.com/v1beta/models?key={{constants.GEMINI_API_KEY}}", + "url_params": [ + [ + "", + "" + ] + ], + "headers": [ + [ + "", + "" + ] + ], + "body": [ + [ + "", + "" + ] + ], + "json_body": null, + "body_toggle": false, + "transformationLanguage": "javascript", + "enableTransformation": false, + "runOnPageLoad": true + }, + "dataSourceId": "489072da-3239-4bd5-91b9-dee5f5da5335", + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.983Z" + } + ], + "dataSources": [ + { + "id": "489072da-3239-4bd5-91b9-dee5f5da5335", + "name": "restapidefault", + "kind": "restapi", + "type": "static", + "pluginId": null, + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "organizationId": null, + "scope": "local", + "createdAt": "2025-02-27T07:28:52.153Z", + "updatedAt": "2025-02-27T07:28:52.153Z" + }, + { + "id": "c462a40f-c7fa-4d55-98fe-9bc445271cab", + "name": "runjsdefault", + "kind": "runjs", + "type": "static", + "pluginId": null, + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "organizationId": null, + "scope": "local", + "createdAt": "2025-02-27T07:28:52.163Z", + "updatedAt": "2025-02-27T07:28:52.163Z" + }, + { + "id": "cc0b5feb-29ea-47c0-9a9a-62c0e0b89ccb", + "name": "runpydefault", + "kind": "runpy", + "type": "static", + "pluginId": null, + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "organizationId": null, + "scope": "local", + "createdAt": "2025-02-27T07:28:52.170Z", + "updatedAt": "2025-02-27T07:28:52.170Z" + }, + { + "id": "907dde15-1ac2-4f53-ba72-8e4e1d066f0e", + "name": "tooljetdbdefault", + "kind": "tooljetdb", + "type": "static", + "pluginId": null, + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "organizationId": null, + "scope": "local", + "createdAt": "2025-02-27T07:28:52.176Z", + "updatedAt": "2025-02-27T07:28:52.176Z" + }, + { + "id": "66ad4e35-f981-47a6-99cd-31e9e7bbd9b3", + "name": "workflowsdefault", + "kind": "workflows", + "type": "static", + "pluginId": null, + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "organizationId": null, + "scope": "local", + "createdAt": "2025-02-27T07:28:52.183Z", + "updatedAt": "2025-02-27T07:28:52.183Z" + } + ], + "appVersions": [ + { + "id": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "name": "v1", + "definition": null, + "globalSettings": { + "hideHeader": true, + "appInMaintenance": false, + "canvasMaxWidth": 100, + "canvasMaxWidthType": "%", + "canvasMaxHeight": 2400, + "canvasBackgroundColor": "#edeff5", + "backgroundFxQuery": "", + "appMode": "auto" + }, + "pageSettings": { + "properties": { + "disableMenu": { + "value": "{{true}}", + "fxActive": false + } + } + }, + "showViewerNavigation": false, + "homePageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "appId": "8819afae-57b6-447d-93dd-6dc108169bfe", + "currentEnvironmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "promotedFrom": null, + "createdAt": "2025-02-27T07:28:52.144Z", + "updatedAt": "2025-02-27T07:28:52.274Z" + } + ], + "appEnvironments": [ + { + "id": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "organizationId": "a51da635-3a28-4b10-a6f4-7ba34e254987", + "name": "development", + "isDefault": false, + "priority": 1, + "enabled": true, + "createdAt": "2025-02-27T07:28:36.425Z", + "updatedAt": "2025-02-27T07:28:36.425Z" + }, + { + "id": "ed48a4ab-ef5c-47c0-b99c-453fec90b9ec", + "organizationId": "a51da635-3a28-4b10-a6f4-7ba34e254987", + "name": "staging", + "isDefault": false, + "priority": 2, + "enabled": true, + "createdAt": "2025-02-27T07:28:36.425Z", + "updatedAt": "2025-02-27T07:28:36.425Z" + }, + { + "id": "eb006618-493c-48ac-8a4d-e80d208d29de", + "organizationId": "a51da635-3a28-4b10-a6f4-7ba34e254987", + "name": "production", + "isDefault": true, + "priority": 3, + "enabled": true, + "createdAt": "2025-02-27T07:28:36.425Z", + "updatedAt": "2025-02-27T07:28:36.425Z" + } + ], + "dataSourceOptions": [ + { + "id": "98e3239b-e54b-4b59-992b-d9bbfb68d1e6", + "dataSourceId": "489072da-3239-4bd5-91b9-dee5f5da5335", + "environmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "options": null, + "createdAt": "2025-02-27T07:28:52.159Z", + "updatedAt": "2025-02-27T07:28:52.159Z" + }, + { + "id": "c997ee43-2f17-46aa-bc35-32af668d546b", + "dataSourceId": "489072da-3239-4bd5-91b9-dee5f5da5335", + "environmentId": "ed48a4ab-ef5c-47c0-b99c-453fec90b9ec", + "options": null, + "createdAt": "2025-02-27T07:28:52.159Z", + "updatedAt": "2025-02-27T07:28:52.159Z" + }, + { + "id": "01bbd244-59c9-4965-8024-401c8f1961fd", + "dataSourceId": "489072da-3239-4bd5-91b9-dee5f5da5335", + "environmentId": "eb006618-493c-48ac-8a4d-e80d208d29de", + "options": null, + "createdAt": "2025-02-27T07:28:52.159Z", + "updatedAt": "2025-02-27T07:28:52.159Z" + }, + { + "id": "8a8096f7-6b6f-49ca-95de-596c5670c832", + "dataSourceId": "c462a40f-c7fa-4d55-98fe-9bc445271cab", + "environmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "options": null, + "createdAt": "2025-02-27T07:28:52.167Z", + "updatedAt": "2025-02-27T07:28:52.167Z" + }, + { + "id": "1e2dcc6d-8944-4b5b-abd4-72f7201bf657", + "dataSourceId": "c462a40f-c7fa-4d55-98fe-9bc445271cab", + "environmentId": "ed48a4ab-ef5c-47c0-b99c-453fec90b9ec", + "options": null, + "createdAt": "2025-02-27T07:28:52.167Z", + "updatedAt": "2025-02-27T07:28:52.167Z" + }, + { + "id": "24bfe83d-b2d3-4bf0-8730-1bd14d96cf7a", + "dataSourceId": "c462a40f-c7fa-4d55-98fe-9bc445271cab", + "environmentId": "eb006618-493c-48ac-8a4d-e80d208d29de", + "options": null, + "createdAt": "2025-02-27T07:28:52.167Z", + "updatedAt": "2025-02-27T07:28:52.167Z" + }, + { + "id": "44600a77-04bf-4b30-8613-bd7a7bff6508", + "dataSourceId": "cc0b5feb-29ea-47c0-9a9a-62c0e0b89ccb", + "environmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "options": null, + "createdAt": "2025-02-27T07:28:52.174Z", + "updatedAt": "2025-02-27T07:28:52.174Z" + }, + { + "id": "b70c436e-70e5-48d3-84d2-ca2c784c7425", + "dataSourceId": "cc0b5feb-29ea-47c0-9a9a-62c0e0b89ccb", + "environmentId": "ed48a4ab-ef5c-47c0-b99c-453fec90b9ec", + "options": null, + "createdAt": "2025-02-27T07:28:52.174Z", + "updatedAt": "2025-02-27T07:28:52.174Z" + }, + { + "id": "7bd1351e-61b9-4ba6-9e57-8eca1a3a0df3", + "dataSourceId": "cc0b5feb-29ea-47c0-9a9a-62c0e0b89ccb", + "environmentId": "eb006618-493c-48ac-8a4d-e80d208d29de", + "options": null, + "createdAt": "2025-02-27T07:28:52.174Z", + "updatedAt": "2025-02-27T07:28:52.174Z" + }, + { + "id": "f8268c18-8453-48ac-acf7-46c2d0c75c75", + "dataSourceId": "907dde15-1ac2-4f53-ba72-8e4e1d066f0e", + "environmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "options": null, + "createdAt": "2025-02-27T07:28:52.181Z", + "updatedAt": "2025-02-27T07:28:52.181Z" + }, + { + "id": "cd59c697-6ac2-4594-b8f6-493676e8b3c7", + "dataSourceId": "907dde15-1ac2-4f53-ba72-8e4e1d066f0e", + "environmentId": "ed48a4ab-ef5c-47c0-b99c-453fec90b9ec", + "options": null, + "createdAt": "2025-02-27T07:28:52.181Z", + "updatedAt": "2025-02-27T07:28:52.181Z" + }, + { + "id": "7270ef0a-f6d6-498e-9959-4b646a30d5d1", + "dataSourceId": "907dde15-1ac2-4f53-ba72-8e4e1d066f0e", + "environmentId": "eb006618-493c-48ac-8a4d-e80d208d29de", + "options": null, + "createdAt": "2025-02-27T07:28:52.181Z", + "updatedAt": "2025-02-27T07:28:52.181Z" + }, + { + "id": "fe4824d5-57fa-42dc-9812-4af634737898", + "dataSourceId": "66ad4e35-f981-47a6-99cd-31e9e7bbd9b3", + "environmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "options": null, + "createdAt": "2025-02-27T07:28:52.189Z", + "updatedAt": "2025-02-27T07:28:52.189Z" + }, + { + "id": "521a6d91-484b-45bc-af8f-aaceb0dc515c", + "dataSourceId": "66ad4e35-f981-47a6-99cd-31e9e7bbd9b3", + "environmentId": "ed48a4ab-ef5c-47c0-b99c-453fec90b9ec", + "options": null, + "createdAt": "2025-02-27T07:28:52.189Z", + "updatedAt": "2025-02-27T07:28:52.189Z" + }, + { + "id": "f5955bf2-c148-4544-acd9-a9a92a943e5b", + "dataSourceId": "66ad4e35-f981-47a6-99cd-31e9e7bbd9b3", + "environmentId": "eb006618-493c-48ac-8a4d-e80d208d29de", + "options": null, + "createdAt": "2025-02-27T07:28:52.189Z", + "updatedAt": "2025-02-27T07:28:52.189Z" + } + ], + "schemaDetails": { + "multiPages": true, + "multiEnv": true, + "globalDataSources": true + } + } + } + } + ], + "tooljet_version": "3.5.3-ee-lts", + "appName": "app_json" +} \ No newline at end of file diff --git a/cypress-tests/cypress/fixtures/templates/import_unnamed_file.json b/cypress-tests/cypress/fixtures/templates/import_unnamed_file.json new file mode 100644 index 0000000000..93c2501a51 --- /dev/null +++ b/cypress-tests/cypress/fixtures/templates/import_unnamed_file.json @@ -0,0 +1,1197 @@ +{ + "app": [ + { + "definition": { + "appV2": { + "type": "front-end", + "id": "8819afae-57b6-447d-93dd-6dc108169bfe", + "name": "AI powered code explainer", + "slug": "8819afae-57b6-447d-93dd-6dc108169bfe", + "isPublic": false, + "isMaintenanceOn": false, + "icon": "apps", + "organizationId": "a51da635-3a28-4b10-a6f4-7ba34e254987", + "currentVersionId": null, + "userId": "988bb9f5-e577-4065-8d3c-4fcf731ee15d", + "workflowApiToken": null, + "workflowEnabled": false, + "createdAt": "2025-02-27T07:28:52.129Z", + "creationMode": "DEFAULT", + "updatedAt": "2025-02-27T07:28:52.281Z", + "editingVersion": { + "id": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "name": "v1", + "definition": null, + "globalSettings": { + "hideHeader": true, + "appInMaintenance": false, + "canvasMaxWidth": 100, + "canvasMaxWidthType": "%", + "canvasMaxHeight": 2400, + "canvasBackgroundColor": "#edeff5", + "backgroundFxQuery": "", + "appMode": "auto" + }, + "pageSettings": { + "properties": { + "disableMenu": { + "value": "{{true}}", + "fxActive": false + } + } + }, + "showViewerNavigation": false, + "homePageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "appId": "8819afae-57b6-447d-93dd-6dc108169bfe", + "currentEnvironmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "promotedFrom": null, + "createdAt": "2025-02-27T07:28:52.144Z", + "updatedAt": "2025-02-27T07:28:52.274Z" + }, + "components": [ + { + "id": "7bf37542-4eaa-42d8-9827-1cf1f1649791", + "name": "container1", + "type": "Container", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": null, + "properties": {}, + "general": {}, + "styles": { + "backgroundColor": { + "value": "#ffffffff" + }, + "borderRadius": { + "value": "10" + }, + "borderColor": { + "value": "#ffffff00", + "fxActive": false + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "7367ab91-9541-4bd9-96f7-32da8bb61cf5", + "type": "desktop", + "top": 20, + "left": 1, + "width": 41, + "height": 70, + "componentId": "7bf37542-4eaa-42d8-9827-1cf1f1649791", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "9b1d3bec-c586-4f2b-acdf-09cea7addecc", + "name": "text1", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "7bf37542-4eaa-42d8-9827-1cf1f1649791", + "properties": { + "text": { + "value": "B R A N D" + } + }, + "general": {}, + "styles": { + "textColor": { + "value": "#000", + "fxActive": false + }, + "textSize": { + "value": "{{24}}" + }, + "fontWeight": { + "value": "bold" + }, + "boxShadow": { + "value": "0px 0px 0px 0px #00000040" + }, + "isScrollRequired": { + "value": "disabled" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "8c07e506-b1f5-4715-ab02-718fcce9295b", + "type": "desktop", + "top": 10, + "left": 1, + "width": 6, + "height": 40, + "componentId": "9b1d3bec-c586-4f2b-acdf-09cea7addecc", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "38100944-4325-49b7-8c70-de75cf5ce63d", + "name": "text2", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "7bf37542-4eaa-42d8-9827-1cf1f1649791", + "properties": { + "text": { + "value": "
AI Code Explainer
" + } + }, + "general": {}, + "styles": { + "textColor": { + "value": "#000", + "fxActive": false + }, + "textSize": { + "value": "{{20}}" + }, + "textAlign": { + "value": "right" + }, + "boxShadow": { + "value": "0px 0px 0px 0px #00000040" + }, + "isScrollRequired": { + "value": "disabled" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "129e63b6-9456-4cb7-94b0-7379743fec88", + "type": "desktop", + "top": 10, + "left": 25, + "width": 17, + "height": 40, + "componentId": "38100944-4325-49b7-8c70-de75cf5ce63d", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "name": "container2", + "type": "Container", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": null, + "properties": {}, + "general": {}, + "styles": { + "borderRadius": { + "value": "10" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "14b7706c-cebf-45dc-a555-3a60fdf01f3b", + "type": "desktop", + "top": 110, + "left": 1, + "width": 41, + "height": 620, + "componentId": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "ef46f35d-bf64-4ea0-8c9b-c525b87d6120", + "type": "mobile", + "top": 110, + "left": 1, + "width": 5, + "height": 200, + "componentId": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "fbdab782-4a3b-4811-9f43-35f6dfae8735", + "name": "text3", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "text": { + "value": "Code to be explained" + } + }, + "general": {}, + "styles": { + "textSize": { + "value": "24" + }, + "fontWeight": { + "value": "bold" + }, + "isScrollRequired": { + "value": "disabled" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "cfc25680-87fe-45d1-8431-f009ba351ae2", + "type": "desktop", + "top": 20, + "left": 1, + "width": 20, + "height": 40, + "componentId": "fbdab782-4a3b-4811-9f43-35f6dfae8735", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "bbb13f33-25ee-4c97-8c08-7d7df99ab431", + "type": "mobile", + "top": 20, + "left": 9, + "width": 13.953488372093023, + "height": 40, + "componentId": "fbdab782-4a3b-4811-9f43-35f6dfae8735", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "dca350e6-c9f8-44aa-94d5-e6245cfb0ae2", + "name": "dropdown1", + "type": "DropDown", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "label": { + "value": "" + }, + "value": { + "value": "" + }, + "values": { + "value": "{{queries.32ff6874-7da0-4b88-ae05-3c9cda4a07dc.data.models.map(item => item.name)}}" + }, + "display_values": { + "value": "{{queries.32ff6874-7da0-4b88-ae05-3c9cda4a07dc.data.models.map(item => item.displayName)}}" + }, + "loadingState": { + "value": "{{queries.32ff6874-7da0-4b88-ae05-3c9cda4a07dc.isLoading}}", + "fxActive": true + }, + "placeholder": { + "value": "Select a model" + } + }, + "general": {}, + "styles": { + "borderRadius": { + "value": "5" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.267Z", + "layouts": [ + { + "id": "91cae02e-6d00-48ad-9750-1ae74bc9fd7f", + "type": "mobile", + "top": 10, + "left": 27, + "width": 18.6046511627907, + "height": 30, + "componentId": "dca350e6-c9f8-44aa-94d5-e6245cfb0ae2", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "bb56cbd1-57f7-4917-8a32-046a8e77ed33", + "type": "desktop", + "top": 480, + "left": 1, + "width": 20, + "height": 40, + "componentId": "dca350e6-c9f8-44aa-94d5-e6245cfb0ae2", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "98a7f66e-d446-4be5-b2e8-6bde808e9461", + "name": "textarea1", + "type": "TextArea", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "value": { + "value": "function addNumbers(a, b) {\n return a + b;\n}\n\nconst sum = addNumbers(5, 3);\nconsole.log(sum);" + }, + "placeholder": { + "value": "function addNumbers(a, b) {\n return a + b;\n}\n\nconst sum = addNumbers(5, 3);\nconsole.log(sum);" + } + }, + "general": {}, + "styles": { + "borderRadius": { + "value": "{{5}}" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "db411aca-2e7e-46ae-8bf6-75f664a636ea", + "type": "mobile", + "top": 100, + "left": 3, + "width": 13.953488372093023, + "height": 100, + "componentId": "98a7f66e-d446-4be5-b2e8-6bde808e9461", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "abdc0362-e37b-48d6-9cad-ccbdfcf6fd55", + "type": "desktop", + "top": 70, + "left": 1, + "width": 20, + "height": 270, + "componentId": "98a7f66e-d446-4be5-b2e8-6bde808e9461", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "37fbb9ed-5ac6-439b-82cb-35e276c89f49", + "name": "button1", + "type": "Button", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "text": { + "value": "Generate explanation >>" + }, + "loadingState": { + "value": "{{false}}", + "fxActive": false + }, + "disabledState": { + "value": "{{components.dca350e6-c9f8-44aa-94d5-e6245cfb0ae2.value == undefined || queries.getCodeExplanation.isLoading}}", + "fxActive": true + } + }, + "general": {}, + "styles": { + "backgroundColor": { + "value": "#ffffff00" + }, + "textColor": { + "value": "#3e63ddff" + }, + "loaderColor": { + "value": "#3e63ddff" + }, + "borderRadius": { + "value": "{{5}}" + }, + "borderColor": { + "value": "#3e63ddff" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.267Z", + "layouts": [ + { + "id": "c110426c-5994-4d04-901d-883aafb9d2eb", + "type": "mobile", + "top": 420, + "left": 7, + "width": 6.976744186046512, + "height": 30, + "componentId": "37fbb9ed-5ac6-439b-82cb-35e276c89f49", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "a6a6b92e-0984-4e21-87fc-462a307e06dd", + "type": "desktop", + "top": 550, + "left": 1, + "width": 20, + "height": 40, + "componentId": "37fbb9ed-5ac6-439b-82cb-35e276c89f49", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "b56cb989-9b4f-4dcf-a6c4-70dcfe6aac1a", + "name": "dropdown2", + "type": "DropDown", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "values": { + "value": "{{[\n \"\",\n \"C#\",\n \"C++\",\n \"Dart\",\n \"Elixir\",\n \"Erlang\",\n \"F#\",\n \"Go\",\n \"Groovy\",\n \"Haskell\",\n \"Java\",\n \"JavaScript\",\n \"Kotlin\",\n \"Lua\",\n \"MATLAB\",\n \"Objective-C\",\n \"Perl\",\n \"PHP\",\n \"Python\",\n \"R\",\n \"Ruby\",\n \"Rust\",\n \"Scala\",\n \"Shell\",\n \"SQL\",\n \"Swift\",\n \"TypeScript\"\n]}}" + }, + "display_values": { + "value": "{{[\n \"Any language\",\n \"C#\",\n \"C++\",\n \"Dart\",\n \"Elixir\",\n \"Erlang\",\n \"F#\",\n \"Go\",\n \"Groovy\",\n \"Haskell\",\n \"Java\",\n \"JavaScript\",\n \"Kotlin\",\n \"Lua\",\n \"MATLAB\",\n \"Objective-C\",\n \"Perl\",\n \"PHP\",\n \"Python\",\n \"R\",\n \"Ruby\",\n \"Rust\",\n \"Scala\",\n \"Shell\",\n \"SQL\",\n \"Swift\",\n \"TypeScript\"\n]}}" + }, + "value": { + "value": "" + }, + "placeholder": { + "value": "Select a language" + }, + "label": { + "value": "" + } + }, + "general": {}, + "styles": {}, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "553e50a3-c9d4-4ae7-9b8d-da129cb2f32d", + "type": "mobile", + "top": 420, + "left": 2, + "width": 8, + "height": 30, + "componentId": "b56cb989-9b4f-4dcf-a6c4-70dcfe6aac1a", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "abeda4d6-0111-4b9a-bfb1-234c986ee777", + "type": "desktop", + "top": 390, + "left": 1, + "width": 20, + "height": 40, + "componentId": "b56cb989-9b4f-4dcf-a6c4-70dcfe6aac1a", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "7112d3b6-f7d5-4da8-84ad-f2db9ab962d8", + "name": "text6", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "text": { + "value": "Language" + } + }, + "general": {}, + "styles": { + "fontWeight": { + "value": "bold" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "3b6ce6c5-bb8b-4145-991b-b4dc659ac9ae", + "type": "desktop", + "top": 360, + "left": 1, + "width": 14, + "height": 30, + "componentId": "7112d3b6-f7d5-4da8-84ad-f2db9ab962d8", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "d907a75f-162c-4e89-8bef-8ad4a6b10f6a", + "type": "mobile", + "top": 70, + "left": 4, + "width": 13.953488372093023, + "height": 40, + "componentId": "7112d3b6-f7d5-4da8-84ad-f2db9ab962d8", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "052d73d1-c415-4720-8963-36c94ce54b19", + "name": "text7", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "text": { + "value": "{{`
${queries.getCodeExplanation.data.candidates ? queries.getCodeExplanation.data.candidates[0].content.parts[0].text : \"\"}
`}}" + }, + "textFormat": { + "value": "html" + }, + "loadingState": { + "fxActive": true, + "value": "{{queries.5774aa01-0931-4036-8bfa-4d12e0b6bc8b.isLoading}}" + } + }, + "general": {}, + "styles": { + "borderColor": { + "value": "#ddddddff" + }, + "borderRadius": { + "value": "5" + }, + "verticalAlignment": { + "value": "top" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.267Z", + "layouts": [ + { + "id": "388a36e0-95ac-49f3-a97b-ad413efafb3a", + "type": "desktop", + "top": 70, + "left": 22, + "width": 20, + "height": 520, + "componentId": "052d73d1-c415-4720-8963-36c94ce54b19", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "1f2da6ab-3493-4ace-b5ae-ceadbd3e2fb0", + "type": "mobile", + "top": 290, + "left": 23, + "width": 6, + "height": 40, + "componentId": "052d73d1-c415-4720-8963-36c94ce54b19", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "3c5278e8-8cc5-442a-bc70-19d4cd72cec7", + "name": "text8", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "text": { + "value": "Gemini Model" + } + }, + "general": {}, + "styles": { + "fontWeight": { + "value": "bold" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "e41fd57d-29e6-49e2-b3ee-75b3769f6d27", + "type": "mobile", + "top": 70, + "left": 4, + "width": 13.953488372093023, + "height": 40, + "componentId": "3c5278e8-8cc5-442a-bc70-19d4cd72cec7", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "7a1d68a9-e9f5-496e-9947-3d6e12c55b0c", + "type": "desktop", + "top": 450, + "left": 1, + "width": 14, + "height": 30, + "componentId": "3c5278e8-8cc5-442a-bc70-19d4cd72cec7", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + }, + { + "id": "521f0268-02d8-4571-9efe-030c9816bdea", + "name": "text9", + "type": "Text", + "pageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "parent": "2727cf8a-1856-41cb-b716-c25afc2a15ad", + "properties": { + "text": { + "value": "Explanation" + } + }, + "general": {}, + "styles": { + "textSize": { + "value": "24" + }, + "fontWeight": { + "value": "bold" + }, + "isScrollRequired": { + "value": "disabled" + } + }, + "generalStyles": {}, + "displayPreferences": { + "showOnDesktop": { + "value": "{{true}}" + }, + "showOnMobile": { + "value": "{{false}}" + } + }, + "validation": {}, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z", + "layouts": [ + { + "id": "81f9d6a1-90c4-422c-8602-1675a76f6de4", + "type": "desktop", + "top": 20, + "left": 22, + "width": 20, + "height": 40, + "componentId": "521f0268-02d8-4571-9efe-030c9816bdea", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "da2abfa1-769b-4784-87fb-5020e6610fed", + "type": "mobile", + "top": 20, + "left": 9, + "width": 13.953488372093023, + "height": 40, + "componentId": "521f0268-02d8-4571-9efe-030c9816bdea", + "dimensionUnit": "count", + "updatedAt": "2025-02-27T07:28:52.148Z" + } + ] + } + ], + "pages": [ + { + "id": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "name": "Home", + "handle": "home", + "index": 1, + "disabled": false, + "hidden": false, + "icon": null, + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.366Z", + "autoComputeLayout": true, + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "pageGroupIndex": 1, + "pageGroupId": null, + "isPageGroup": false + } + ], + "events": [ + { + "id": "9417716e-b415-4532-aea4-8a2afa224f10", + "name": "onClick", + "index": 0, + "event": { + "eventId": "onClick", + "message": "Hello world!", + "queryId": "5774aa01-0931-4036-8bfa-4d12e0b6bc8b", + "actionId": "run-query", + "alertType": "info", + "queryName": "getCodeExplanation", + "parameters": {} + }, + "sourceId": "37fbb9ed-5ac6-439b-82cb-35e276c89f49", + "target": "component", + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.260Z" + } + ], + "dataQueries": [ + { + "id": "5774aa01-0931-4036-8bfa-4d12e0b6bc8b", + "name": "getCodeExplanation", + "options": { + "method": "post", + "url": "https://generativelanguage.googleapis.com/v1beta/{{components.dropdown1.value}}:generateContent", + "url_params": [ + [ + "key", + "{{constants.GEMINI_API_KEY}}" + ], + [ + "", + "" + ] + ], + "headers": [ + [ + "Content-Type", + "application/json" + ], + [ + "", + "" + ] + ], + "body": [ + [ + "", + "" + ] + ], + "json_body": "{\n \"contents\": [\n {\n \"parts\": [\n {\n \"text\": \"{{components.textarea1.value.replaceAll('\\n','\\\\n')}} - Generate a point-wise line by line explanation of this code in html formatting only. Keep only the explanation, and nothing else. {{components.dropdown2.value ? `The code is in ${components.dropdown2.value} language.` : 'Also identify the language of the code.'}}\"\n }\n ]\n }\n ]\n}", + "body_toggle": true, + "transformationLanguage": "javascript", + "enableTransformation": false, + "arrayValuesChanged": false, + "transformation": "// write your code here\n// return value will be set as data and the original data will be available as rawData\nreturn data.filter(row => row.amount > 1000);\n " + }, + "dataSourceId": "489072da-3239-4bd5-91b9-dee5f5da5335", + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.148Z" + }, + { + "id": "32ff6874-7da0-4b88-ae05-3c9cda4a07dc", + "name": "getGeminiModels", + "options": { + "method": "get", + "url": "https://generativelanguage.googleapis.com/v1beta/models?key={{constants.GEMINI_API_KEY}}", + "url_params": [ + [ + "", + "" + ] + ], + "headers": [ + [ + "", + "" + ] + ], + "body": [ + [ + "", + "" + ] + ], + "json_body": null, + "body_toggle": false, + "transformationLanguage": "javascript", + "enableTransformation": false, + "runOnPageLoad": true + }, + "dataSourceId": "489072da-3239-4bd5-91b9-dee5f5da5335", + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "createdAt": "2025-02-27T07:28:52.148Z", + "updatedAt": "2025-02-27T07:28:52.983Z" + } + ], + "dataSources": [ + { + "id": "489072da-3239-4bd5-91b9-dee5f5da5335", + "name": "restapidefault", + "kind": "restapi", + "type": "static", + "pluginId": null, + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "organizationId": null, + "scope": "local", + "createdAt": "2025-02-27T07:28:52.153Z", + "updatedAt": "2025-02-27T07:28:52.153Z" + }, + { + "id": "c462a40f-c7fa-4d55-98fe-9bc445271cab", + "name": "runjsdefault", + "kind": "runjs", + "type": "static", + "pluginId": null, + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "organizationId": null, + "scope": "local", + "createdAt": "2025-02-27T07:28:52.163Z", + "updatedAt": "2025-02-27T07:28:52.163Z" + }, + { + "id": "cc0b5feb-29ea-47c0-9a9a-62c0e0b89ccb", + "name": "runpydefault", + "kind": "runpy", + "type": "static", + "pluginId": null, + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "organizationId": null, + "scope": "local", + "createdAt": "2025-02-27T07:28:52.170Z", + "updatedAt": "2025-02-27T07:28:52.170Z" + }, + { + "id": "907dde15-1ac2-4f53-ba72-8e4e1d066f0e", + "name": "tooljetdbdefault", + "kind": "tooljetdb", + "type": "static", + "pluginId": null, + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "organizationId": null, + "scope": "local", + "createdAt": "2025-02-27T07:28:52.176Z", + "updatedAt": "2025-02-27T07:28:52.176Z" + }, + { + "id": "66ad4e35-f981-47a6-99cd-31e9e7bbd9b3", + "name": "workflowsdefault", + "kind": "workflows", + "type": "static", + "pluginId": null, + "appVersionId": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "organizationId": null, + "scope": "local", + "createdAt": "2025-02-27T07:28:52.183Z", + "updatedAt": "2025-02-27T07:28:52.183Z" + } + ], + "appVersions": [ + { + "id": "430dd7d7-1cd1-4c36-975f-229a1aa7dcb8", + "name": "v1", + "definition": null, + "globalSettings": { + "hideHeader": true, + "appInMaintenance": false, + "canvasMaxWidth": 100, + "canvasMaxWidthType": "%", + "canvasMaxHeight": 2400, + "canvasBackgroundColor": "#edeff5", + "backgroundFxQuery": "", + "appMode": "auto" + }, + "pageSettings": { + "properties": { + "disableMenu": { + "value": "{{true}}", + "fxActive": false + } + } + }, + "showViewerNavigation": false, + "homePageId": "93c0473f-6ada-4f1d-9c05-8a4775466aab", + "appId": "8819afae-57b6-447d-93dd-6dc108169bfe", + "currentEnvironmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "promotedFrom": null, + "createdAt": "2025-02-27T07:28:52.144Z", + "updatedAt": "2025-02-27T07:28:52.274Z" + } + ], + "appEnvironments": [ + { + "id": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "organizationId": "a51da635-3a28-4b10-a6f4-7ba34e254987", + "name": "development", + "isDefault": false, + "priority": 1, + "enabled": true, + "createdAt": "2025-02-27T07:28:36.425Z", + "updatedAt": "2025-02-27T07:28:36.425Z" + }, + { + "id": "ed48a4ab-ef5c-47c0-b99c-453fec90b9ec", + "organizationId": "a51da635-3a28-4b10-a6f4-7ba34e254987", + "name": "staging", + "isDefault": false, + "priority": 2, + "enabled": true, + "createdAt": "2025-02-27T07:28:36.425Z", + "updatedAt": "2025-02-27T07:28:36.425Z" + }, + { + "id": "eb006618-493c-48ac-8a4d-e80d208d29de", + "organizationId": "a51da635-3a28-4b10-a6f4-7ba34e254987", + "name": "production", + "isDefault": true, + "priority": 3, + "enabled": true, + "createdAt": "2025-02-27T07:28:36.425Z", + "updatedAt": "2025-02-27T07:28:36.425Z" + } + ], + "dataSourceOptions": [ + { + "id": "98e3239b-e54b-4b59-992b-d9bbfb68d1e6", + "dataSourceId": "489072da-3239-4bd5-91b9-dee5f5da5335", + "environmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "options": null, + "createdAt": "2025-02-27T07:28:52.159Z", + "updatedAt": "2025-02-27T07:28:52.159Z" + }, + { + "id": "c997ee43-2f17-46aa-bc35-32af668d546b", + "dataSourceId": "489072da-3239-4bd5-91b9-dee5f5da5335", + "environmentId": "ed48a4ab-ef5c-47c0-b99c-453fec90b9ec", + "options": null, + "createdAt": "2025-02-27T07:28:52.159Z", + "updatedAt": "2025-02-27T07:28:52.159Z" + }, + { + "id": "01bbd244-59c9-4965-8024-401c8f1961fd", + "dataSourceId": "489072da-3239-4bd5-91b9-dee5f5da5335", + "environmentId": "eb006618-493c-48ac-8a4d-e80d208d29de", + "options": null, + "createdAt": "2025-02-27T07:28:52.159Z", + "updatedAt": "2025-02-27T07:28:52.159Z" + }, + { + "id": "8a8096f7-6b6f-49ca-95de-596c5670c832", + "dataSourceId": "c462a40f-c7fa-4d55-98fe-9bc445271cab", + "environmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "options": null, + "createdAt": "2025-02-27T07:28:52.167Z", + "updatedAt": "2025-02-27T07:28:52.167Z" + }, + { + "id": "1e2dcc6d-8944-4b5b-abd4-72f7201bf657", + "dataSourceId": "c462a40f-c7fa-4d55-98fe-9bc445271cab", + "environmentId": "ed48a4ab-ef5c-47c0-b99c-453fec90b9ec", + "options": null, + "createdAt": "2025-02-27T07:28:52.167Z", + "updatedAt": "2025-02-27T07:28:52.167Z" + }, + { + "id": "24bfe83d-b2d3-4bf0-8730-1bd14d96cf7a", + "dataSourceId": "c462a40f-c7fa-4d55-98fe-9bc445271cab", + "environmentId": "eb006618-493c-48ac-8a4d-e80d208d29de", + "options": null, + "createdAt": "2025-02-27T07:28:52.167Z", + "updatedAt": "2025-02-27T07:28:52.167Z" + }, + { + "id": "44600a77-04bf-4b30-8613-bd7a7bff6508", + "dataSourceId": "cc0b5feb-29ea-47c0-9a9a-62c0e0b89ccb", + "environmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "options": null, + "createdAt": "2025-02-27T07:28:52.174Z", + "updatedAt": "2025-02-27T07:28:52.174Z" + }, + { + "id": "b70c436e-70e5-48d3-84d2-ca2c784c7425", + "dataSourceId": "cc0b5feb-29ea-47c0-9a9a-62c0e0b89ccb", + "environmentId": "ed48a4ab-ef5c-47c0-b99c-453fec90b9ec", + "options": null, + "createdAt": "2025-02-27T07:28:52.174Z", + "updatedAt": "2025-02-27T07:28:52.174Z" + }, + { + "id": "7bd1351e-61b9-4ba6-9e57-8eca1a3a0df3", + "dataSourceId": "cc0b5feb-29ea-47c0-9a9a-62c0e0b89ccb", + "environmentId": "eb006618-493c-48ac-8a4d-e80d208d29de", + "options": null, + "createdAt": "2025-02-27T07:28:52.174Z", + "updatedAt": "2025-02-27T07:28:52.174Z" + }, + { + "id": "f8268c18-8453-48ac-acf7-46c2d0c75c75", + "dataSourceId": "907dde15-1ac2-4f53-ba72-8e4e1d066f0e", + "environmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "options": null, + "createdAt": "2025-02-27T07:28:52.181Z", + "updatedAt": "2025-02-27T07:28:52.181Z" + }, + { + "id": "cd59c697-6ac2-4594-b8f6-493676e8b3c7", + "dataSourceId": "907dde15-1ac2-4f53-ba72-8e4e1d066f0e", + "environmentId": "ed48a4ab-ef5c-47c0-b99c-453fec90b9ec", + "options": null, + "createdAt": "2025-02-27T07:28:52.181Z", + "updatedAt": "2025-02-27T07:28:52.181Z" + }, + { + "id": "7270ef0a-f6d6-498e-9959-4b646a30d5d1", + "dataSourceId": "907dde15-1ac2-4f53-ba72-8e4e1d066f0e", + "environmentId": "eb006618-493c-48ac-8a4d-e80d208d29de", + "options": null, + "createdAt": "2025-02-27T07:28:52.181Z", + "updatedAt": "2025-02-27T07:28:52.181Z" + }, + { + "id": "fe4824d5-57fa-42dc-9812-4af634737898", + "dataSourceId": "66ad4e35-f981-47a6-99cd-31e9e7bbd9b3", + "environmentId": "4efb81aa-756a-4a8f-a017-e167f0720b85", + "options": null, + "createdAt": "2025-02-27T07:28:52.189Z", + "updatedAt": "2025-02-27T07:28:52.189Z" + }, + { + "id": "521a6d91-484b-45bc-af8f-aaceb0dc515c", + "dataSourceId": "66ad4e35-f981-47a6-99cd-31e9e7bbd9b3", + "environmentId": "ed48a4ab-ef5c-47c0-b99c-453fec90b9ec", + "options": null, + "createdAt": "2025-02-27T07:28:52.189Z", + "updatedAt": "2025-02-27T07:28:52.189Z" + }, + { + "id": "f5955bf2-c148-4544-acd9-a9a92a943e5b", + "dataSourceId": "66ad4e35-f981-47a6-99cd-31e9e7bbd9b3", + "environmentId": "eb006618-493c-48ac-8a4d-e80d208d29de", + "options": null, + "createdAt": "2025-02-27T07:28:52.189Z", + "updatedAt": "2025-02-27T07:28:52.189Z" + } + ], + "schemaDetails": { + "multiPages": true, + "multiEnv": true, + "globalDataSources": true + } + } + } + } + ], + "tooljet_version": "3.5.3-ee-lts" +} \ No newline at end of file diff --git a/cypress-tests/cypress/support/utils/api.js b/cypress-tests/cypress/support/utils/api.js new file mode 100644 index 0000000000..1ea37104f8 --- /dev/null +++ b/cypress-tests/cypress/support/utils/api.js @@ -0,0 +1,72 @@ +import { groupsSelector } from "Selectors/manageGroups"; +import { navigateToManageGroups } from 'Support/utils/common'; +export const apiRequest = (method, url, body = {}, headers = {}) => { + return cy.request({ + method, + url, + body, + headers: { + Authorization: Cypress.env('AUTH_TOKEN'), + "Content-Type": "application/json", + ...headers, + }, + failOnStatusCode: false + }); +}; + +export const createUser = (userData) => { + return apiRequest("POST", `${Cypress.env('API_URL')}/ext/users`, userData); +}; + +export const getUser = (userId) => { + return apiRequest("GET", `${Cypress.env('API_URL')}/ext/user/${userId}`); +}; + +export const getAllUsers = () => { + return apiRequest("GET", `${Cypress.env('API_URL')}/ext/users`); +}; + +export const updateUser = (userId, userData) => { + return apiRequest("PATCH", `${Cypress.env('API_URL')}/ext/user/${userId}`, userData); +}; +export const updateUserRole = (workspaceId, userData) => { + return apiRequest("PUT", `${Cypress.env('API_URL')}/ext/update-user-role/workspace/${workspaceId}`, userData); +} + +export const replaceUserWorkspace = (userId, workspaceId, userData) => { + return apiRequest("PATCH", `${Cypress.env('API_URL')}/ext/user/${userId}/workspace/${workspaceId}`, userData); +} + +export const replaceUserWorkspacesRelations = (userId, userData) => { + return apiRequest("PUT", `${Cypress.env('API_URL')}/ext/user/${userId}/workspaces`, userData); +} + +export const getAllWorkspaces = () => { + return apiRequest("GET", `${Cypress.env('API_URL')}/ext/workspaces`); +} + +export const importApp = (workspaceId, appData, headers) => { + return apiRequest("POST", `${Cypress.env('API_URL')}/ext/import/workspace/${workspaceId}/apps`, appData, headers); +} + +export const exportApp = (workspaceId, appId, endpoint, headers) => { + return apiRequest("POST", `${Cypress.env('API_URL')}/ext/export/workspace/${workspaceId}/apps/${appId}${endpoint}`, headers); +} + +export const allAppsDetails = (workspaceIds) => { + return apiRequest("GET", `${Cypress.env('API_URL')}/ext/workspace/${workspaceIds}/apps`); +} + +export const createGroup = (groupName) => { + cy.get(groupsSelector.createNewGroupButton).click(); + cy.clearAndType(groupsSelector.groupNameInput, groupName); + cy.get(groupsSelector.createGroupButton).click(); +} +export const validateUserInGroup = (email, workspaceSlug, groupName, shouldExist = true) => { + if (workspaceSlug) cy.visit(workspaceSlug); + navigateToManageGroups(); + cy.get(groupsSelector.groupLink(groupName)).click(); + cy.get(groupsSelector.usersLink).click(); + const userRow = `[data-cy="${email}-user-row"]`; + cy.get(userRow).should(shouldExist ? "exist" : "not.exist"); +}; \ No newline at end of file diff --git a/cypress-tests/cypress/support/utils/manageGroups.js b/cypress-tests/cypress/support/utils/manageGroups.js index dfda103d91..3f0c85d1cf 100644 --- a/cypress-tests/cypress/support/utils/manageGroups.js +++ b/cypress-tests/cypress/support/utils/manageGroups.js @@ -853,6 +853,9 @@ export const createGroupsAndAddUserInGroup = (groupName, email) => { commonSelectors.toastMessage, groupsText.groupCreatedToast ); + addUserInGroup(groupName, email); +}; +export const addUserInGroup = (groupName, email) => { cy.get(groupsSelector.groupLink(groupName)).click(); cy.clearAndType(groupsSelector.multiSelectSearchInput, email); cy.wait(2000); @@ -862,7 +865,7 @@ export const createGroupsAndAddUserInGroup = (groupName, email) => { commonSelectors.toastMessage, groupsText.userAddedToast ); -}; +} export const inviteUserBasedOnRole = (firstName, email, role = "end-user") => { fillUserInviteForm(firstName, email); diff --git a/docker/ce-entrypoint.sh b/docker/ce-entrypoint.sh index 4b63af2e45..b18ab59ffd 100755 --- a/docker/ce-entrypoint.sh +++ b/docker/ce-entrypoint.sh @@ -1,6 +1,10 @@ #!/bin/bash set -e +if [ -f "./.env" ]; then + export $(grep -v '^#' ./.env | xargs -d '\n') || true +fi + if [ -d "./server/dist" ]; then SETUP_CMD='npm run db:setup:prod' else diff --git a/docker/ce-preview.Dockerfile b/docker/ce-preview.Dockerfile index 4e9f8dd796..d71e6c1dbc 100644 --- a/docker/ce-preview.Dockerfile +++ b/docker/ce-preview.Dockerfile @@ -75,20 +75,39 @@ 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 +USER root +RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - +RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list +RUN echo "deb http://deb.debian.org/debian" +RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor +USER postgres +RUN service postgresql start && \ + psql -c "create role tooljet with login superuser password 'postgres';" +USER root + # ENV defaults -ENV TOOLJET_HOST=http://localhost:80 \ - PGRST_HOST=http://localhost:3000 \ - PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \ - TOOLJET_DB=tooljet_db \ - ENABLE_TOOLJET_DB=true \ - PORT=80 \ +ENV TOOLJET_HOST=http://localhost \ + NODE_ENV=production \ LOCKBOX_MASTER_KEY=replace_with_lockbox_master_key \ SECRET_KEY_BASE=replace_with_secret_key_base \ - ORM_LOGGING=all \ + PG_DB=tooljet_production \ + PG_USER=tooljet \ + PG_PASS=postgres \ + PG_HOST=localhost \ + ENABLE_TOOLJET_DB=true \ + TOOLJET_DB_HOST=localhost \ + TOOLJET_DB_USER=tooljet \ + TOOLJET_DB_PASS=postgres \ + TOOLJET_DB=tooljet_db \ + PGRST_HOST=http://localhost:3000 \ + PGRST_DB_URI=postgres://tooljet:postgres@localhost/tooljet_db \ + PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \ + PGRST_DB_PRE_CONFIG=postgrest.pre_config \ + ORM_LOGGING=true \ + DEPLOYMENT_PLATFORM=docker:local \ + HOME=/home/appuser \ TERM=xterm CMD ["/usr/bin/supervisord"] diff --git a/docker/ee/ee-preview.Dockerfile b/docker/ee/ee-preview.Dockerfile index d88efbfecf..91e0864bd0 100644 --- a/docker/ee/ee-preview.Dockerfile +++ b/docker/ee/ee-preview.Dockerfile @@ -104,20 +104,40 @@ 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 -ENV TOOLJET_HOST=http://localhost:80 \ - PGRST_HOST=http://localhost:3000 \ - PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \ - TOOLJET_DB=tooljet_db \ - ENABLE_TOOLJET_DB=true \ - PORT=80 \ +USER root +RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - +RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list +RUN echo "deb http://deb.debian.org/debian" +RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor +USER postgres +RUN service postgresql start && \ + psql -c "create role tooljet with login superuser password 'postgres';" +USER root + +# ENV defaults +ENV TOOLJET_HOST=http://localhost \ + NODE_ENV=production \ LOCKBOX_MASTER_KEY=replace_with_lockbox_master_key \ SECRET_KEY_BASE=replace_with_secret_key_base \ - ORM_LOGGING=all \ + PG_DB=tooljet_production \ + PG_USER=tooljet \ + PG_PASS=postgres \ + PG_HOST=localhost \ + ENABLE_TOOLJET_DB=true \ + TOOLJET_DB_HOST=localhost \ + TOOLJET_DB_USER=tooljet \ + TOOLJET_DB_PASS=postgres \ + TOOLJET_DB=tooljet_db \ + PGRST_HOST=http://localhost:3000 \ + PGRST_DB_URI=postgres://tooljet:postgres@localhost/tooljet_db \ + PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \ + PGRST_DB_PRE_CONFIG=postgrest.pre_config \ + ORM_LOGGING=true \ + DEPLOYMENT_PLATFORM=docker:local \ + REDIS_PASS= \ TERM=xterm CMD ["/usr/bin/supervisord"] diff --git a/server/scripts/boot.sh b/server/scripts/boot.sh index e12aa43a25..3c2bbad93e 100755 --- a/server/scripts/boot.sh +++ b/server/scripts/boot.sh @@ -1,6 +1,8 @@ #!/bin/bash set -e +service postgresql start + echo " _____ _ ___ _ |_ _| | | |_ | | |