mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-06 06:48:21 +00:00
Merge branch 'main' into appbuilder/sprint-14
This commit is contained in:
commit
ca09b8df9c
20 changed files with 1276 additions and 308 deletions
2
.github/workflows/docker-release.yml
vendored
2
.github/workflows/docker-release.yml
vendored
|
|
@ -139,6 +139,7 @@ jobs:
|
|||
context: .
|
||||
build-args: |
|
||||
CUSTOM_GITHUB_TOKEN=${{ secrets.CUSTOM_GITHUB_TOKEN }}
|
||||
BRANCH_NAME=main
|
||||
file: docker/ee/ee-production.Dockerfile
|
||||
push: true
|
||||
tags: tooljet/tooljet-ee:${{ github.event.release.tag_name }},tooljet/tooljet-ee:ee-lts-latest,tooljet/tooljet:ee-lts-latest,tooljet/tooljet:${{ github.event.release.tag_name }}
|
||||
|
|
@ -155,6 +156,7 @@ jobs:
|
|||
context: .
|
||||
build-args: |
|
||||
CUSTOM_GITHUB_TOKEN=${{ secrets.CUSTOM_GITHUB_TOKEN }}
|
||||
BRANCH_NAME=lts
|
||||
file: docker/ee/ee-production.Dockerfile
|
||||
push: true
|
||||
tags: tooljet/tooljet-ee:${{ github.event.release.tag_name }},tooljet/tooljet-ee:ee-lts-latest,tooljet/tooljet:ee-lts-latest,tooljet/tooljet:${{ github.event.release.tag_name }}
|
||||
|
|
|
|||
47
.github/workflows/manual-docker-build.yml
vendored
Normal file
47
.github/workflows/manual-docker-build.yml
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
name: Manual Docker Build and Push
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch_name:
|
||||
description: 'Git branch to build from'
|
||||
required: true
|
||||
default: 'main'
|
||||
dockerfile_path:
|
||||
description: 'Path to Dockerfile'
|
||||
required: true
|
||||
default: './Dockerfile'
|
||||
docker_tag:
|
||||
description: 'Docker tag suffix (e.g., pre-release-14)'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.inputs.branch_name }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and Push Docker image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ${{ github.event.inputs.dockerfile_path }}
|
||||
push: true
|
||||
tags: tooljet/tj-osv:${{ github.event.inputs.docker_tag }}
|
||||
platforms: linux/amd64
|
||||
build-args: |
|
||||
CUSTOM_GITHUB_TOKEN=${{ secrets.CUSTOM_GITHUB_TOKEN }}
|
||||
|
|
@ -98,8 +98,10 @@ module.exports = defineConfig({
|
|||
configFile: environment.configFile,
|
||||
specPattern: [
|
||||
"cypress/e2e/happyPath/platform/firstUser/firstUserOnboarding.cy.js",
|
||||
"cypress/e2e/happyPath/platform/ceTestcases/apps/appSlug.cy.js",
|
||||
"cypress/e2e/happyPath/platform/ceTestcases/apps/!(*appSlug).cy.js",
|
||||
"cypress/e2e/happyPath/platform/commonTestcases/userManagment/*.cy.js",
|
||||
"cypress/e2e/happyPath/platform/eeTestcases/**/*.cy.js",
|
||||
"cypress/e2e/happyPath/platform/eeTestcases/workspace/*.cy.js",
|
||||
],
|
||||
numTestsKeptInMemory: 1,
|
||||
redirectionLimit: 15,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ RUN git checkout ${BRANCH_NAME}
|
|||
RUN git submodule update --init --recursive
|
||||
|
||||
# Checkout the same branch in submodules if it exists, otherwise stay on default branch
|
||||
RUN git submodule foreach 'git checkout ${BRANCH_NAME} || true'
|
||||
RUN git submodule foreach 'git checkout main'
|
||||
|
||||
# Scripts for building
|
||||
COPY ./package.json ./package.json
|
||||
|
|
@ -54,7 +54,7 @@ RUN npm install -g @nestjs/cli
|
|||
RUN npm install -g copyfiles
|
||||
RUN npm --prefix server run build
|
||||
|
||||
FROM node:22.15.1
|
||||
FROM node:22.15.1-bullseye
|
||||
|
||||
RUN apt-get update -yq \
|
||||
&& apt-get install curl wget gnupg zip -yq \
|
||||
|
|
|
|||
|
|
@ -479,24 +479,22 @@ Cypress.Commands.add("apiMakeAppPublic", (appId = Cypress.env("appId")) => {
|
|||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("apiDeleteGranularPermission", (groupName) => {
|
||||
Cypress.Commands.add("apiDeleteGranularPermission", (groupName, typesToDelete = []) => {
|
||||
cy.getAuthHeaders().then((headers) => {
|
||||
// Fetch group permissions
|
||||
// Step 1: Get the group by name
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url: `${Cypress.env("server_host")}/api/v2/group-permissions`,
|
||||
headers: headers,
|
||||
headers,
|
||||
log: false,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
const group = response.body.groupPermissions.find(
|
||||
(g) => g.name === groupName
|
||||
);
|
||||
const group = response.body.groupPermissions.find((g) => g.name === groupName);
|
||||
if (!group) throw new Error(`Group with name ${groupName} not found`);
|
||||
|
||||
const groupId = group.id;
|
||||
|
||||
// Fetch granular permissions for the specific group
|
||||
// Step 2: Get all granular permissions for the group
|
||||
cy.request({
|
||||
method: "GET",
|
||||
url: `${Cypress.env("server_host")}/api/v2/group-permissions/${groupId}/granular-permissions`,
|
||||
|
|
@ -504,22 +502,31 @@ Cypress.Commands.add("apiDeleteGranularPermission", (groupName) => {
|
|||
log: false,
|
||||
}).then((granularResponse) => {
|
||||
expect(granularResponse.status).to.equal(200);
|
||||
const granularPermissionId = granularResponse.body[0].id;
|
||||
const granularPermissions = granularResponse.body;
|
||||
|
||||
// Delete the granular permission
|
||||
cy.request({
|
||||
method: "DELETE",
|
||||
url: `${Cypress.env("server_host")}/api/v2/group-permissions/granular-permissions/app/${granularPermissionId}`,
|
||||
headers,
|
||||
log: false,
|
||||
}).then((deleteResponse) => {
|
||||
expect(deleteResponse.status).to.equal(200);
|
||||
// Step 3: Filter if typesToDelete is specified
|
||||
const permissionsToDelete = typesToDelete.length
|
||||
? granularPermissions.filter((perm) => typesToDelete.includes(perm.type))
|
||||
: granularPermissions;
|
||||
|
||||
// Step 4: Delete each granular permission
|
||||
permissionsToDelete.forEach((permission) => {
|
||||
cy.request({
|
||||
method: "DELETE",
|
||||
url: `${Cypress.env("server_host")}/api/v2/group-permissions/granular-permissions/app/${permission.id}`,
|
||||
headers,
|
||||
log: false,
|
||||
}).then((deleteResponse) => {
|
||||
expect(deleteResponse.status).to.equal(200);
|
||||
cy.log(`Deleted granular permission: ${permission.name}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Cypress.Commands.add(
|
||||
"apiCreateGranularPermission",
|
||||
(
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ describe("App Import Functionality", () => {
|
|||
cy.apiLogin();
|
||||
cy.apiCreateWorkspace(data.workspaceName, data.workspaceSlug);
|
||||
cy.apiLogout();
|
||||
cy.skipWalkthrough()
|
||||
cy.skipWalkthrough();
|
||||
});
|
||||
|
||||
it("should verify app import functionality", () => {
|
||||
|
|
@ -151,23 +151,49 @@ describe("App Import Functionality", () => {
|
|||
|
||||
cy.visit(`${data.workspaceSlug}/data-sources`);
|
||||
cy.get('[data-cy="postgresql-button"]').should("be.visible");
|
||||
cy.apiUpdateDataSource("postgresql", "production", {
|
||||
options: [
|
||||
{
|
||||
key: "password",
|
||||
value: `${Cypress.env("pg_password")}`,
|
||||
encrypted: true,
|
||||
},
|
||||
],
|
||||
|
||||
cy.ifEnv("Community", () => {
|
||||
cy.apiUpdateDataSource("postgresql", "production", {
|
||||
options: [
|
||||
{
|
||||
key: "password",
|
||||
value: `${Cypress.env("pg_password")}`,
|
||||
encrypted: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
cy.ifEnv("Enterprise", () => {
|
||||
cy.apiUpdateDataSource("postgresql", "development", {
|
||||
options: [
|
||||
{
|
||||
key: "password",
|
||||
value: `${Cypress.env("pg_password")}`,
|
||||
encrypted: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
cy.apiCreateWsConstant(
|
||||
"pageHeader",
|
||||
"Import and Export",
|
||||
["Global"],
|
||||
["production"]
|
||||
);
|
||||
cy.apiCreateWsConstant("db_name", "persons", ["Secret"], ["production"]);
|
||||
cy.ifEnv("Community", () => {
|
||||
cy.apiCreateWsConstant(
|
||||
"pageHeader",
|
||||
"Import and Export",
|
||||
["Global"],
|
||||
["production"]
|
||||
);
|
||||
cy.apiCreateWsConstant("db_name", "persons", ["Secret"], ["production"]);
|
||||
});
|
||||
|
||||
cy.ifEnv("Enterprise", () => {
|
||||
cy.apiCreateWsConstant(
|
||||
"pageHeader",
|
||||
"Import and Export",
|
||||
["Global"],
|
||||
["development"]
|
||||
);
|
||||
cy.apiCreateWsConstant("db_name", "persons", ["Secret"], ["development"]);
|
||||
});
|
||||
|
||||
// Verify app after setup
|
||||
cy.wait("@importApp").then((interception) => {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
verifyURLs,
|
||||
resolveHost,
|
||||
} from "Support/utils/apps";
|
||||
import { appPromote } from "Support/utils/platform/multiEnv";
|
||||
|
||||
describe("App Slug", () => {
|
||||
const data = {};
|
||||
|
|
@ -153,6 +154,7 @@ describe("App Slug", () => {
|
|||
cy.visit("/my-workspace");
|
||||
cy.apiCreateApp(data.slug);
|
||||
cy.openApp("my-workspace");
|
||||
|
||||
releaseApp();
|
||||
cy.get(commonWidgetSelector.shareAppButton).click();
|
||||
cy.clearAndType(commonWidgetSelector.appNameSlugInput, data.slug);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import {
|
|||
verifyRestrictedAccess,
|
||||
onboardUserFromAppLink,
|
||||
} from "Support/utils/apps";
|
||||
import { appPromote } from "Support/utils/platform/multiEnv";
|
||||
import { InstanceSSO } from "Support/utils/platform/eeCommon";
|
||||
|
||||
describe(
|
||||
"Private and Public apps",
|
||||
|
|
@ -183,6 +185,9 @@ describe(
|
|||
setupAppWithSlug(data.appName, data.slug);
|
||||
|
||||
cy.apiLogout();
|
||||
cy.ifEnv("Enterprise", () => {
|
||||
InstanceSSO(true, true, true);
|
||||
});
|
||||
userSignUp(data.firstName, data.email, data.workspaceName);
|
||||
cy.wait(1000);
|
||||
cy.visitSlug({
|
||||
|
|
@ -312,7 +317,9 @@ describe(
|
|||
cy.apiLogout();
|
||||
cy.apiLogin();
|
||||
cy.visit(`${data.workspaceSlug}`);
|
||||
cy.apiDeleteGranularPermission("end-user");
|
||||
|
||||
cy.apiDeleteGranularPermission("end-user", ["app", "workflow"]);
|
||||
|
||||
setSignupStatus(true, data.workspaceName);
|
||||
|
||||
setupAppWithSlug(data.appName, data.slug);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
|
||||
import { fake } from "Fixtures/fake";
|
||||
import { commonText } from "Texts/common";
|
||||
|
||||
import {
|
||||
editVersionAndVerify,
|
||||
deleteVersionAndVerify,
|
||||
|
|
@ -13,25 +12,20 @@ import {
|
|||
navigateToEditVersionModal,
|
||||
switchVersionAndVerify,
|
||||
} from "Support/utils/version";
|
||||
|
||||
import { appVersionSelectors } from "Selectors/exportImport";
|
||||
import { editVersionSelectors } from "Selectors/version";
|
||||
import { editVersionText } from "Texts/version";
|
||||
import { createNewVersion } from "Support/utils/exportImport";
|
||||
|
||||
import { verifyModal, closeModal } from "Support/utils/common";
|
||||
|
||||
import {
|
||||
verifyComponent,
|
||||
verifyComponentinrightpannel,
|
||||
deleteComponentAndVerify,
|
||||
} from "Support/utils/basicComponents";
|
||||
|
||||
import { deleteVersionText, onlydeleteVersionText } from "Texts/version";
|
||||
|
||||
import { createRestAPIQuery } from "Support/utils/dataSource";
|
||||
import { deleteQuery } from "Support/utils/queries";
|
||||
|
||||
import { selectEnv, appPromote } from "Support/utils/platform/multiEnv";
|
||||
describe("App Version", () => {
|
||||
let data;
|
||||
|
||||
|
|
@ -120,7 +114,15 @@ describe("App Version", () => {
|
|||
|
||||
// Preview and release verification
|
||||
cy.openInCurrentTab(commonWidgetSelector.previewButton);
|
||||
cy.url().should("include", "/home?version=v2");
|
||||
|
||||
cy.ifEnv("Community", () => {
|
||||
cy.url().should("include", "/home?version=v2");
|
||||
});
|
||||
|
||||
cy.ifEnv("Enterprise", () => {
|
||||
cy.url().should("include", "/home?env=development&version=v2");
|
||||
});
|
||||
|
||||
cy.openApp(
|
||||
"",
|
||||
Cypress.env("workspaceId"),
|
||||
|
|
@ -149,7 +151,11 @@ describe("App Version", () => {
|
|||
|
||||
createRestAPIQuery(data.query1, data.datasourceName, "", "", "/1", true);
|
||||
|
||||
// Version v2 creation and verification
|
||||
cy.ifEnv("Enterprise", () => {
|
||||
appPromote("development", "production");
|
||||
});
|
||||
|
||||
// Version v2 creation and verification and v2 is created from v1 production environment
|
||||
navigateToCreateNewVersionModal("v1");
|
||||
createNewVersion(["v2"], "v1");
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).verifyVisibleElement(
|
||||
|
|
@ -201,7 +207,8 @@ describe("App Version", () => {
|
|||
versionChecks.forEach((check) => {
|
||||
navigateToCreateNewVersionModal(check.create.from);
|
||||
createNewVersion([check.create.version], check.create.from);
|
||||
|
||||
cy.waitForAutoSave();
|
||||
cy.wait(1000);
|
||||
if (check.verify.component.value) {
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget(check.verify.component.selector)
|
||||
|
|
@ -224,6 +231,9 @@ describe("App Version", () => {
|
|||
);
|
||||
|
||||
// Version switching and component verification
|
||||
cy.ifEnv("Enterprise", () => {
|
||||
selectEnv("development");
|
||||
});
|
||||
cy.get(appVersionSelectors.currentVersionField("v5")).click();
|
||||
cy.contains(`[id*="react-select-"]`, "v4").click();
|
||||
cy.get(appVersionSelectors.currentVersionField("v4")).should(
|
||||
|
|
@ -238,7 +248,14 @@ describe("App Version", () => {
|
|||
|
||||
// Preview and version switching verification
|
||||
cy.openInCurrentTab(commonWidgetSelector.previewButton);
|
||||
cy.url().should("include", "/home?version=v4");
|
||||
|
||||
cy.ifEnv("Community", () => {
|
||||
cy.url().should("include", "/home?version=v4");
|
||||
});
|
||||
cy.ifEnv("Enterprise", () => {
|
||||
cy.url().should("include", "/home?env=development&version=v4");
|
||||
});
|
||||
|
||||
cy.get(commonWidgetSelector.draggableWidget("text1")).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Leanne Graham"
|
||||
|
|
@ -250,8 +267,74 @@ describe("App Version", () => {
|
|||
cy.get(
|
||||
commonWidgetSelector.draggableWidget("textInput")
|
||||
).verifyVisibleElement("have.value", "Ervin Howell");
|
||||
//url validation should be added after bug fix
|
||||
|
||||
// cy.url().should("include", "/home?version=v5");
|
||||
cy.ifEnv("Enterprise", () => {
|
||||
cy.openApp(
|
||||
"",
|
||||
Cypress.env("workspaceId"),
|
||||
Cypress.env("appId"),
|
||||
commonWidgetSelector.draggableWidget("textInput")
|
||||
);
|
||||
|
||||
navigateToCreateNewVersionModal("v5");
|
||||
createNewVersion(["v6"], "v5");
|
||||
cy.waitForAutoSave();
|
||||
cy.wait(1000);
|
||||
|
||||
appPromote("development", "staging");
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget("textInput")
|
||||
).verifyVisibleElement("have.value", "Ervin Howell");
|
||||
cy.get(`[data-cy="list-query-${data.query2}"]`).should("be.visible");
|
||||
|
||||
appPromote("staging", "production");
|
||||
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget("textInput")
|
||||
).verifyVisibleElement("have.value", "Ervin Howell");
|
||||
cy.get(`[data-cy="list-query-${data.query2}"]`).should("be.visible");
|
||||
|
||||
cy.openInCurrentTab(commonWidgetSelector.previewButton);
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget("textInput")
|
||||
).verifyVisibleElement("have.value", "Ervin Howell");
|
||||
cy.url().should("include", "/home?env=production&version=v6");
|
||||
|
||||
cy.wait(1000);
|
||||
|
||||
cy.get('[data-cy="preview-settings"]').click();
|
||||
switchVersionAndVerify("v6", "v1");
|
||||
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget("text1")
|
||||
).verifyVisibleElement("have.text", "Leanne Graham");
|
||||
// url bug
|
||||
// cy.url().should("include", "/home?env=production&version=v1");
|
||||
cy.wait(1000);
|
||||
cy.get('[data-cy="preview-settings"]').click();
|
||||
switchVersionAndVerify("v1", "v6");
|
||||
|
||||
cy.wait(1000);
|
||||
cy.get('[data-cy="preview-settings"]').click();
|
||||
selectEnv("staging");
|
||||
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget("textInput")
|
||||
).verifyVisibleElement("have.value", "Ervin Howell");
|
||||
// cy.url().should("include", "/home?env=staging&version=v6");
|
||||
|
||||
|
||||
cy.wait(1000);
|
||||
cy.get('[data-cy="preview-settings"]').click();
|
||||
selectEnv("development");
|
||||
|
||||
cy.wait(1000);
|
||||
cy.get('[data-cy="preview-settings"]').click();
|
||||
switchVersionAndVerify("v6", "v1");
|
||||
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget("text1")
|
||||
).verifyVisibleElement("have.text", "Leanne Graham");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,662 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
|
||||
import { commonEeText, ssoEeText } from "Texts/eeCommon";
|
||||
import { commonEeSelectors, multiEnvSelector } from "Selectors/eeCommon";
|
||||
import {
|
||||
verifyPromoteModalUI,
|
||||
verifyTooltipDisabled,
|
||||
} from "Support/utils/platform/eeCommon";
|
||||
import { dataSourceSelector } from "Selectors/dataSource";
|
||||
import {
|
||||
navigateToAppEditor,
|
||||
pinInspector,
|
||||
verifyTooltip,
|
||||
} from "Support/utils/common";
|
||||
import { addQuery, selectDatasource } from "Support/utils/dataSource";
|
||||
import {
|
||||
appPromote,
|
||||
createNewVersion,
|
||||
selectVersion,
|
||||
selectEnv,
|
||||
} from "Support/utils/platform/multiEnv";
|
||||
import { appVersionSelectors } from "Selectors/exportImport";
|
||||
|
||||
import { editAndVerifyWidgetName } from "Support/utils/commonWidget";
|
||||
import { deleteVersionAndVerify } from "Support/utils/version";
|
||||
import { deleteVersionText } from "Texts/version";
|
||||
|
||||
describe("Multi env", () => {
|
||||
const data = {};
|
||||
data.appName = `${fake.companyName} App`;
|
||||
data.ds = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.constName = fake.firstName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
const slug = data.appName.toLowerCase().replace(/\s+/g, "-");
|
||||
let currentVersion = "";
|
||||
let newVersion = [];
|
||||
let versionFrom = "";
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.viewport(1800, 1800);
|
||||
cy.skipWalkthrough();
|
||||
});
|
||||
|
||||
it.only("Verify the datasource configuration and data on each env", () => {
|
||||
cy.apiCreateGDS(
|
||||
`${Cypress.env("server_host")}/api/data-sources`,
|
||||
data.ds,
|
||||
"restapi",
|
||||
[
|
||||
{ key: "url", value: "" },
|
||||
{ key: "auth_type", value: "none" },
|
||||
{ key: "grant_type", value: "authorization_code" },
|
||||
{ key: "add_token_to", value: "header" },
|
||||
{ key: "header_prefix", value: "Bearer " },
|
||||
{ key: "access_token_url", value: "" },
|
||||
{ key: "client_ide", value: "" },
|
||||
{ key: "client_secret", value: "", encrypted: true },
|
||||
{ key: "scopes", value: "read, write" },
|
||||
{ key: "username", value: "", encrypted: false },
|
||||
{ key: "password", value: "", encrypted: true },
|
||||
{ key: "bearer_token", value: "", encrypted: true },
|
||||
{ key: "auth_url", value: "" },
|
||||
{ key: "client_auth", value: "header" },
|
||||
{ key: "headers", value: [["", ""]] },
|
||||
{ key: "custom_query_params", value: [["", ""]], encrypted: false },
|
||||
{ key: "custom_auth_params", value: [["", ""]] },
|
||||
{
|
||||
key: "access_token_custom_headers",
|
||||
value: [["", ""]],
|
||||
encrypted: false,
|
||||
},
|
||||
{ key: "multiple_auth_enabled", value: false, encrypted: false },
|
||||
{ key: "ssl_certificate", value: "none", encrypted: false },
|
||||
]
|
||||
);
|
||||
cy.apiCreateApp(data.appName);
|
||||
cy.visit("/my-workspace");
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
selectDatasource(data.ds);
|
||||
cy.get('[data-cy="development-label"]').click();
|
||||
cy.clearAndType(
|
||||
'[data-cy="base-url-text-field"]',
|
||||
"https://reqres.in/api/users?page=1"
|
||||
);
|
||||
cy.get(dataSourceSelector.buttonSave).click();
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
|
||||
cy.openApp();
|
||||
// cy.waitForAppLoad();
|
||||
cy.wait(2000);
|
||||
cy.get(`[data-cy="${data.ds}-add-query-card"] > .text-truncate`).click();
|
||||
cy.wait(1000);
|
||||
cy.get(dataSourceSelector.queryCreateAndRunButton).click();
|
||||
cy.get('[data-cy="query-tab-settings"]').click();
|
||||
cy.get(':nth-child(1) > .custom-toggle-switch > .switch > .slider').click();
|
||||
cy.waitForAutoSave();
|
||||
|
||||
cy.dragAndDropWidget("Text Input", 550, 650);
|
||||
editAndVerifyWidgetName(data.constName, []);
|
||||
cy.waitForAutoSave();
|
||||
|
||||
cy.get(
|
||||
'[data-cy="default-value-input-field"]'
|
||||
).clearAndTypeOnCodeMirror(`{{queries.restapi1.data.data[0].email`);
|
||||
cy.wait(1000);
|
||||
cy.forceClickOnCanvas();
|
||||
cy.waitForAutoSave();
|
||||
cy.get(dataSourceSelector.queryCreateAndRunButton).click();
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget(data.constName)
|
||||
).verifyVisibleElement("have.value", "george.bluth@reqres.in");
|
||||
|
||||
pinInspector();
|
||||
cy.get(commonWidgetSelector.sidebarinspector).click();
|
||||
cy.get(commonWidgetSelector.inspectorNodeComponents).click();
|
||||
cy.get(commonWidgetSelector.nodeComponent(data.constName)).click();
|
||||
cy.get('[data-cy="inspector-node-value"] > .mx-2').verifyVisibleElement(
|
||||
"have.text",
|
||||
`"george.bluth@reqres.in"`
|
||||
);
|
||||
cy.get('[style="height: 13px; width: 13px;"] > img').should("exist");
|
||||
cy.get('[data-cy="inspector-node-globals"] > .node-key').click();
|
||||
cy.get('[data-cy="inspector-node-environment"] > .node-key').click();
|
||||
cy.get('[data-cy="inspector-node-name"] > .mx-2').verifyVisibleElement(
|
||||
"have.text",
|
||||
`"development"`
|
||||
);
|
||||
|
||||
cy.openInCurrentTab(commonWidgetSelector.previewButton);
|
||||
cy.wait(4000);
|
||||
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget(data.constName)
|
||||
).verifyVisibleElement("have.value", "george.bluth@reqres.in");
|
||||
|
||||
cy.go("back");
|
||||
cy.waitForAppLoad();
|
||||
cy.wait(3000);
|
||||
cy.get(commonEeSelectors.promoteButton).click();
|
||||
cy.get(commonEeSelectors.promoteButton).eq(1).click();
|
||||
cy.waitForAppLoad();
|
||||
cy.wait(3000);
|
||||
|
||||
cy.get(dataSourceSelector.queryCreateAndRunButton, {
|
||||
timeout: 20000,
|
||||
}).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
"Query could not be completed"
|
||||
);
|
||||
|
||||
cy.backToApps();
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
selectDatasource(data.ds);
|
||||
cy.get('[data-cy="staging-label"]').click();
|
||||
cy.clearAndType(
|
||||
'[data-cy="base-url-text-field"]',
|
||||
"https://reqres.in/api/users?page=2"
|
||||
);
|
||||
cy.get(dataSourceSelector.buttonSave).click();
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
navigateToAppEditor(data.appName);
|
||||
cy.get(dataSourceSelector.queryCreateAndRunButton).click();
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget(data.constName)
|
||||
).verifyVisibleElement("have.value", "michael.lawson@reqres.in");
|
||||
|
||||
cy.get(commonWidgetSelector.sidebarinspector).click();
|
||||
cy.get(commonWidgetSelector.inspectorNodeComponents).click();
|
||||
cy.get(commonWidgetSelector.nodeComponent(data.constName)).click();
|
||||
cy.get('[data-cy="inspector-node-value"] > .mx-2').verifyVisibleElement(
|
||||
"have.text",
|
||||
`"michael.lawson@reqres.in"`
|
||||
);
|
||||
cy.get('[style="height: 13px; width: 13px;"] > img').should("not.exist");
|
||||
cy.get('[data-cy="inspector-node-globals"] > .node-key').click();
|
||||
cy.get('[data-cy="inspector-node-environment"] > .node-key').click();
|
||||
cy.get('[data-cy="inspector-node-name"] > .mx-2').verifyVisibleElement(
|
||||
"have.text",
|
||||
`"staging"`
|
||||
);
|
||||
|
||||
cy.openInCurrentTab(commonWidgetSelector.previewButton);
|
||||
cy.wait(4000);
|
||||
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget(data.constName)
|
||||
).verifyVisibleElement("have.value", "michael.lawson@reqres.in");
|
||||
|
||||
cy.go("back");
|
||||
cy.waitForAppLoad();
|
||||
cy.wait(3000);
|
||||
cy.get(commonEeSelectors.promoteButton).click();
|
||||
cy.get(commonEeSelectors.promoteButton).eq(1).click();
|
||||
cy.waitForAppLoad();
|
||||
cy.wait(3000);
|
||||
|
||||
cy.get(dataSourceSelector.queryCreateAndRunButton, {
|
||||
timeout: 20000,
|
||||
}).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
"Query could not be completed"
|
||||
);
|
||||
|
||||
cy.backToApps();
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
selectDatasource(data.ds);
|
||||
cy.get('[data-cy="production-label"]').click();
|
||||
cy.clearAndType(
|
||||
'[data-cy="base-url-text-field"]',
|
||||
"https://reqres.in/api/users?page=1"
|
||||
);
|
||||
cy.get(dataSourceSelector.buttonSave).click();
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
navigateToAppEditor(data.appName);
|
||||
cy.get(dataSourceSelector.queryCreateAndRunButton).click();
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget(data.constName)
|
||||
).verifyVisibleElement("have.value", "george.bluth@reqres.in");
|
||||
|
||||
cy.get(commonWidgetSelector.sidebarinspector).click();
|
||||
cy.get(commonWidgetSelector.inspectorNodeComponents).click();
|
||||
cy.get(commonWidgetSelector.nodeComponent(data.constName)).click();
|
||||
cy.get('[data-cy="inspector-node-value"] > .mx-2').verifyVisibleElement(
|
||||
"have.text",
|
||||
`"george.bluth@reqres.in"`
|
||||
);
|
||||
cy.get('[style="height: 13px; width: 13px;"] > img').should("not.exist");
|
||||
cy.get('[data-cy="inspector-node-globals"] > .node-key').click();
|
||||
cy.get('[data-cy="inspector-node-environment"] > .node-key').click();
|
||||
cy.get('[data-cy="inspector-node-name"] > .mx-2').verifyVisibleElement(
|
||||
"have.text",
|
||||
`"production"`
|
||||
);
|
||||
|
||||
cy.openInCurrentTab(commonWidgetSelector.previewButton);
|
||||
cy.wait(4000);
|
||||
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget(data.constName)
|
||||
).verifyVisibleElement("have.value", "george.bluth@reqres.in");
|
||||
|
||||
cy.go("back");
|
||||
cy.waitForAppLoad();
|
||||
cy.wait(3000);
|
||||
cy.get(commonSelectors.releaseButton).click();
|
||||
cy.get(commonSelectors.yesButton).click();
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, "Version v1 released");
|
||||
cy.wait(4000);
|
||||
|
||||
cy.get(commonWidgetSelector.shareAppButton).click();
|
||||
cy.clearAndType(commonWidgetSelector.appNameSlugInput, `${slug}`);
|
||||
cy.wait(2000);
|
||||
cy.get(commonWidgetSelector.modalCloseButton).click();
|
||||
|
||||
cy.visit(`/applications/${slug}`);
|
||||
cy.get(
|
||||
commonWidgetSelector.draggableWidget(data.constName)
|
||||
).verifyVisibleElement("have.value", "george.bluth@reqres.in");
|
||||
});
|
||||
|
||||
it("should verify edit privilages of a promoted version", () => {
|
||||
data.appName = `${fake.companyName} App`;
|
||||
cy.apiCreateApp(data.appName);
|
||||
cy.openApp();
|
||||
cy.waitForAppLoad();
|
||||
cy.dragAndDropWidget("Text", 550, 650);
|
||||
appPromote("development", "production");
|
||||
|
||||
createNewVersion(
|
||||
(currentVersion = "v1"),
|
||||
(newVersion = ["v2"]),
|
||||
(versionFrom = "v1")
|
||||
);
|
||||
appPromote("development", "release");
|
||||
|
||||
createNewVersion(
|
||||
(currentVersion = "v2"),
|
||||
(newVersion = ["v3"]),
|
||||
(versionFrom = "v2")
|
||||
);
|
||||
appPromote("development", "staging");
|
||||
|
||||
selectVersion((currentVersion = "v3"), (newVersion = ["v1"]));
|
||||
cy.get(commonSelectors.warningText).eq(0).verifyVisibleElement(
|
||||
"have.text",
|
||||
"App cannot be edited after promotion. Please create a new version from Development to make any changes."
|
||||
);
|
||||
|
||||
cy.forceClickOnCanvas();
|
||||
cy.get(".datasource-picker").should("have.class", "disabled");
|
||||
cy.get(commonEeSelectors.AddQueryButton).should("be.disabled");
|
||||
cy.get(".components-container").should("have.class", "disabled");
|
||||
|
||||
cy.wait(1000);
|
||||
selectEnv("development");
|
||||
cy.get(commonSelectors.warningText).eq(0).verifyVisibleElement(
|
||||
"have.text",
|
||||
"App cannot be edited after promotion. Please create a new version from Development to make any changes."
|
||||
);
|
||||
cy.get(".datasource-picker").should("have.class", "disabled");
|
||||
cy.get(commonEeSelectors.AddQueryButton).should("be.disabled");
|
||||
cy.get(".components-container").should("have.class", "disabled");
|
||||
|
||||
selectVersion((currentVersion = "v1"), (newVersion = ["v2"]));
|
||||
cy.get(commonSelectors.warningText).eq(0).verifyVisibleElement(
|
||||
"have.text",
|
||||
"This version of the app is released. Please create a new version in development to make any changes."
|
||||
);
|
||||
cy.get(".datasource-picker").should("have.class", "disabled");
|
||||
cy.get(commonEeSelectors.AddQueryButton).should("be.disabled");
|
||||
cy.get(".components-container").should("have.class", "disabled");
|
||||
|
||||
cy.wait(1000);
|
||||
selectEnv("staging");
|
||||
cy.get(commonSelectors.warningText).eq(0).verifyVisibleElement(
|
||||
"have.text",
|
||||
"This version of the app is released. Please create a new version in development to make any changes."
|
||||
);
|
||||
cy.get(".datasource-picker").should("have.class", "disabled");
|
||||
cy.get(commonEeSelectors.AddQueryButton).should("be.disabled");
|
||||
cy.get(".components-container").should("have.class", "disabled");
|
||||
|
||||
cy.wait(1000);
|
||||
selectEnv("production");
|
||||
cy.get(commonSelectors.warningText).eq(0).verifyVisibleElement(
|
||||
"have.text",
|
||||
"This version of the app is released. Please create a new version in development to make any changes."
|
||||
);
|
||||
cy.get(".datasource-picker").should("have.class", "disabled");
|
||||
cy.get(commonEeSelectors.AddQueryButton).should("be.disabled");
|
||||
cy.get(".components-container").should("have.class", "disabled");
|
||||
cy.get(commonSelectors.releaseButton).should("be.disabled");
|
||||
});
|
||||
|
||||
it("Should verify last exisiting version", () => {
|
||||
data.appName = `${fake.companyName} App`;
|
||||
cy.apiCreateApp(data.appName);
|
||||
cy.openApp();
|
||||
cy.waitForAppLoad();
|
||||
cy.dragAndDropWidget("Text", 550, 650);
|
||||
|
||||
appPromote("development", "staging");
|
||||
createNewVersion(
|
||||
(currentVersion = "v1"),
|
||||
(newVersion = ["v2"]),
|
||||
(versionFrom = "v1")
|
||||
);
|
||||
|
||||
selectVersion((currentVersion = "v2"), (newVersion = ["v1"]));
|
||||
|
||||
cy.wait(1000);
|
||||
selectEnv("staging");
|
||||
|
||||
cy.get(appVersionSelectors.currentVersionField(newVersion[0]))
|
||||
.should("be.visible")
|
||||
.and("have.text", "v1");
|
||||
|
||||
appPromote("staging", "production");
|
||||
|
||||
cy.wait(3000)
|
||||
deleteVersionAndVerify(
|
||||
(currentVersion = "v1"),
|
||||
deleteVersionText.deleteToastMessage((currentVersion = "v1"))
|
||||
);
|
||||
|
||||
cy.wait(2000);
|
||||
cy.get('[data-cy="list-current-env-name"]').click();
|
||||
verifyTooltip(
|
||||
'[data-cy="env-name-dropdown"]:eq(1)',
|
||||
"There are no versions in this environment"
|
||||
);
|
||||
verifyTooltip(
|
||||
'[data-cy="env-name-dropdown"]:eq(2)',
|
||||
"There are no versions in this environment"
|
||||
);
|
||||
});
|
||||
|
||||
it("Should verify version deletion", () => {
|
||||
data.appName = `${fake.companyName} App`;
|
||||
cy.apiCreateApp(data.appName);
|
||||
cy.openApp();
|
||||
cy.waitForAppLoad();
|
||||
cy.dragAndDropWidget("Text", 550, 650);
|
||||
|
||||
appPromote("development", "staging");
|
||||
createNewVersion(
|
||||
(currentVersion = "v1"),
|
||||
(newVersion = ["v2"]),
|
||||
(versionFrom = "v1")
|
||||
);
|
||||
appPromote("development", "staging");
|
||||
|
||||
createNewVersion(
|
||||
(currentVersion = "v2"),
|
||||
(newVersion = ["v3"]),
|
||||
(versionFrom = "v2")
|
||||
);
|
||||
appPromote("development", "production");
|
||||
|
||||
selectEnv("staging");
|
||||
selectVersion((currentVersion = "v3"), (newVersion = ["v2"]));
|
||||
deleteVersionAndVerify(
|
||||
(currentVersion = "v2"),
|
||||
deleteVersionText.deleteToastMessage((currentVersion = "v2"))
|
||||
);
|
||||
|
||||
cy.get('[data-cy="v3-current-version-text"]')
|
||||
.should("be.visible")
|
||||
.and("have.text", "v3");
|
||||
|
||||
cy.get('[data-cy="list-current-env-name"]').should(
|
||||
"have.text",
|
||||
"Staging"
|
||||
);
|
||||
})
|
||||
|
||||
it("Verify the multi env components UI", () => {
|
||||
data.appName = `${fake.companyName} App`;
|
||||
cy.apiCreateApp(data.appName);
|
||||
cy.openApp();
|
||||
cy.waitForAppLoad();
|
||||
cy.dragAndDropWidget("Text", 550, 650);
|
||||
cy.get(multiEnvSelector.envContainer).should("be.visible");
|
||||
cy.get(multiEnvSelector.currentEnvName)
|
||||
.verifyVisibleElement("have.text", "Development")
|
||||
.click();
|
||||
cy.get(multiEnvSelector.envArrow).should("be.visible");
|
||||
cy.get(multiEnvSelector.selectedEnvName).verifyVisibleElement(
|
||||
"have.text",
|
||||
" Development"
|
||||
);
|
||||
cy.get(multiEnvSelector.envNameList)
|
||||
.eq(0)
|
||||
.verifyVisibleElement("have.text", "Development");
|
||||
cy.get(multiEnvSelector.envNameList)
|
||||
.eq(1)
|
||||
.verifyVisibleElement("have.text", "Staging");
|
||||
cy.get(multiEnvSelector.envNameList)
|
||||
.eq(2)
|
||||
.verifyVisibleElement("have.text", "Production");
|
||||
|
||||
verifyTooltip(
|
||||
'[data-cy="env-name-dropdown"]:eq(1)',
|
||||
"There are no versions in this environment"
|
||||
);
|
||||
verifyTooltip(
|
||||
'[data-cy="env-name-dropdown"]:eq(2)',
|
||||
"There are no versions in this environment"
|
||||
);
|
||||
|
||||
cy.get(multiEnvSelector.appVersionLabel).should("be.visible");
|
||||
cy.get('[data-cy="v1-current-version-text"]')
|
||||
.verifyVisibleElement("have.text", "v1")
|
||||
.click();
|
||||
cy.get(multiEnvSelector.currentVersion).verifyVisibleElement(
|
||||
"have.text",
|
||||
"v1"
|
||||
);
|
||||
cy.get(".col-10 > .app-version-name").verifyVisibleElement(
|
||||
"have.text",
|
||||
"v1"
|
||||
);
|
||||
cy.get(multiEnvSelector.createNewVersionButton).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Create new version"
|
||||
);
|
||||
|
||||
verifyPromoteModalUI("v1", "Development", "Staging");
|
||||
cy.get('[data-cy="env-change-info-text"]').verifyVisibleElement(
|
||||
"have.text",
|
||||
"You won’t be able to edit this version after promotion. Are you sure you want to continue?"
|
||||
);
|
||||
cy.get(commonSelectors.closeButton).click();
|
||||
cy.get(multiEnvSelector.currentEnvName).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Development"
|
||||
);
|
||||
|
||||
cy.get(commonEeSelectors.promoteButton).click();
|
||||
cy.get(commonSelectors.cancelButton).click();
|
||||
cy.get(multiEnvSelector.currentEnvName).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Development"
|
||||
);
|
||||
|
||||
cy.get(commonEeSelectors.promoteButton).click();
|
||||
cy.get(commonEeSelectors.promoteButton).eq(1).click();
|
||||
|
||||
cy.waitForAppLoad();
|
||||
cy.wait(3000);
|
||||
|
||||
cy.get(commonSelectors.warningText).eq(0).verifyVisibleElement(
|
||||
"have.text",
|
||||
"App cannot be edited after promotion. Please create a new version from Development to make any changes."
|
||||
);
|
||||
cy.get(multiEnvSelector.envContainer).should("be.visible");
|
||||
cy.get(multiEnvSelector.currentEnvName)
|
||||
.verifyVisibleElement("have.text", "Staging")
|
||||
.click();
|
||||
cy.get(multiEnvSelector.envArrow).should("be.visible");
|
||||
cy.get(multiEnvSelector.currentEnvName).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Staging"
|
||||
);
|
||||
cy.get(multiEnvSelector.envNameList)
|
||||
.eq(0)
|
||||
.verifyVisibleElement("have.text", "Development");
|
||||
cy.get(multiEnvSelector.envNameList)
|
||||
.eq(1)
|
||||
.verifyVisibleElement("have.text", "Staging");
|
||||
cy.get(multiEnvSelector.envNameList)
|
||||
.eq(2)
|
||||
.verifyVisibleElement("have.text", "Production");
|
||||
cy.wait(2000)
|
||||
verifyTooltip(
|
||||
'[data-cy="env-name-dropdown"]:eq(2)',
|
||||
"There are no versions in this environment"
|
||||
);
|
||||
|
||||
cy.get(multiEnvSelector.appVersionLabel).should("be.visible");
|
||||
cy.get('[data-cy="v1-current-version-text"]')
|
||||
.verifyVisibleElement("have.text", "v1")
|
||||
.click();
|
||||
cy.get(multiEnvSelector.currentVersion).verifyVisibleElement(
|
||||
"have.text",
|
||||
"v1"
|
||||
);
|
||||
cy.get(".col-10 > .app-version-name").verifyVisibleElement(
|
||||
"have.text",
|
||||
"v1"
|
||||
);
|
||||
cy.get(multiEnvSelector.createNewVersionButton).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Create new version"
|
||||
);
|
||||
|
||||
verifyTooltip(
|
||||
multiEnvSelector.createNewVersionButton,
|
||||
"New versions can only be created in development"
|
||||
);
|
||||
cy.forceClickOnCanvas();
|
||||
cy.get(".datasource-picker").should("have.class", "disabled");
|
||||
cy.get(commonEeSelectors.AddQueryButton).should("be.disabled");
|
||||
cy.get(".components-container").should("have.class", "disabled");
|
||||
|
||||
verifyPromoteModalUI("v1", "Staging", "Production");
|
||||
cy.get(commonSelectors.closeButton).click();
|
||||
cy.get(multiEnvSelector.currentEnvName).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Staging"
|
||||
);
|
||||
|
||||
cy.get(commonEeSelectors.promoteButton).click();
|
||||
cy.get(commonSelectors.cancelButton).click();
|
||||
cy.get(multiEnvSelector.currentEnvName).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Staging"
|
||||
);
|
||||
|
||||
cy.get(commonEeSelectors.promoteButton).click();
|
||||
cy.get(commonEeSelectors.promoteButton).eq(1).click();
|
||||
cy.waitForAppLoad();
|
||||
cy.wait(3000);
|
||||
|
||||
cy.get(commonSelectors.warningText).eq(0).verifyVisibleElement(
|
||||
"have.text",
|
||||
"App cannot be edited after promotion. Please create a new version from Development to make any changes."
|
||||
);
|
||||
cy.get(multiEnvSelector.envContainer).should("be.visible");
|
||||
cy.get(multiEnvSelector.currentEnvName)
|
||||
.verifyVisibleElement("have.text", "Production")
|
||||
.click();
|
||||
cy.get(multiEnvSelector.envArrow).should("be.visible");
|
||||
cy.get(multiEnvSelector.currentEnvName).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Production"
|
||||
);
|
||||
cy.get(multiEnvSelector.envNameList)
|
||||
.eq(0)
|
||||
.verifyVisibleElement("have.text", "Development");
|
||||
cy.get(multiEnvSelector.envNameList)
|
||||
.eq(1)
|
||||
.verifyVisibleElement("have.text", "Staging");
|
||||
cy.get(multiEnvSelector.envNameList)
|
||||
.eq(2)
|
||||
.verifyVisibleElement("have.text", "Production");
|
||||
|
||||
cy.get(multiEnvSelector.appVersionLabel).should("be.visible");
|
||||
cy.get('[data-cy="v1-current-version-text"]')
|
||||
.verifyVisibleElement("have.text", "v1")
|
||||
.click();
|
||||
cy.get(multiEnvSelector.currentVersion).verifyVisibleElement(
|
||||
"have.text",
|
||||
"v1"
|
||||
);
|
||||
cy.get(".col-10 > .app-version-name").verifyVisibleElement(
|
||||
"have.text",
|
||||
"v1"
|
||||
);
|
||||
cy.get(multiEnvSelector.createNewVersionButton).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Create new version"
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.releaseButton)
|
||||
.verifyVisibleElement("have.text", "Release")
|
||||
.click();
|
||||
cy.get('[data-cy="modal-title"]').verifyVisibleElement(
|
||||
"have.text",
|
||||
"Release Version"
|
||||
);
|
||||
cy.get(commonSelectors.closeButton).should("be.visible");
|
||||
cy.get('[data-cy="confirm-dialogue-box-text"]').verifyVisibleElement(
|
||||
"have.text",
|
||||
"Are you sure you want to release this version?"
|
||||
);
|
||||
cy.get(commonSelectors.cancelButton).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Cancel"
|
||||
);
|
||||
cy.get(commonSelectors.yesButton).verifyVisibleElement("have.text", "Yes");
|
||||
|
||||
cy.get(commonSelectors.closeButton).click();
|
||||
cy.get(multiEnvSelector.currentEnvName).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Production"
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.releaseButton).click();
|
||||
cy.get(commonSelectors.cancelButton).click();
|
||||
cy.get(multiEnvSelector.currentEnvName).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Production"
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.releaseButton).click();
|
||||
cy.get(commonSelectors.yesButton).click();
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, "Version v1 released");
|
||||
cy.wait(500);
|
||||
cy.get(commonSelectors.warningText).eq(0).verifyVisibleElement(
|
||||
"have.text",
|
||||
"This version of the app is released. Please create a new version in development to make any changes."
|
||||
);
|
||||
cy.get('[data-cy="v1-current-version-text"]').click();
|
||||
verifyTooltip(
|
||||
multiEnvSelector.createNewVersionButton,
|
||||
"New versions can only be created in development"
|
||||
);
|
||||
cy.get(".datasource-picker").should("have.class", "disabled");
|
||||
cy.get(commonEeSelectors.AddQueryButton).should("be.disabled");
|
||||
cy.get(".components-container").should("have.class", "disabled");
|
||||
cy.get(commonSelectors.releaseButton).should("be.disabled");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,112 +1,132 @@
|
|||
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
|
||||
import { appPromote } from "Support/utils/platform/multiEnv";
|
||||
|
||||
const slugValidations = [
|
||||
{ input: "", error: "App slug can't be empty" },
|
||||
{ input: "_2#", error: "Special characters are not accepted." },
|
||||
{ input: "t ", error: "Cannot contain spaces" },
|
||||
{ input: "T", error: "Only lowercase letters are accepted." },
|
||||
{ input: "", error: "App slug can't be empty" },
|
||||
{ input: "_2#", error: "Special characters are not accepted." },
|
||||
{ input: "t ", error: "Cannot contain spaces" },
|
||||
{ input: "T", error: "Only lowercase letters are accepted." },
|
||||
];
|
||||
|
||||
export const verifySlugValidations = (inputSelector) => {
|
||||
slugValidations.forEach(({ input, error }) => {
|
||||
cy.get(inputSelector).clear();
|
||||
if (input) cy.clearAndType(inputSelector, input);
|
||||
cy.wait(500);
|
||||
cy.get(commonWidgetSelector.appSlugErrorLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
error
|
||||
);
|
||||
});
|
||||
slugValidations.forEach(({ input, error }) => {
|
||||
cy.get(inputSelector).clear();
|
||||
if (input) cy.clearAndType(inputSelector, input);
|
||||
cy.wait(500);
|
||||
cy.get(commonWidgetSelector.appSlugErrorLabel).verifyVisibleElement(
|
||||
"have.text",
|
||||
error
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export const verifySuccessfulSlugUpdate = (workspaceId, slug) => {
|
||||
const host = resolveHost();
|
||||
cy.get('[data-cy="app-slug-accepted-label"]').verifyVisibleElement(
|
||||
"have.text",
|
||||
"Slug accepted!"
|
||||
);
|
||||
const host = resolveHost();
|
||||
cy.get('[data-cy="app-slug-accepted-label"]').verifyVisibleElement(
|
||||
"have.text",
|
||||
"Slug accepted!"
|
||||
);
|
||||
|
||||
cy.wait(500);
|
||||
// cy.get(commonWidgetSelector.appLinkSucessLabel).should('be.visible');
|
||||
cy.get(commonWidgetSelector.appLinkSucessLabel).should(
|
||||
"have.text",
|
||||
"Link updated successfully!"
|
||||
);
|
||||
cy.get(commonWidgetSelector.appLinkField).verifyVisibleElement(
|
||||
"have.text",
|
||||
`${host}/${workspaceId}/apps/${slug}`
|
||||
);
|
||||
cy.wait(500);
|
||||
// cy.get(commonWidgetSelector.appLinkSucessLabel).should('be.visible');
|
||||
cy.get(commonWidgetSelector.appLinkSucessLabel).should(
|
||||
"have.text",
|
||||
"Link updated successfully!"
|
||||
);
|
||||
cy.get(commonWidgetSelector.appLinkField).verifyVisibleElement(
|
||||
"have.text",
|
||||
`${host}/${workspaceId}/apps/${slug}`
|
||||
);
|
||||
};
|
||||
|
||||
export const verifyURLs = (workspaceId, slug, page) => {
|
||||
const baseUrl = Cypress.config("baseUrl");
|
||||
const baseUrl = Cypress.config("baseUrl");
|
||||
|
||||
cy.url().should(
|
||||
"eq",
|
||||
page
|
||||
? `${baseUrl}/${workspaceId}/apps/${slug}/home`
|
||||
: `${baseUrl}/${workspaceId}/apps/${slug}`
|
||||
);
|
||||
cy.url().should(
|
||||
"eq",
|
||||
page
|
||||
? `${baseUrl}/${workspaceId}/apps/${slug}/home`
|
||||
: `${baseUrl}/${workspaceId}/apps/${slug}`
|
||||
);
|
||||
|
||||
cy.openInCurrentTab(commonWidgetSelector.previewButton);
|
||||
cy.openInCurrentTab(commonWidgetSelector.previewButton);
|
||||
cy.ifEnv("Community", () => {
|
||||
cy.url().should("eq", `${baseUrl}/applications/${slug}/home?version=v1`);
|
||||
});
|
||||
cy.ifEnv("Enterprise", () => {
|
||||
cy.url().should(
|
||||
"eq",
|
||||
`${baseUrl}/applications/${slug}/home?env=production&version=v1`
|
||||
);
|
||||
});
|
||||
|
||||
cy.visit("/my-workspace");
|
||||
cy.visitSlug({
|
||||
actualUrl: `${baseUrl}/applications/${slug}`,
|
||||
});
|
||||
cy.url().should("eq", `${baseUrl}/applications/${slug}`);
|
||||
cy.visit("/my-workspace");
|
||||
cy.visitSlug({
|
||||
actualUrl: `${baseUrl}/applications/${slug}`,
|
||||
});
|
||||
cy.url().should("eq", `${baseUrl}/applications/${slug}`);
|
||||
};
|
||||
|
||||
export const setUpSlug = (slug) => {
|
||||
cy.get(commonWidgetSelector.shareAppButton).click();
|
||||
cy.clearAndType(commonWidgetSelector.appNameSlugInput, slug);
|
||||
cy.get('[data-cy="app-slug-accepted-label"]')
|
||||
.should("be.visible")
|
||||
.and("have.text", "Slug accepted!");
|
||||
cy.get(commonWidgetSelector.modalCloseButton).click();
|
||||
cy.get(commonWidgetSelector.shareAppButton).click();
|
||||
cy.clearAndType(commonWidgetSelector.appNameSlugInput, slug);
|
||||
cy.get('[data-cy="app-slug-accepted-label"]')
|
||||
.should("be.visible")
|
||||
.and("have.text", "Slug accepted!");
|
||||
cy.get(commonWidgetSelector.modalCloseButton).click();
|
||||
};
|
||||
|
||||
export const setupAppWithSlug = (appName, slug) => {
|
||||
cy.apiCreateApp(appName);
|
||||
cy.apiAddComponentToApp(appName, "text1");
|
||||
cy.apiReleaseApp(appName);
|
||||
cy.apiAddAppSlug(appName, slug);
|
||||
cy.apiCreateApp(appName);
|
||||
cy.apiAddComponentToApp(appName, "text1");
|
||||
|
||||
cy.ifEnv("Enterprise", () => {
|
||||
cy.openApp(
|
||||
"",
|
||||
Cypress.env("workspaceId"),
|
||||
Cypress.env("appId"),
|
||||
commonWidgetSelector.draggableWidget("text1")
|
||||
);
|
||||
appPromote("development", "production");
|
||||
});
|
||||
|
||||
cy.apiReleaseApp(appName);
|
||||
cy.apiAddAppSlug(appName, slug);
|
||||
};
|
||||
|
||||
export const verifyRestrictedAccess = () => {
|
||||
cy.get('[data-cy="modal-header"]').should("have.text", "Restricted access");
|
||||
cy.get('[data-cy="modal-description"]')
|
||||
.invoke("text")
|
||||
.then((text) => {
|
||||
const normalizedText = text.replace(/’/g, "'");
|
||||
expect(normalizedText).to.equal(
|
||||
"You don't have access to this app. Kindly contact admin to know more."
|
||||
);
|
||||
});
|
||||
cy.get('[data-cy="back-to-home-button"]').verifyVisibleElement(
|
||||
"have.text",
|
||||
"Back to home page"
|
||||
);
|
||||
cy.get('[data-cy="modal-header"]').should("have.text", "Restricted access");
|
||||
cy.get('[data-cy="modal-description"]')
|
||||
.invoke("text")
|
||||
.then((text) => {
|
||||
const normalizedText = text.replace(/’/g, "'");
|
||||
expect(normalizedText).to.equal(
|
||||
"You don't have access to this app. Kindly contact admin to know more."
|
||||
);
|
||||
});
|
||||
cy.get('[data-cy="back-to-home-button"]').verifyVisibleElement(
|
||||
"have.text",
|
||||
"Back to home page"
|
||||
);
|
||||
};
|
||||
|
||||
export const onboardUserFromAppLink = (
|
||||
email,
|
||||
slug,
|
||||
workspaceName = "My workspace",
|
||||
isNonExistingUser = true
|
||||
email,
|
||||
slug,
|
||||
workspaceName = "My workspace",
|
||||
isNonExistingUser = true
|
||||
) => {
|
||||
const dbConfig = Cypress.env("app_db");
|
||||
const dbConfig = Cypress.env("app_db");
|
||||
|
||||
const query = isNonExistingUser
|
||||
? `
|
||||
const query = isNonExistingUser
|
||||
? `
|
||||
SELECT u.invitation_token, o.id AS workspace_id, ou.invitation_token AS organization_token
|
||||
FROM users u
|
||||
JOIN organization_users ou ON u.id = ou.user_id
|
||||
JOIN organizations o ON ou.organization_id = o.id
|
||||
WHERE u.email = '${email}' AND o.name = '${workspaceName}';
|
||||
`
|
||||
: `
|
||||
: `
|
||||
SELECT ou.invitation_token, o.id AS workspace_id
|
||||
FROM users u
|
||||
JOIN organization_users ou ON u.id = ou.user_id
|
||||
|
|
@ -114,33 +134,33 @@ export const onboardUserFromAppLink = (
|
|||
WHERE u.email = '${email}' AND o.name = '${workspaceName}';
|
||||
`;
|
||||
|
||||
cy.task("dbConnection", { dbconfig: dbConfig, sql: query }).then((resp) => {
|
||||
if (!resp.rows || resp.rows.length === 0) {
|
||||
throw new Error(
|
||||
`No records found for email: ${email} and workspace: ${workspaceName}`
|
||||
);
|
||||
}
|
||||
cy.task("dbConnection", { dbconfig: dbConfig, sql: query }).then((resp) => {
|
||||
if (!resp.rows || resp.rows.length === 0) {
|
||||
throw new Error(
|
||||
`No records found for email: ${email} and workspace: ${workspaceName}`
|
||||
);
|
||||
}
|
||||
|
||||
const { invitation_token, workspace_id, organization_token } = resp.rows[0];
|
||||
const token = isNonExistingUser ? organization_token : invitation_token;
|
||||
const url = isNonExistingUser
|
||||
? `${Cypress.config("baseUrl")}/invitations/${invitation_token}/workspaces/${organization_token}?oid=${workspace_id}&redirectTo=%2Fapplications%2F${slug}`
|
||||
: `${Cypress.config("baseUrl")}/organization-invitations/${token}?oid=${workspace_id}&redirectTo=%2Fapplications%2F${slug}`;
|
||||
const { invitation_token, workspace_id, organization_token } = resp.rows[0];
|
||||
const token = isNonExistingUser ? organization_token : invitation_token;
|
||||
const url = isNonExistingUser
|
||||
? `${Cypress.config("baseUrl")}/invitations/${invitation_token}/workspaces/${organization_token}?oid=${workspace_id}&redirectTo=%2Fapplications%2F${slug}`
|
||||
: `${Cypress.config("baseUrl")}/organization-invitations/${token}?oid=${workspace_id}&redirectTo=%2Fapplications%2F${slug}`;
|
||||
|
||||
cy.visit(url);
|
||||
});
|
||||
cy.visit(url);
|
||||
});
|
||||
};
|
||||
|
||||
export const resolveHost = () => {
|
||||
const baseUrl = Cypress.config("baseUrl");
|
||||
const baseUrl = Cypress.config("baseUrl");
|
||||
|
||||
const urlMapping = {
|
||||
"http://localhost:8082": "http://localhost:8082",
|
||||
"http://localhost:3000": "http://localhost:3000",
|
||||
"http://localhost:3000/apps": "http://localhost:3000/apps",
|
||||
"http://localhost:4001": "http://localhost:3000",
|
||||
"http://localhost:4001/apps": "http://localhost:3000/apps",
|
||||
};
|
||||
const urlMapping = {
|
||||
"http://localhost:8082": "http://localhost:8082",
|
||||
"http://localhost:3000": "http://localhost:3000",
|
||||
"http://localhost:3000/apps": "http://localhost:3000/apps",
|
||||
"http://localhost:4001": "http://localhost:3000",
|
||||
"http://localhost:4001/apps": "http://localhost:3000/apps",
|
||||
};
|
||||
|
||||
return urlMapping[baseUrl];
|
||||
return urlMapping[baseUrl];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import moment from "moment";
|
|||
import { dashboardSelector } from "Selectors/dashboard";
|
||||
import { groupsSelector } from "Selectors/manageGroups";
|
||||
import { groupsText } from "Texts/manageGroups";
|
||||
import { appPromote } from "Support/utils/platform/multiEnv";
|
||||
|
||||
export const navigateToProfile = () => {
|
||||
cy.get(commonSelectors.settingsIcon).click();
|
||||
|
|
@ -48,7 +49,7 @@ export const randomDateOrTime = (format = "DD/MM/YYYY") => {
|
|||
let startDate = new Date(2018, 0, 1);
|
||||
startDate = new Date(
|
||||
startDate.getTime() +
|
||||
Math.random() * (endDate.getTime() - startDate.getTime())
|
||||
Math.random() * (endDate.getTime() - startDate.getTime())
|
||||
);
|
||||
return moment(startDate).format(format);
|
||||
};
|
||||
|
|
@ -104,7 +105,7 @@ export const viewAppCardOptions = (appName) => {
|
|||
cy.get(commonSelectors.appCard(appName))
|
||||
.realHover()
|
||||
.find(commonSelectors.appCardOptionsButton)
|
||||
.realHover()
|
||||
.realHover();
|
||||
cy.contains("div", appName)
|
||||
.parent()
|
||||
.within(() => {
|
||||
|
|
@ -230,6 +231,9 @@ export const navigateToworkspaceConstants = () => {
|
|||
};
|
||||
|
||||
export const releaseApp = () => {
|
||||
cy.ifEnv("Enterprise", () => {
|
||||
appPromote("development", "production");
|
||||
});
|
||||
cy.get(commonSelectors.releaseButton).click();
|
||||
cy.get(commonSelectors.yesButton).click();
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, "Version v1 released");
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ export const userSignUp = (fullName, email, workspaceName = "test") => {
|
|||
cy.visit(invitationLink);
|
||||
cy.wait(2500);
|
||||
});
|
||||
if (Cypress.env("environment") !== "Community") {
|
||||
if (Cypress.env("environment") == "Cloud") {
|
||||
cy.clearAndType(
|
||||
'[data-cy="onboarding-workspace-name-input"]',
|
||||
workspaceName
|
||||
|
|
|
|||
120
cypress-tests/cypress/support/utils/platform/multiEnv.js
Normal file
120
cypress-tests/cypress/support/utils/platform/multiEnv.js
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
import { multiEnvSelector, commonEeSelectors } from "Selectors/eeCommon";
|
||||
import { commonSelectors, commonWidgetSelector } from "Selectors/common";
|
||||
import { appVersionSelectors } from "Selectors/exportImport";
|
||||
import { appVersionText } from "Texts/exportImport";
|
||||
|
||||
export const promoteApp = () => {
|
||||
cy.get(commonEeSelectors.promoteButton).click();
|
||||
cy.get(commonEeSelectors.promoteButton).eq(1).click();
|
||||
cy.waitForAppLoad();
|
||||
cy.wait(3000);
|
||||
};
|
||||
|
||||
export const releaseApp = () => {
|
||||
cy.get(commonSelectors.releaseButton).click();
|
||||
cy.get(commonSelectors.yesButton).click();
|
||||
cy.verifyToastMessage(commonSelectors.toastMessage, "Version v1 released");
|
||||
cy.wait(500);
|
||||
};
|
||||
|
||||
export const launchApp = () => {
|
||||
cy.url().then((url) => {
|
||||
const parts = url.split("/");
|
||||
const value = parts[parts.length - 1];
|
||||
cy.log(`Extracted value: ${value}`);
|
||||
cy.visit(`/applications/${value}`);
|
||||
cy.wait(3000);
|
||||
});
|
||||
};
|
||||
|
||||
export const appPromote = (fromEnv, toEnv) => {
|
||||
const commonActions = () => {
|
||||
cy.get(commonEeSelectors.promoteButton).click();
|
||||
cy.get(commonEeSelectors.promoteButton).eq(1).click();
|
||||
cy.waitForAppLoad();
|
||||
cy.wait(2000);
|
||||
};
|
||||
|
||||
const transitions = {
|
||||
development: {
|
||||
staging: commonActions,
|
||||
production: () => {
|
||||
commonActions();
|
||||
appPromote("staging", "production");
|
||||
},
|
||||
release: () => {
|
||||
commonActions();
|
||||
commonActions();
|
||||
cy.get(commonSelectors.releaseButton).click();
|
||||
cy.get(commonSelectors.yesButton).click();
|
||||
cy.wait(500);
|
||||
},
|
||||
},
|
||||
staging: {
|
||||
production: commonActions,
|
||||
release: () => {
|
||||
commonActions();
|
||||
cy.get(commonSelectors.releaseButton).click();
|
||||
cy.get(commonSelectors.yesButton).click();
|
||||
cy.wait(500);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const transition = transitions[fromEnv]?.[toEnv];
|
||||
|
||||
transition();
|
||||
};
|
||||
|
||||
export const createNewVersion = (value, newVersion = [], version) => {
|
||||
cy.get('[data-cy="list-current-env-name"]').click();
|
||||
cy.get(multiEnvSelector.envNameList).eq(0).click();
|
||||
cy.get(appVersionSelectors.currentVersionField(value)).click();
|
||||
cy.get(appVersionSelectors.createNewVersionButton).click();
|
||||
cy.get(appVersionSelectors.createVersionInputField).click();
|
||||
cy.contains(`[id*="react-select-"]`, version).click();
|
||||
cy.get(appVersionSelectors.versionNameInputField).click().type(newVersion[0]);
|
||||
cy.get(appVersionSelectors.createNewVersionButton).click();
|
||||
cy.waitForAppLoad();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
appVersionText.createdToastMessage
|
||||
);
|
||||
cy.get(appVersionSelectors.currentVersionField(newVersion[0])).should(
|
||||
"be.visible"
|
||||
);
|
||||
};
|
||||
|
||||
export const selectVersion = (value, newVersion = []) => {
|
||||
cy.get(appVersionSelectors.currentVersionField(value)).click();
|
||||
cy.get(".react-select__menu-list .app-version-name")
|
||||
.contains(newVersion[0])
|
||||
.click();
|
||||
cy.waitForAppLoad();
|
||||
};
|
||||
|
||||
export const selectEnv = (envName) => {
|
||||
const envIndex = {
|
||||
development: 0,
|
||||
staging: 1,
|
||||
production: 2,
|
||||
}[envName];
|
||||
|
||||
const isValidEnvName = (envName) => {
|
||||
return (
|
||||
envName === "development" ||
|
||||
envName === "staging" ||
|
||||
envName === "production"
|
||||
);
|
||||
};
|
||||
|
||||
if (isValidEnvName(envName)) {
|
||||
cy.get('[data-cy="list-current-env-name"]').click();
|
||||
cy.wait(500)
|
||||
const envSelector = `${multiEnvSelector.envNameList}:eq(${envIndex})`;
|
||||
cy.get(envSelector).click();
|
||||
cy.waitForAppLoad();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -9,6 +9,7 @@ import {
|
|||
} from "Selectors/version";
|
||||
import { deleteVersionText, releasedVersionText } from "Texts/version";
|
||||
import { verifyComponent } from "Support/utils/basicComponents";
|
||||
import { appPromote } from "./platform/multiEnv";
|
||||
|
||||
export const navigateToCreateNewVersionModal = (value) => {
|
||||
cy.get(appVersionSelectors.appVersionLabel).click();
|
||||
|
|
@ -121,6 +122,9 @@ export const verifyDuplicateVersion = (newVersion = [], version) => {
|
|||
};
|
||||
|
||||
export const releasedVersionAndVerify = (currentVersion) => {
|
||||
cy.ifEnv("Enterprise", () => {
|
||||
appPromote("development", "production");
|
||||
});
|
||||
cy.contains("Release").click();
|
||||
|
||||
cy.get(confirmVersionModalSelectors.yesButton).click();
|
||||
|
|
|
|||
|
|
@ -3,15 +3,14 @@ FROM node:22.15.1 AS builder
|
|||
# Fix for JS heap limit allocation issue
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
|
||||
RUN npm i -g npm@10.9.2
|
||||
RUN mkdir -p /app
|
||||
RUN npm cache clean --force
|
||||
RUN npm i -g npm@10.9.2 && npm cache clean --force
|
||||
|
||||
RUN mkdir -p /app
|
||||
WORKDIR /app
|
||||
|
||||
# Set GitHub token and branch as build arguments
|
||||
ARG CUSTOM_GITHUB_TOKEN
|
||||
ARG BRANCH_NAME=main
|
||||
ARG BRANCH_NAME
|
||||
|
||||
# Clone and checkout the frontend repository
|
||||
RUN git config --global url."https://x-access-token:${CUSTOM_GITHUB_TOKEN}@github.com/".insteadOf "https://github.com/"
|
||||
|
|
@ -21,7 +20,7 @@ RUN git config --global http.postBuffer 524288000
|
|||
RUN git clone https://github.com/ToolJet/ToolJet.git .
|
||||
|
||||
# The branch name needs to be changed the branch with modularisation in CE repo
|
||||
RUN git checkout main
|
||||
RUN git checkout ${BRANCH_NAME}
|
||||
|
||||
RUN git submodule update --init --recursive
|
||||
|
||||
|
|
@ -33,85 +32,61 @@ COPY ./package.json ./package.json
|
|||
|
||||
# Build plugins
|
||||
COPY ./plugins/package.json ./plugins/package-lock.json ./plugins/
|
||||
RUN npm --prefix plugins install
|
||||
RUN npm --prefix plugins ci --omit=dev
|
||||
COPY ./plugins/ ./plugins/
|
||||
RUN NODE_ENV=production npm --prefix plugins run build
|
||||
RUN npm --prefix plugins prune --production
|
||||
|
||||
ENV TOOLJET_EDITION=ee
|
||||
RUN npm --prefix plugins prune --omit=dev
|
||||
|
||||
# Build frontend
|
||||
COPY ./frontend/package.json ./frontend/package-lock.json ./frontend/
|
||||
RUN npm --prefix frontend install
|
||||
COPY ./frontend/ ./frontend/
|
||||
RUN npm --prefix frontend run build --production
|
||||
RUN npm --prefix frontend prune --production
|
||||
RUN npm --prefix frontend run build --production && npm --prefix frontend prune --production
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV TOOLJET_EDITION=ee
|
||||
|
||||
# Build server
|
||||
COPY ./server/package.json ./server/package-lock.json ./server/
|
||||
RUN npm --prefix server install
|
||||
RUN npm --prefix server ci --omit=dev
|
||||
COPY ./server/ ./server/
|
||||
RUN npm install -g @nestjs/cli
|
||||
RUN npm install -g @nestjs/cli
|
||||
RUN npm install -g copyfiles
|
||||
RUN npm --prefix server run build
|
||||
RUN npm prune --production --prefix server
|
||||
|
||||
FROM debian:12
|
||||
|
||||
RUN apt-get update -yq \
|
||||
&& apt-get install curl wget gnupg zip -yq \
|
||||
&& apt-get install -yq build-essential \
|
||||
&& apt -y install redis \
|
||||
&& apt-get clean -y
|
||||
|
||||
# Install required dependencies for downloading and extracting files
|
||||
# Install dependencies for PostgREST, curl, unzip, etc.
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl tar xz-utils postgresql postgresql-contrib postgresql-client && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
curl ca-certificates unzip tar \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install PostgREST from official Docker image
|
||||
COPY --from=postgrest/postgrest:v12.2.0 /bin/postgrest /bin
|
||||
ENV POSTGREST_VERSION=v12.2.0
|
||||
|
||||
RUN apt-get update && apt-get install -y supervisor
|
||||
RUN curl -Lo postgrest.tar.xz https://github.com/PostgREST/postgrest/releases/download/${POSTGREST_VERSION}/postgrest-v12.2.0-linux-static-x64.tar.xz && \
|
||||
tar -xf postgrest.tar.xz && \
|
||||
mv postgrest /postgrest && \
|
||||
rm postgrest.tar.xz && \
|
||||
chmod +x /postgrest
|
||||
|
||||
# Create supervisord configuration file
|
||||
RUN echo "[supervisord]\n" \
|
||||
"nodaemon=true\n" \
|
||||
"\n" \
|
||||
"[program:postgrest]\n" \
|
||||
"command=/bin/postgrest\n" \
|
||||
"autostart=true\n" \
|
||||
"autorestart=true\n" \
|
||||
"stdout_logfile=/dev/stdout\n" \
|
||||
"stderr_logfile=/dev/stderr\n" \
|
||||
"stdout_logfile_maxbytes=0\n" \
|
||||
"stderr_logfile_maxbytes=0\n" \
|
||||
"\n" \
|
||||
"[program:neo4j]\n" \
|
||||
"command=neo4j console\n" \
|
||||
"autostart=true\n" \
|
||||
"autorestart=unexpected\n" \
|
||||
"startsecs=30\n" \
|
||||
"startretries=999\n" \
|
||||
"priority=90\n" \
|
||||
"exitcodes=0,1,2\n" \
|
||||
"stopsignal=SIGTERM\n" \
|
||||
"stopasgroup=true\n" \
|
||||
"killasgroup=true\n" \
|
||||
"redirect_stderr=true\n" \
|
||||
"stdout_logfile=/var/log/neo4j/neo4j.log\n" \
|
||||
"stdout_logfile_backups=10\n" \
|
||||
"stderr_capture_maxbytes=20MB\n" \
|
||||
"\n" | sed 's/ //' > /etc/supervisor/conf.d/supervisord.conf
|
||||
FROM debian:12-slim
|
||||
|
||||
# Create a wrapper for PostgREST to prefix its logs
|
||||
RUN mv /bin/postgrest /bin/postgrest-original && \
|
||||
echo '#!/bin/bash\n\
|
||||
exec /bin/postgrest-original "$@" 2>&1 | sed "s/^/[PostgREST] /"\n\
|
||||
' > /bin/postgrest && \
|
||||
chmod +x /bin/postgrest
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
wget \
|
||||
gnupg \
|
||||
unzip \
|
||||
ca-certificates \
|
||||
xz-utils \
|
||||
tar \
|
||||
zip \
|
||||
postgresql-client \
|
||||
redis \
|
||||
libaio1 \
|
||||
git \
|
||||
freetds-dev \
|
||||
&& apt-get upgrade -y -o Dpkg::Options::="--force-confold" \
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
RUN curl -O https://nodejs.org/dist/v22.15.1/node-v22.15.1-linux-x64.tar.xz \
|
||||
|
|
@ -125,53 +100,18 @@ ENV PATH=/usr/local/lib/nodejs/bin:$PATH
|
|||
ENV NODE_ENV=production
|
||||
ENV TOOLJET_EDITION=ee
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
RUN apt-get update && \
|
||||
apt-get install -y postgresql-client freetds-dev libaio1 wget && \
|
||||
apt-get -o Dpkg::Options::="--force-confold" upgrade -q -y --force-yes && \
|
||||
apt-get -y autoremove && \
|
||||
apt-get -y autoclean
|
||||
|
||||
# Install Neo4j
|
||||
# Install Neo4j + APOC
|
||||
RUN wget -O - https://debian.neo4j.com/neotechnology.gpg.key | apt-key add - && \
|
||||
echo "deb https://debian.neo4j.com stable 5" > /etc/apt/sources.list.d/neo4j.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y neo4j=1:5.26.6 && \
|
||||
apt-mark hold neo4j && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Set the necessary Neo4j environment variables
|
||||
ENV NEO4J_HOME=/opt/neo4j
|
||||
ENV NEO4J_CONF=/etc/neo4j
|
||||
ENV NEO4J_DATA=/var/lib/neo4j/data
|
||||
ENV NEO4J_LOG=/var/log/neo4j
|
||||
ENV NEO4J_PLUGIN=/var/lib/neo4j/plugins
|
||||
ENV NEO4J_IMPORT=/var/lib/neo4j/import
|
||||
|
||||
# Create the necessary directories for Neo4j
|
||||
RUN mkdir -p /data/db /data/logs /data/plugins
|
||||
RUN mkdir -p /opt/neo4j/plugins
|
||||
|
||||
# Configure APOC plugin for Neo4j
|
||||
ENV NEO4J_dbms_active_plugins=apoc
|
||||
|
||||
# Download and install APOC plugin for Neo4j 5.x (BEFORE creating user)
|
||||
RUN mkdir -p /var/lib/neo4j/plugins && \
|
||||
apt-get update && apt-get install -y neo4j=1:5.26.6 && apt-mark hold neo4j && \
|
||||
mkdir -p /var/lib/neo4j/plugins && \
|
||||
wget -P /var/lib/neo4j/plugins https://github.com/neo4j/apoc/releases/download/5.26.6/apoc-5.26.6-core.jar && \
|
||||
# Try to download extended version
|
||||
(wget -P /var/lib/neo4j/plugins https://github.com/neo4j/apoc/releases/download/5.26.6/apoc-5.26.6-extended.jar || \
|
||||
wget -P /var/lib/neo4j/plugins https://neo4j-contrib.github.io/neo4j-apoc-procedures/5.26.6/apoc-5.26.6-extended.jar || \
|
||||
echo "Extended JAR not available, continuing with core only")
|
||||
|
||||
# Configure Neo4j with APOC
|
||||
RUN echo "dbms.security.procedures.unrestricted=apoc.*" >> /etc/neo4j/neo4j.conf && \
|
||||
echo "dbms.security.procedures.unrestricted=apoc.*" >> /etc/neo4j/neo4j.conf && \
|
||||
echo "dbms.security.procedures.allowlist=apoc.*,algo.*,gds.*" >> /etc/neo4j/neo4j.conf && \
|
||||
echo "dbms.directories.plugins=/var/lib/neo4j/plugins" >> /etc/neo4j/neo4j.conf
|
||||
|
||||
# Configure Neo4j to use authentication
|
||||
RUN if [ -f "/etc/neo4j/neo4j.conf" ]; then \
|
||||
sed -i '/dbms.security.auth_enabled/d' /etc/neo4j/neo4j.conf && \
|
||||
echo "dbms.security.auth_enabled=true" >> /etc/neo4j/neo4j.conf; \
|
||||
fi
|
||||
echo "dbms.directories.plugins=/var/lib/neo4j/plugins" >> /etc/neo4j/neo4j.conf && \
|
||||
echo "dbms.security.auth_enabled=true" >> /etc/neo4j/neo4j.conf && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Instantclient Basic Light Oracle and Dependencies
|
||||
WORKDIR /opt/oracle
|
||||
|
|
@ -186,40 +126,39 @@ RUN wget https://tooljet-plugins-production.s3.us-east-2.amazonaws.com/marketpla
|
|||
# Set the Instant Client library paths
|
||||
ENV LD_LIBRARY_PATH="/opt/oracle/instantclient_11_2:/opt/oracle/instantclient_21_10:${LD_LIBRARY_PATH}"
|
||||
|
||||
RUN rm -f *.zip *.key && apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /
|
||||
|
||||
RUN mkdir -p /app
|
||||
# copy npm scripts
|
||||
COPY --from=builder /app/package.json ./app/package.json
|
||||
# copy plugins dependencies
|
||||
COPY --from=builder /app/plugins/dist ./app/plugins/dist
|
||||
COPY --from=builder /app/plugins/client.js ./app/plugins/client.js
|
||||
COPY --from=builder /app/plugins/node_modules ./app/plugins/node_modules
|
||||
COPY --from=builder /app/plugins/packages/common ./app/plugins/packages/common
|
||||
COPY --from=builder /app/plugins/package.json ./app/plugins/package.json
|
||||
# copy frontend build
|
||||
COPY --from=builder /app/frontend/build ./app/frontend/build
|
||||
# copy server build
|
||||
COPY --from=builder /app/server/package.json ./app/server/package.json
|
||||
COPY --from=builder /app/server/.version ./app/server/.version
|
||||
COPY --from=builder /app/server/ee/keys ./app/server/ee/keys
|
||||
COPY --from=builder /app/server/node_modules ./app/server/node_modules
|
||||
COPY --from=builder /app/server/templates ./app/server/templates
|
||||
COPY --from=builder /app/server/scripts ./app/server/scripts
|
||||
COPY --from=builder /app/server/dist ./app/server/dist
|
||||
COPY --from=builder /app/server/src/assets ./app/server/src/assets
|
||||
|
||||
COPY ./docker/ee/ee-entrypoint.sh ./app/server/ee-entrypoint.sh
|
||||
RUN useradd --create-home --home-dir /home/appuser appuser
|
||||
|
||||
# Define non-sudo user
|
||||
RUN useradd --create-home --home-dir /home/appuser appuser \
|
||||
&& chown -R appuser:0 /app \
|
||||
&& chown -R appuser:0 /home \
|
||||
&& chmod u+x /app \
|
||||
&& chmod u+x /home \
|
||||
&& chmod -R g=u /app \
|
||||
&& chmod -R g=u /home
|
||||
# Use the PostgREST binary from the builder stage
|
||||
COPY --from=builder --chown=appuser:0 /postgrest /usr/local/bin/postgrest
|
||||
|
||||
RUN mv /usr/local/bin/postgrest /usr/local/bin/postgrest-original && \
|
||||
echo '#!/bin/bash\nexec /usr/local/bin/postgrest-original "$@" 2>&1 | sed "s/^/[PostgREST] /"' > /usr/local/bin/postgrest && \
|
||||
chmod +x /usr/local/bin/postgrest
|
||||
|
||||
|
||||
# Copy application with ownership set directly to avoid chown -R
|
||||
COPY --from=builder --chown=appuser:0 /app/package.json ./app/package.json
|
||||
COPY --from=builder --chown=appuser:0 /app/plugins/dist ./app/plugins/dist
|
||||
COPY --from=builder --chown=appuser:0 /app/plugins/client.js ./app/plugins/client.js
|
||||
COPY --from=builder --chown=appuser:0 /app/plugins/node_modules ./app/plugins/node_modules
|
||||
COPY --from=builder --chown=appuser:0 /app/plugins/packages/common ./app/plugins/packages/common
|
||||
COPY --from=builder --chown=appuser:0 /app/plugins/package.json ./app/plugins/package.json
|
||||
COPY --from=builder --chown=appuser:0 /app/frontend/build ./app/frontend/build
|
||||
COPY --from=builder --chown=appuser:0 /app/server/package.json ./app/server/package.json
|
||||
COPY --from=builder --chown=appuser:0 /app/server/.version ./app/server/.version
|
||||
COPY --from=builder --chown=appuser:0 /app/server/ee/keys ./app/server/ee/keys
|
||||
COPY --from=builder --chown=appuser:0 /app/server/node_modules ./app/server/node_modules
|
||||
COPY --from=builder --chown=appuser:0 /app/server/templates ./app/server/templates
|
||||
COPY --from=builder --chown=appuser:0 /app/server/scripts ./app/server/scripts
|
||||
COPY --from=builder --chown=appuser:0 /app/server/dist ./app/server/dist
|
||||
COPY --from=builder --chown=appuser:0 /app/server/src/assets ./app/server/src/assets
|
||||
COPY ./docker/ee/ee-entrypoint.sh ./app/server/ee-entrypoint.sh
|
||||
|
||||
RUN mkdir -p /var/lib/neo4j/data/databases /var/lib/neo4j/data/transactions /var/log/neo4j /opt/neo4j/run && \
|
||||
chown -R appuser:0 /var/lib/neo4j /var/log/neo4j /etc/neo4j /opt/neo4j/run && \
|
||||
|
|
@ -258,31 +197,11 @@ RUN mkdir -p /var/lib/redis /var/log/redis /etc/redis \
|
|||
&& chmod g+s /var/lib/redis /var/log/redis /etc/redis \
|
||||
&& chmod -R g=u /var/lib/redis /var/log/redis /etc/redis
|
||||
|
||||
# Set permissions for PostgREST binary
|
||||
RUN chown appuser:0 /bin/postgrest && chmod u+x /bin/postgrest && chmod g=u /bin/postgrest
|
||||
|
||||
RUN touch /tmp/postgrest.conf \
|
||||
&& chown appuser:0 /tmp/postgrest.conf \
|
||||
&& chmod 640 /tmp/postgrest.conf
|
||||
|
||||
# Create PostgREST data, log, and configuration directories
|
||||
RUN mkdir -p /var/lib/postgrest /var/log/postgrest /etc/postgrest \
|
||||
&& chown -R appuser:0 /var/lib/postgrest /var/log/postgrest /etc/postgrest \
|
||||
&& chmod g+s /var/lib/postgrest /var/log/postgrest /etc/postgrest \
|
||||
&& chmod -R g=u /var/lib/postgrest /var/log/postgrest /etc/postgrest
|
||||
|
||||
ENV HOME=/home/appuser
|
||||
|
||||
# Installing git for simple git commands
|
||||
RUN apt-get update && apt-get install -y git && apt-get clean
|
||||
|
||||
# Switch back to appuser
|
||||
USER appuser
|
||||
|
||||
WORKDIR /app
|
||||
# Dependencies for scripts outside nestjs
|
||||
RUN npm install dotenv@10.0.0 joi@17.4.1
|
||||
|
||||
RUN npm cache clean --force
|
||||
RUN npm install --prefix server --no-save dotenv@10.0.0 joi@17.4.1 && npm cache clean --force
|
||||
|
||||
ENTRYPOINT ["./server/ee-entrypoint.sh"]
|
||||
|
|
|
|||
|
|
@ -1,15 +1,47 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Install grpcurl if not already installed
|
||||
if ! command -v grpcurl &> /dev/null; then
|
||||
echo "grpcurl not found, installing..."
|
||||
apt update && apt install -y curl \
|
||||
&& curl -sSL https://github.com/fullstorydev/grpcurl/releases/download/v1.8.0/grpcurl_1.8.0_linux_x86_64.tar.gz | tar -xzv -C /usr/local/bin grpcurl
|
||||
fi
|
||||
|
||||
# Start Redis
|
||||
# service redis-server start
|
||||
# redis-server /etc/redis/redis.conf
|
||||
service redis-server start
|
||||
|
||||
# Start Postgres
|
||||
service postgresql start
|
||||
|
||||
# Start Temporal Server (SQLite configuration)
|
||||
echo "Starting Temporal Server..."
|
||||
/usr/bin/temporal-server -r / -c /etc/temporal/ -e temporal-server start &
|
||||
|
||||
# Export the PORT variable to be used by the application
|
||||
export PORT=${PORT:-80}
|
||||
|
||||
# Start Supervisor
|
||||
exec supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
exec supervisord -c /etc/supervisor/conf.d/supervisord.conf &
|
||||
|
||||
# Wait for Temporal Server to be ready
|
||||
echo "Waiting for Temporal Server to be ready..."
|
||||
sleep 10
|
||||
|
||||
# Check if namespace already exists
|
||||
echo "Checking if Temporal namespace exists..."
|
||||
if grpcurl -plaintext localhost:7233 temporal.api.workflowservice.v1.WorkflowService/ListNamespaces | grep -q '"name": "default"'; then
|
||||
echo "Namespace 'default' already exists."
|
||||
else
|
||||
# Register the namespace if it doesn't exist
|
||||
echo "Registering Temporal namespace..."
|
||||
grpcurl -plaintext -d '{
|
||||
"namespace": "default",
|
||||
"description": "Default namespace",
|
||||
"workflowExecutionRetentionPeriod": "259200s"
|
||||
}' localhost:7233 temporal.api.workflowservice.v1.WorkflowService/RegisterNamespace
|
||||
fi
|
||||
|
||||
# Run the worker process (last step)
|
||||
echo "Starting worker process..."
|
||||
npm run worker:prod
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
FROM tooljet/tooljet:ee-lts-latest
|
||||
|
||||
# Copy PostgREST executable
|
||||
# Copy postgrest executable
|
||||
COPY --from=postgrest/postgrest:v12.2.0 /bin/postgrest /bin
|
||||
|
||||
# Install PostgreSQL
|
||||
# Install Postgres
|
||||
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
|
||||
|
||||
# Install Redis
|
||||
|
||||
RUN apt update && apt -y install redis
|
||||
|
||||
# Create appuser home & ensure permission for supervisord and services
|
||||
|
|
@ -22,6 +22,28 @@ RUN mkdir -p /var/log/supervisor /var/run/postgresql /var/lib/postgresql /var/li
|
|||
chown -R appuser:appuser /etc/supervisor /var/log/supervisor /var/lib/redis && \
|
||||
chown -R postgres:postgres /var/run/postgresql /var/lib/postgresql
|
||||
|
||||
# Install Temporal Server Binaries
|
||||
RUN curl -OL https://github.com/temporalio/temporal/releases/download/v1.24.2/temporal_1.24.2_linux_amd64.tar.gz && \
|
||||
tar -xzf temporal_1.24.2_linux_amd64.tar.gz && \
|
||||
mv temporal-server /usr/bin/temporal-server && \
|
||||
chmod +x /usr/bin/temporal-server && \
|
||||
rm temporal_1.24.2_linux_amd64.tar.gz
|
||||
|
||||
# Install Temporal UI Server Binaries
|
||||
RUN curl -OL https://github.com/temporalio/ui-server/releases/download/v2.28.0/ui-server_2.28.0_linux_amd64.tar.gz && \
|
||||
tar -xzf ui-server_2.28.0_linux_amd64.tar.gz && \
|
||||
mv ui-server /usr/bin/temporal-ui-server && \
|
||||
chmod +x /usr/bin/temporal-ui-server && \
|
||||
rm ui-server_2.28.0_linux_amd64.tar.gz
|
||||
|
||||
# Copy Temporal configuration files
|
||||
COPY ./docker/ee/temporal-server.yaml /etc/temporal/temporal-server.yaml
|
||||
COPY ./docker/ee/temporal-ui-server.yaml /etc/temporal/temporal-ui-server.yaml
|
||||
|
||||
# Install grpcurl
|
||||
RUN apt update && apt install -y curl \
|
||||
&& curl -sSL https://github.com/fullstorydev/grpcurl/releases/download/v1.8.0/grpcurl_1.8.0_linux_x86_64.tar.gz | tar -xzv -C /usr/local/bin grpcurl
|
||||
|
||||
# Configure Supervisor to manage PostgREST, ToolJet, and Redis
|
||||
RUN echo "[supervisord] \n" \
|
||||
"nodaemon=true \n" \
|
||||
|
|
@ -52,8 +74,10 @@ RUN echo "[supervisord] \n" \
|
|||
"stdout_logfile=/dev/stdout \n" \
|
||||
"stdout_logfile_maxbytes=0 \n" | sed 's/ //' > /etc/supervisor/conf.d/supervisord.conf
|
||||
|
||||
|
||||
# ENV defaults
|
||||
ENV TOOLJET_HOST=http://localhost \
|
||||
TOOLJET_SERVER_URL=http://localhost \
|
||||
PORT=80 \
|
||||
NODE_ENV=production \
|
||||
LOCKBOX_MASTER_KEY=replace_with_lockbox_master_key \
|
||||
|
|
@ -78,7 +102,14 @@ ENV TOOLJET_HOST=http://localhost \
|
|||
REDIS_PORT=6379 \
|
||||
REDIS_USER=default \
|
||||
REDIS_PASS= \
|
||||
TERM=xterm
|
||||
ENABLE_MARKETPLACE_FEATURE=true \
|
||||
TERM=xterm \
|
||||
ENABLE_WORKFLOW_SCHEDULING=true \
|
||||
TEMPORAL_SERVER_ADDRESS=localhost:7233 \
|
||||
TEMPORAL_TASK_QUEUE_NAME_FOR_WORKFLOWS=tooljet-workflows \
|
||||
TOOLJET_WORKFLOWS_TEMPORAL_NAMESPACE=default \
|
||||
TEMPORAL_ADDRESS=localhost:7233 \
|
||||
TEMPORAL_CORS_ORIGINS=http://localhost:8080
|
||||
|
||||
# Set the entrypoint
|
||||
COPY ./docker/ee/ee-try-entrypoint-lts.sh /ee-try-entrypoint-lts.sh
|
||||
|
|
|
|||
Loading…
Reference in a new issue