mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 17:08:34 +00:00
Merge branch 'appbuilder/sprint-9' into feat/dropdown-multiselect-navigation
This commit is contained in:
commit
3a40a71ed7
79 changed files with 2567 additions and 204 deletions
2
.github/workflows/cypress-platform.yml
vendored
2
.github/workflows/cypress-platform.yml
vendored
|
|
@ -79,7 +79,7 @@ jobs:
|
|||
|
||||
- name: Set up environment variables
|
||||
run: |
|
||||
echo "TOOLJET_EDITION=${{ matrix.edition == 'ee' && 'EE' || 'CE' }}" >> .env
|
||||
echo "TOOLJET_EDITION=${{ matrix.edition == 'ee' && 'ee' || 'ce' }}" >> .env
|
||||
echo "TOOLJET_HOST=http://localhost:8082" >> .env
|
||||
echo "LOCKBOX_MASTER_KEY=cd97331a419c09387bef49787f7da8d2a81d30733f0de6bed23ad8356d2068b2" >> .env
|
||||
echo "SECRET_KEY_BASE=7073b9a35a15dd20914ae17e36a693093f25b74b96517a5fec461fc901c51e011cd142c731bee48c5081ec8bac321c1f259ef097ef2a16f25df17a3798c03426" >> .env
|
||||
|
|
|
|||
|
|
@ -116,8 +116,10 @@ Cypress.Commands.add(
|
|||
});
|
||||
|
||||
const splitIntoFlatArray = (value) => {
|
||||
const regex = /(\{|\}|\(|\)|\[|\]|,|:|;|=>|'[^']*'|[a-zA-Z0-9._]+|\s+)/g;
|
||||
const regex =
|
||||
/(\{|\}|\(|\)|\[|\]|,|:|;|=>|'[^']*'|"[^"]*"|[a-zA-Z0-9._-]+|\s+)/g;
|
||||
let prefix = "";
|
||||
|
||||
return (
|
||||
value.match(regex)?.reduce((acc, part) => {
|
||||
if (part === "{{" || part === "((") {
|
||||
|
|
@ -132,6 +134,10 @@ Cypress.Commands.add(
|
|||
acc.push(prefix + " ");
|
||||
} else if (part === ":") {
|
||||
acc.push(prefix + ":");
|
||||
} else if (part === '"') {
|
||||
acc.push(prefix + '"');
|
||||
} else if (part.includes("-")) {
|
||||
acc.push(prefix + part); // Ensure hyphen is included
|
||||
} else {
|
||||
acc.push(prefix + part);
|
||||
prefix = "";
|
||||
|
|
@ -142,13 +148,11 @@ Cypress.Commands.add(
|
|||
};
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
cy.wrap(subject)
|
||||
.last()
|
||||
.realType(value, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 0,
|
||||
force: true,
|
||||
});
|
||||
cy.wrap(subject).last().realType(value, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 0,
|
||||
force: true,
|
||||
});
|
||||
} else {
|
||||
splitIntoFlatArray(value).forEach((i) => {
|
||||
cy.wrap(subject)
|
||||
|
|
@ -228,9 +232,9 @@ Cypress.Commands.add(
|
|||
.invoke("text")
|
||||
.then((text) => {
|
||||
cy.wrap(subject).realType(createBackspaceText(text)),
|
||||
{
|
||||
delay: 0,
|
||||
};
|
||||
{
|
||||
delay: 0,
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
|||
40
cypress-tests/cypress/constants/selectors/Plugins.js
Normal file
40
cypress-tests/cypress/constants/selectors/Plugins.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
export const pluginSelectors = {
|
||||
regionField: '[data-cy="region-section"] .react-select__control',
|
||||
regionFieldValue: '[data-cy="region-section"] .react-select__single-value',
|
||||
amazonsesAccesKey: '[data-cy="access-key-text-field"]',
|
||||
operationDropdown: '[data-cy="operation-select-dropdown"]',
|
||||
sendEmailInputField: '[data-cy="send-mail-to-input-field"]',
|
||||
ccEmailInputField: '[data-cy="cc-to-input-field"]',
|
||||
bccEmailInputField: '[data-cy="bcc-to-input-field"]',
|
||||
sendEmailFromInputField: '[data-cy="send-mail-from-input-field"]',
|
||||
emailSubjetInputField: '[data-cy="subject-input-field"]',
|
||||
emailbodyInputField: '[data-cy="body-input-field"]',
|
||||
amazonAthenaDbName: '[data-cy="database-text-field"]',
|
||||
};
|
||||
|
||||
export const baserowSelectors = {
|
||||
hostField: '[data-cy="host-select-dropdown"]',
|
||||
baserowApiKey: '[data-cy="api-token-text-field"]',
|
||||
table: '[data-cy="table-id-input-field"]',
|
||||
rowIdinputfield: '[data-cy="row-id-input-field"]',
|
||||
};
|
||||
|
||||
export const appWriteSelectors = {
|
||||
projectID: '[data-cy="project-id-text-field"]',
|
||||
collectionId: '[data-cy="collectionid-input-field"]',
|
||||
documentId: '[data-cy="documentid-input-field"]',
|
||||
bodyInput: '[data-cy="body-input-field"]',
|
||||
};
|
||||
|
||||
export const twilioSelectors = {
|
||||
toNumberInputField: '[data-cy="to-number-input-field"]',
|
||||
bodyInput: '[data-cy="body-input-field"]',
|
||||
};
|
||||
|
||||
export const minioSelectors = {
|
||||
sslToggle: 'data-cy="ssl-enabled-toggle-input"',
|
||||
bucketNameInputField: '[data-cy="bucket-input-field"]',
|
||||
objectNameInputField: '[data-cy="objectname-input-field"]',
|
||||
contentTypeInputField: '[data-cy="contenttype-input-field"]',
|
||||
dataInput: '[data-cy="data-input-field"]',
|
||||
};
|
||||
|
|
@ -5,5 +5,5 @@ export const s3Selector = {
|
|||
regionLabel: '[data-cy="label-region"]',
|
||||
customEndpointLabel: '[data-cy="label-custom-endpoint"]',
|
||||
customEndpointInput: '[data-cy="undefined-text-field"]',
|
||||
dataSourceNameInput: '[data-cy="data-source-name-input-filed"]',
|
||||
dataSourceNameInput: '[data-cy="data-source-name-input-field"]',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export const dataSourceSelector = {
|
|||
dataSourceSearchInputField: '[data-cy="home-page-search-bar"]',
|
||||
|
||||
postgresDataSource: "[data-cy='data-source-postgresql']",
|
||||
dataSourceNameInputField: '[data-cy="data-source-name-input-filed"]',
|
||||
dataSourceNameInputField: '[data-cy="data-source-name-input-field"]',
|
||||
labelHost: '[data-cy="label-host"]',
|
||||
labelPort: '[data-cy="label-port"]',
|
||||
labelSsl: '[data-cy="label-ssl"]',
|
||||
|
|
@ -28,7 +28,7 @@ export const dataSourceSelector = {
|
|||
buttonTestConnection: '[data-cy="test-connection-button"]',
|
||||
connectionFailedText: '[data-cy="test-connection-failed-text"]',
|
||||
buttonSave: '[data-cy="db-connection-save-button"] > .tj-base-btn',
|
||||
dangerAlertNotSupportSSL: '.go3958317564',
|
||||
dangerAlertNotSupportSSL: ".go3958317564",
|
||||
|
||||
passwordTextField: '[data-cy="password-text-field"]',
|
||||
textConnectionVerified: '[data-cy="test-connection-verified-text"]',
|
||||
|
|
@ -97,11 +97,11 @@ export const dataSourceSelector = {
|
|||
eventQuerySelectionField: '[data-cy="query-selection-field"]',
|
||||
addedDsSearchIcon: '[data-cy="added-ds-search-icon"]',
|
||||
AddedDsSearchBar: '[data-cy="added-ds-search-bar"]',
|
||||
dsNameInputField: '[data-cy="data-source-name-input-filed"]',
|
||||
dsNameInputField: '[data-cy="data-source-name-input-field"]',
|
||||
unSavedModalTitle: '[data-cy="unsaved-changes-title"]',
|
||||
eventQuerySelectionField: '[data-cy="query-selection-field"]',
|
||||
connectionAlertText: '[data-cy="connection-alert-text"]',
|
||||
deleteDSButton: (datasourceName) => {
|
||||
return `[data-cy="${cyParamName(datasourceName)}-delete-button"]`
|
||||
return `[data-cy="${cyParamName(datasourceName)}-delete-button"]`;
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export const postgreSqlSelector = {
|
|||
dataSourceSearchInputField: '[data-cy="home-page-search-bar"]',
|
||||
|
||||
postgresDataSource: "[data-cy='data-source-postgresql']",
|
||||
dataSourceNameInputField: '[data-cy="data-source-name-input-filed"]',
|
||||
dataSourceNameInputField: '[data-cy="data-source-name-input-field"]',
|
||||
labelHost: '[data-cy="label-host"]',
|
||||
labelPort: '[data-cy="label-port"]',
|
||||
labelSsl: '[data-cy="label-ssl"]',
|
||||
|
|
@ -88,3 +88,11 @@ export const postgreSqlSelector = {
|
|||
|
||||
eventQuerySelectionField: '[data-cy="query-selection-field"]',
|
||||
};
|
||||
|
||||
export const airTableSelector = {
|
||||
operationSelectDropdown: '[data-cy="operation-select-dropdown"]',
|
||||
baseIdInputField: '[data-cy="base-id-input-field"]',
|
||||
tableNameInputField: '[data-cy="table-name-input-field"]',
|
||||
recordIdInputField: '[data-cy="record-id-input-field"]',
|
||||
bodyInputField: '[data-cy="body-input-field"]',
|
||||
};
|
||||
|
|
|
|||
6
cypress-tests/cypress/constants/texts/airTable.js
Normal file
6
cypress-tests/cypress/constants/texts/airTable.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export const airtableText = {
|
||||
airtable: "Airtable",
|
||||
cypressairtable: "cypress-Airtable",
|
||||
ApiKey: "Personal access token",
|
||||
apikeyPlaceholder: "**************",
|
||||
};
|
||||
8
cypress-tests/cypress/constants/texts/amazonAthena.js
Normal file
8
cypress-tests/cypress/constants/texts/amazonAthena.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export const amazonAthenaText = {
|
||||
AmazonAthena: "Amazon Athena",
|
||||
cypressAmazonAthena: "cypress-Amazon Athena",
|
||||
labelAccesskey: "Access key",
|
||||
labelSecretKey: "Secret key",
|
||||
placeholderEnteraAccessKey: "Enter access key",
|
||||
placeholderSecretKey:"**************",
|
||||
};
|
||||
8
cypress-tests/cypress/constants/texts/amazonSes.js
Normal file
8
cypress-tests/cypress/constants/texts/amazonSes.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export const amazonSesText = {
|
||||
AmazonSES: "Amazon SES",
|
||||
cypressAmazonSES: "cypress-Amazon SES",
|
||||
labelAccesskey: "Access key",
|
||||
labelSecretKey: "Secret key",
|
||||
placeholderAccessKey: "Enter access key",
|
||||
placeholderSecretKey:"**************",
|
||||
};
|
||||
12
cypress-tests/cypress/constants/texts/appwrite.js
Normal file
12
cypress-tests/cypress/constants/texts/appwrite.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
export const appwriteText = {
|
||||
appwrite: "Appwrite",
|
||||
cypressAppwrite: "cypress-Appwrite",
|
||||
host: "Host",
|
||||
ProjectID: "Project ID",
|
||||
DatabaseID: "Database ID",
|
||||
SecretKey: "Secret Key",
|
||||
SecretKeyPlaceholder: "**************",
|
||||
hostPlaceholder: "Appwrite database host/endpoint",
|
||||
projectIdPlaceholder: "Appwrite project id",
|
||||
databaseIdPlaceholder: "Appwrite Database id",
|
||||
};
|
||||
6
cypress-tests/cypress/constants/texts/baseRow.js
Normal file
6
cypress-tests/cypress/constants/texts/baseRow.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export const baseRowText = {
|
||||
baserow: "baserow",
|
||||
cypressBaseRow: "cypress-baserow",
|
||||
lableApiToken: "API token",
|
||||
placeholderApiToken:"**************",
|
||||
};
|
||||
14
cypress-tests/cypress/constants/texts/minio.js
Normal file
14
cypress-tests/cypress/constants/texts/minio.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
export const minioText = {
|
||||
minio: "Minio",
|
||||
cypressMinio: "cypressMinio",
|
||||
hostLabel: "Host",
|
||||
hostInputPlaceholder: "Enter host",
|
||||
portLabel: "Port",
|
||||
portPlaceholder: "Enter port",
|
||||
labelAccesskey: "Access key",
|
||||
labelSecretKey: "Secret key",
|
||||
placeholderAccessKey: "Enter access key",
|
||||
placeholderSecretKey: "**************",
|
||||
bucketName: `my-second-bucket`,
|
||||
objectName: `mybucket`,
|
||||
};
|
||||
11
cypress-tests/cypress/constants/texts/twilio.js
Normal file
11
cypress-tests/cypress/constants/texts/twilio.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
export const twilioText = {
|
||||
twilio: "Twilio",
|
||||
cypresstwilio: "cypress-Twilio",
|
||||
authTokenLabel: "Auth Token",
|
||||
authTokenPlaceholder: "**************",
|
||||
accountSidLabel: "Account SID",
|
||||
accountSidPlaceholder: "Account SID for Twilio",
|
||||
messagingSIDLabel: "Messaging Service SID",
|
||||
messagingSIDPalceholder: "Messaging Service SID for Twilio",
|
||||
messageText: "Sending test message to check twilio",
|
||||
};
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { postgreSqlSelector } from "Selectors/postgreSql";
|
||||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { commonSelectors } from "Selectors/common";
|
||||
|
||||
import { selectAndAddDataSource } from "Support/utils/postgreSql";
|
||||
|
||||
import { closeDSModal } from "Support/utils/dataSource";
|
||||
|
||||
const data = {};
|
||||
data.dsNamefake = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.dsNamefake1 = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
const cyParamName = (name) => name.toLowerCase().replace(/[^a-z0-9]/g, "-");
|
||||
|
||||
const dataSources = [
|
||||
"BigQuery",
|
||||
"ClickHouse",
|
||||
"CosmosDB",
|
||||
"CouchDB",
|
||||
"Databricks",
|
||||
"DynamoDB",
|
||||
"Elasticsearch",
|
||||
"Firestore",
|
||||
"InfluxDB",
|
||||
"MariaDB",
|
||||
"MongoDB",
|
||||
"SQL Server",
|
||||
"MySQL",
|
||||
"Oracle DB",
|
||||
"PostgreSQL",
|
||||
"Redis",
|
||||
"RethinkDB",
|
||||
"SAP HANA",
|
||||
"Snowflake",
|
||||
"TypeSense",
|
||||
"Airtable",
|
||||
"Amazon SES",
|
||||
"Appwrite",
|
||||
"Amazon Athena",
|
||||
"Baserow",
|
||||
// "Google Sheets", need to remove
|
||||
"GraphQL",
|
||||
// "gRPC", need to remove
|
||||
"Mailgun",
|
||||
"n8n",
|
||||
"Notion",
|
||||
"OpenAPI",
|
||||
"REST API",
|
||||
"SendGrid",
|
||||
// "Slack", need to remove
|
||||
"SMTP",
|
||||
"Stripe",
|
||||
"Twilio",
|
||||
"Woocommerce",
|
||||
//"Zendesk", need to remove
|
||||
"Azure Blob Storage",
|
||||
"GCS",
|
||||
"Minio",
|
||||
"AWS S3",
|
||||
];
|
||||
|
||||
describe("Add all Data sources to app", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
});
|
||||
|
||||
it("Should verify global data source page", () => {
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allDataSources()
|
||||
);
|
||||
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.commonlyUsed
|
||||
);
|
||||
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allCloudStorage
|
||||
);
|
||||
});
|
||||
|
||||
it("Should add all data sources in data source page", () => {
|
||||
dataSources.forEach((dsName) => {
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
selectAndAddDataSource("databases", dsName, dsName); // Using the correct fake name
|
||||
|
||||
// Test connection
|
||||
// cy.get(postgreSqlSelector.buttonTestConnection).click();
|
||||
// cy.get(postgreSqlSelector.textConnectionVerified, {
|
||||
// timeout: 10000,
|
||||
// }).should("have.text", postgreSqlText.labelConnectionVerified);
|
||||
|
||||
// // Save data source
|
||||
// cy.get(postgreSqlSelector.buttonSave).click();
|
||||
// cy.verifyToastMessage(
|
||||
// commonSelectors.toastMessage,
|
||||
// `Data Source ${dsName} saved.`
|
||||
// );
|
||||
});
|
||||
});
|
||||
|
||||
it("Should add all data sources in the app", () => {
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
cy.get(commonSelectors.appCreateButton).click();
|
||||
cy.get(commonSelectors.appNameInput).click().type(data.dsNamefake);
|
||||
cy.get(commonSelectors.createAppButton).click();
|
||||
cy.skipWalkthrough();
|
||||
|
||||
cy.wrap(dataSources).each((dsName) => {
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
cy.get(".css-4e90k9").type(
|
||||
`cypress-${cyParamName(dsName)}-${cyParamName(dsName)}`
|
||||
);
|
||||
cy.wait(500);
|
||||
|
||||
cy.contains(
|
||||
`[id*="react-select-"]`,
|
||||
`cypress-${cyParamName(dsName)}-${cyParamName(dsName)}`
|
||||
)
|
||||
.should("be.visible")
|
||||
.click();
|
||||
|
||||
cy.wait(500);
|
||||
});
|
||||
});
|
||||
|
||||
it("Should install all makretplace plugins and add them into the app", () => {
|
||||
const dataSourcesMarketplace = [
|
||||
"Plivo",
|
||||
"GitHub",
|
||||
"OpenAI",
|
||||
"AWS Textract",
|
||||
"HarperDB",
|
||||
"AWS Redshift",
|
||||
"PocketBase",
|
||||
"AWS Lambda",
|
||||
"Supabase",
|
||||
"Engagespot",
|
||||
// "Salesforce", need to remove
|
||||
"Presto",
|
||||
"Jira",
|
||||
// "Sharepoint", need to remove
|
||||
"Portkey",
|
||||
"Pinecone",
|
||||
"Hugging Face",
|
||||
"Cohere",
|
||||
"Gemini",
|
||||
"Mistral",
|
||||
"Anthropic",
|
||||
"Qdrant",
|
||||
"Weaviate DB",
|
||||
];
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
|
||||
cy.window().then((win) => {
|
||||
cy.stub(win, "open").callsFake((url) => {
|
||||
win.location.href = url;
|
||||
});
|
||||
});
|
||||
|
||||
cy.get('[data-cy="data-source-add-plugin"]').click();
|
||||
|
||||
cy.get(".marketplace-install").each(($el) => {
|
||||
cy.wrap($el).click();
|
||||
cy.wait(500);
|
||||
cy.get(commonSelectors.toastMessage).should("include.text", "installed");
|
||||
});
|
||||
cy.wait(1000);
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
cy.get(commonSelectors.pageSectionHeader).should(
|
||||
"have.text",
|
||||
"Data sources"
|
||||
);
|
||||
|
||||
cy.wrap(dataSourcesMarketplace).each((dsName) => {
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
selectAndAddDataSource("databases", dsName, dsName);
|
||||
cy.wait(500);
|
||||
});
|
||||
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
cy.get(commonSelectors.appCreateButton).click();
|
||||
cy.get(commonSelectors.appNameInput).click().type(data.dsNamefake1);
|
||||
cy.get(commonSelectors.createAppButton).click();
|
||||
cy.skipWalkthrough();
|
||||
|
||||
cy.wrap(dataSourcesMarketplace).each((dsName) => {
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
cy.get(".css-4e90k9").type(
|
||||
`cypress-${cyParamName(dsName)}-${cyParamName(dsName)}`
|
||||
);
|
||||
cy.wait(500);
|
||||
|
||||
cy.contains(
|
||||
`[id*="react-select-"]`,
|
||||
`cypress-${cyParamName(dsName)}-${cyParamName(dsName)}`
|
||||
)
|
||||
.should("be.visible")
|
||||
.click();
|
||||
|
||||
cy.wait(500);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { postgreSqlSelector, airTableSelector } from "Selectors/postgreSql";
|
||||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { airtableText } from "Texts/airTable";
|
||||
import { commonSelectors } from "Selectors/common";
|
||||
import { commonText } from "Texts/common";
|
||||
|
||||
import {
|
||||
fillDataSourceTextField,
|
||||
selectAndAddDataSource,
|
||||
} from "Support/utils/postgreSql";
|
||||
import { redisText } from "Texts/redis";
|
||||
|
||||
import {
|
||||
verifyCouldnotConnectWithAlert,
|
||||
deleteDatasource,
|
||||
closeDSModal,
|
||||
addQuery,
|
||||
addDsAndAddQuery,
|
||||
selectDatasource,
|
||||
} from "Support/utils/dataSource";
|
||||
|
||||
import { openQueryEditor } from "Support/utils/dataSource";
|
||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||
|
||||
const data = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
data.dsName1 = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source Airtable", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
});
|
||||
|
||||
it("Should verify elements on connection AirTable form", () => {
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allDataSources()
|
||||
);
|
||||
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.commonlyUsed
|
||||
);
|
||||
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allDatabase()
|
||||
);
|
||||
cy.get(postgreSqlSelector.apiLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allApis
|
||||
);
|
||||
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allCloudStorage
|
||||
);
|
||||
|
||||
selectAndAddDataSource("databases", airtableText.airtable, data.dsName);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave).verifyVisibleElement(
|
||||
"have.text",
|
||||
postgreSqlText.buttonTextSave
|
||||
);
|
||||
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
deleteDatasource(`cypress-${data.dsName}-airtable`);
|
||||
});
|
||||
|
||||
it("Should verify the functionality of AirTable connection form.", () => {
|
||||
selectAndAddDataSource("databases", airtableText.airtable, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
airtableText.ApiKey,
|
||||
airtableText.apikeyPlaceholder,
|
||||
Cypress.env("airTable_apikey")
|
||||
);
|
||||
cy.get(postgreSqlSelector.buttonSave).click();
|
||||
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
cy.get(
|
||||
`[data-cy="cypress-${data.dsName}-airtable-button"]`
|
||||
).verifyVisibleElement("have.text", `cypress-${data.dsName}-airtable`);
|
||||
deleteDatasource(`cypress-${data.dsName}-airtable`);
|
||||
});
|
||||
|
||||
it("Should able to run the query with valid conection", () => {
|
||||
const airTable_apiKey = Cypress.env("airTable_apikey");
|
||||
const airTable_baseId = Cypress.env("airtabelbaseId");
|
||||
const airTable_tableName = Cypress.env("airtable_tableName");
|
||||
const airTable_recordID = Cypress.env("airtable_recordId");
|
||||
|
||||
selectAndAddDataSource("databases", airtableText.airtable, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
airtableText.ApiKey,
|
||||
airtableText.apikeyPlaceholder,
|
||||
airTable_apiKey
|
||||
);
|
||||
|
||||
cy.wait(1000);
|
||||
cy.get(postgreSqlSelector.buttonSave).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
cy.get(
|
||||
`[data-cy="cypress-${data.dsName}-airtable-button"]`
|
||||
).verifyVisibleElement("have.text", `cypress-${data.dsName}-airtable`);
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
cy.get(commonSelectors.appCreateButton).click();
|
||||
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
|
||||
cy.get(commonSelectors.createAppButton).click();
|
||||
cy.skipWalkthrough();
|
||||
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
cy.get(".css-4e90k9").type(`${data.dsName}`);
|
||||
cy.contains(`[id*="react-select-"]`, data.dsName).click();
|
||||
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
|
||||
|
||||
// Verfiy List Recored operation
|
||||
|
||||
cy.get(airTableSelector.operationSelectDropdown)
|
||||
.click()
|
||||
.type("List records{enter}");
|
||||
|
||||
cy.get(airTableSelector.baseIdInputField).clearAndTypeOnCodeMirror(
|
||||
airTable_baseId
|
||||
);
|
||||
|
||||
cy.get(airTableSelector.tableNameInputField).clearAndTypeOnCodeMirror(
|
||||
airTable_tableName
|
||||
);
|
||||
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
|
||||
// Verfiy Retrieve record operation
|
||||
|
||||
cy.get(airTableSelector.operationSelectDropdown)
|
||||
.click()
|
||||
.type("Retrieve record{enter}");
|
||||
|
||||
cy.get(airTableSelector.baseIdInputField).clearAndTypeOnCodeMirror(
|
||||
airTable_baseId
|
||||
);
|
||||
cy.get(airTableSelector.tableNameInputField).clearAndTypeOnCodeMirror(
|
||||
airTable_tableName
|
||||
);
|
||||
|
||||
cy.get(airTableSelector.recordIdInputField).clearAndTypeOnCodeMirror(
|
||||
airTable_recordID
|
||||
);
|
||||
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
|
||||
// Verfiy Create record operation
|
||||
|
||||
cy.get(airTableSelector.operationSelectDropdown)
|
||||
.click()
|
||||
.type("Create record{enter}");
|
||||
|
||||
cy.get(airTableSelector.baseIdInputField).clearAndTypeOnCodeMirror(
|
||||
airTable_baseId
|
||||
);
|
||||
|
||||
cy.get(airTableSelector.tableNameInputField).clearAndTypeOnCodeMirror(
|
||||
airTable_tableName
|
||||
);
|
||||
|
||||
cy.get(airTableSelector.bodyInputField)
|
||||
.realClick()
|
||||
.realType('[{"', { force: true, delay: 0 })
|
||||
.realType("fields", { force: true, delay: 0 })
|
||||
.realType('": {}', { force: true, delay: 0 });
|
||||
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
|
||||
// Verfiy Update record operation
|
||||
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
cy.get(".css-4e90k9").type(`${data.dsName}`);
|
||||
cy.contains(`[id*="react-select-"]`, data.dsName).click();
|
||||
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName1);
|
||||
|
||||
cy.get(airTableSelector.operationSelectDropdown)
|
||||
.click()
|
||||
.type("Update record{enter}");
|
||||
|
||||
cy.get(airTableSelector.baseIdInputField).clearAndTypeOnCodeMirror(
|
||||
airTable_baseId
|
||||
);
|
||||
cy.get(airTableSelector.tableNameInputField).clearAndTypeOnCodeMirror(
|
||||
airTable_tableName
|
||||
);
|
||||
|
||||
cy.get(airTableSelector.recordIdInputField).clearAndTypeOnCodeMirror(
|
||||
airTable_recordID
|
||||
);
|
||||
|
||||
cy.get(airTableSelector.bodyInputField)
|
||||
.realClick()
|
||||
.realType("{", { force: true, delay: 0 })
|
||||
.realType("{enter}", { force: true, delay: 0 })
|
||||
.realType('"Phone Number": "555_98"', { force: true, delay: 0 });
|
||||
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName1}) completed.`
|
||||
);
|
||||
|
||||
// Verify Delete record operation
|
||||
|
||||
cy.get(airTableSelector.operationSelectDropdown)
|
||||
.click()
|
||||
.type("Delete record{enter}");
|
||||
|
||||
const recordId = Cypress._.uniqueId("recDummy_");
|
||||
|
||||
cy.request({
|
||||
method: "POST",
|
||||
url: `https://api.airtable.com/v0/${airTable_baseId}/${airTable_tableName}`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${Cypress.env("airTable_apikey")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: {
|
||||
records: [
|
||||
{
|
||||
fields: {
|
||||
"Employee ID": "E005",
|
||||
"First Name": "test",
|
||||
"Last Name": "abc",
|
||||
Email: "doe@example.com",
|
||||
"Phone Number": "555-12",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}).then((createResponse) => {
|
||||
const newRecordId = createResponse.body.records[0].id;
|
||||
|
||||
cy.get(airTableSelector.operationSelectDropdown)
|
||||
.click()
|
||||
.type("Delete record{enter}");
|
||||
|
||||
cy.get(airTableSelector.baseIdInputField).clearAndTypeOnCodeMirror(
|
||||
airTable_baseId
|
||||
);
|
||||
cy.get(airTableSelector.tableNameInputField).clearAndTypeOnCodeMirror(
|
||||
airTable_tableName
|
||||
);
|
||||
|
||||
cy.get(airTableSelector.recordIdInputField).clearAndTypeOnCodeMirror(
|
||||
newRecordId
|
||||
);
|
||||
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName1}) completed.`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { postgreSqlSelector } from "Selectors/postgreSql";
|
||||
import { pluginSelectors } from "Selectors/plugins";
|
||||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { amazonSesText } from "Texts/amazonSes";
|
||||
import { amazonAthenaText } from "Texts/amazonAthena";
|
||||
import { commonSelectors } from "Selectors/common";
|
||||
import { commonText } from "Texts/common";
|
||||
|
||||
import {
|
||||
fillDataSourceTextField,
|
||||
selectAndAddDataSource,
|
||||
} from "Support/utils/postgreSql";
|
||||
|
||||
import {
|
||||
verifyCouldnotConnectWithAlert,
|
||||
deleteDatasource,
|
||||
closeDSModal,
|
||||
addQuery,
|
||||
addDsAndAddQuery,
|
||||
} from "Support/utils/dataSource";
|
||||
|
||||
import { openQueryEditor } from "Support/utils/dataSource";
|
||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||
|
||||
const data = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source amazon athena", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on amazon athena connection form", () => {
|
||||
const Accesskey = Cypress.env("amazonathena_accessKey");
|
||||
const Secretkey = Cypress.env("amazonathena_secretKey");
|
||||
const DbName = Cypress.env("amazonathena_DbName");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allDataSources()
|
||||
);
|
||||
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.commonlyUsed
|
||||
);
|
||||
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allDatabase()
|
||||
);
|
||||
cy.get(postgreSqlSelector.apiLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allApis
|
||||
);
|
||||
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allCloudStorage
|
||||
);
|
||||
|
||||
selectAndAddDataSource(
|
||||
"databases",
|
||||
amazonAthenaText.AmazonAthena,
|
||||
data.dsName
|
||||
);
|
||||
|
||||
cy.get(pluginSelectors.amazonAthenaDbName).click().type(DbName);
|
||||
|
||||
cy.get(pluginSelectors.amazonsesAccesKey).click().type(" ");
|
||||
|
||||
fillDataSourceTextField(
|
||||
amazonSesText.labelSecretKey,
|
||||
amazonAthenaText.placeholderSecretKey,
|
||||
Secretkey
|
||||
);
|
||||
|
||||
cy.get(".react-select__dropdown-indicator").eq(1).click();
|
||||
cy.get(".react-select__option").contains("US West (N. California)").click();
|
||||
|
||||
cy.get(postgreSqlSelector.buttonTestConnection)
|
||||
.verifyVisibleElement(
|
||||
"have.text",
|
||||
postgreSqlText.buttonTextTestConnection
|
||||
)
|
||||
.click();
|
||||
cy.get(postgreSqlSelector.connectionFailedText).verifyVisibleElement(
|
||||
"have.text",
|
||||
postgreSqlText.couldNotConnect
|
||||
);
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-Amazon-Athena`);
|
||||
});
|
||||
|
||||
it("Should verify the functionality of amazon athena connection form.", () => {
|
||||
const Accesskey = Cypress.env("amazonathena_accessKey");
|
||||
const Secretkey = Cypress.env("amazonathena_secretKey");
|
||||
const DbName = Cypress.env("amazonathena_DbName");
|
||||
selectAndAddDataSource(
|
||||
"databases",
|
||||
amazonAthenaText.AmazonAthena,
|
||||
data.dsName
|
||||
);
|
||||
|
||||
cy.get(pluginSelectors.amazonAthenaDbName).click().type(DbName);
|
||||
|
||||
cy.get(pluginSelectors.amazonsesAccesKey).click().type(Accesskey);
|
||||
|
||||
fillDataSourceTextField(
|
||||
amazonSesText.labelSecretKey,
|
||||
amazonAthenaText.placeholderSecretKey,
|
||||
Secretkey
|
||||
);
|
||||
|
||||
cy.get(".react-select__dropdown-indicator").eq(1).click();
|
||||
cy.get(".react-select__option").contains("US West (N. California)").click();
|
||||
|
||||
cy.get(postgreSqlSelector.buttonTestConnection).click();
|
||||
cy.get(postgreSqlSelector.textConnectionVerified, {
|
||||
timeout: 10000,
|
||||
}).should("have.text", postgreSqlText.labelConnectionVerified);
|
||||
cy.get(postgreSqlSelector.buttonSave).click();
|
||||
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-amazon-Athena`);
|
||||
});
|
||||
|
||||
it("Should able to run the query with valid conection", () => {
|
||||
const Accesskey = Cypress.env("amazonathena_accessKey");
|
||||
const Secretkey = Cypress.env("amazonathena_secretKey");
|
||||
const DbName = Cypress.env("amazonathena_DbName");
|
||||
selectAndAddDataSource(
|
||||
"databases",
|
||||
amazonAthenaText.AmazonAthena,
|
||||
data.dsName
|
||||
);
|
||||
|
||||
cy.get(pluginSelectors.amazonAthenaDbName).click().type(DbName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
amazonAthenaText.labelAccesskey,
|
||||
amazonAthenaText.placeholderEnteraAccessKey,
|
||||
Cypress.env("amazonathena_accessKey")
|
||||
);
|
||||
fillDataSourceTextField(
|
||||
amazonAthenaText.labelSecretKey,
|
||||
amazonAthenaText.placeholderSecretKey,
|
||||
Cypress.env("amazonathena_secretKey")
|
||||
);
|
||||
|
||||
cy.get(".react-select__dropdown-indicator").eq(1).click();
|
||||
cy.get(".react-select__option").contains("US West (N. California)").click();
|
||||
|
||||
cy.get(postgreSqlSelector.buttonTestConnection).click();
|
||||
cy.get(postgreSqlSelector.textConnectionVerified, {
|
||||
timeout: 10000,
|
||||
}).should("have.text", postgreSqlText.labelConnectionVerified);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave).click();
|
||||
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
cy.get(
|
||||
`[data-cy="cypress-${data.dsName}-amazon-athena-button"]`
|
||||
).verifyVisibleElement("have.text", `cypress-${data.dsName}-amazon-athena`);
|
||||
cy.wait(1000);
|
||||
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
cy.get(commonSelectors.appCreateButton).click();
|
||||
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
|
||||
cy.get(commonSelectors.createAppButton).click();
|
||||
cy.skipWalkthrough();
|
||||
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
cy.get(".css-4e90k9").type(`${data.dsName}`);
|
||||
cy.contains(`[id*="react-select-"]`, data.dsName).click();
|
||||
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
|
||||
|
||||
cy.get('[data-cy="query-input-field"]').clearAndTypeOnCodeMirror(
|
||||
"SHOW DATABASES;"
|
||||
);
|
||||
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { postgreSqlSelector } from "Selectors/postgreSql";
|
||||
import { pluginSelectors } from "Selectors/plugins";
|
||||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { amazonSesText } from "Texts/amazonSes";
|
||||
import { commonSelectors } from "Selectors/common";
|
||||
import { commonText } from "Texts/common";
|
||||
|
||||
import {
|
||||
fillDataSourceTextField,
|
||||
selectAndAddDataSource,
|
||||
} from "Support/utils/postgreSql";
|
||||
|
||||
import {
|
||||
verifyCouldnotConnectWithAlert,
|
||||
deleteDatasource,
|
||||
closeDSModal,
|
||||
addQuery,
|
||||
addDsAndAddQuery,
|
||||
} from "Support/utils/dataSource";
|
||||
|
||||
import { openQueryEditor } from "Support/utils/dataSource";
|
||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||
|
||||
const data = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source amazon ses", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on amazonses connection form", () => {
|
||||
const Accesskey = Cypress.env("amazonSes_accessKey");
|
||||
const Secretkey = Cypress.env("amazonSes_secretKey");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allDataSources()
|
||||
);
|
||||
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.commonlyUsed
|
||||
);
|
||||
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allDatabase()
|
||||
);
|
||||
cy.get(postgreSqlSelector.apiLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allApis
|
||||
);
|
||||
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allCloudStorage
|
||||
);
|
||||
|
||||
selectAndAddDataSource("databases", amazonSesText.AmazonSES, data.dsName);
|
||||
|
||||
cy.get(".react-select__dropdown-indicator").eq(1).click();
|
||||
cy.get(".react-select__option").contains("US West (N. California)").click();
|
||||
|
||||
cy.get(pluginSelectors.amazonsesAccesKey).click().type(Accesskey);
|
||||
|
||||
fillDataSourceTextField(
|
||||
amazonSesText.labelSecretKey,
|
||||
"**************",
|
||||
Secretkey
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-Amazon-ses`);
|
||||
});
|
||||
|
||||
it("Should verify the functionality of amazonses connection form.", () => {
|
||||
selectAndAddDataSource("databases", amazonSesText.AmazonSES, data.dsName);
|
||||
|
||||
cy.get(".react-select__dropdown-indicator").eq(1).click();
|
||||
cy.get(".react-select__option").contains("US West (N. California)").click();
|
||||
|
||||
fillDataSourceTextField(
|
||||
amazonSesText.labelAccesskey,
|
||||
amazonSesText.placeholderAccessKey,
|
||||
Cypress.env("amazonSes_accessKey")
|
||||
);
|
||||
fillDataSourceTextField(
|
||||
amazonSesText.labelSecretKey,
|
||||
amazonSesText.placeholderSecretKey,
|
||||
Cypress.env("amazonSes_secretKey")
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave).click();
|
||||
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
cy.get(
|
||||
`[data-cy="cypress-${data.dsName}-amazon-ses-button"]`
|
||||
).verifyVisibleElement("have.text", `cypress-${data.dsName}-amazon-ses`);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-amazon-ses`);
|
||||
});
|
||||
|
||||
it("Should able to run the query with valid conection", () => {
|
||||
const email = "adish" + "@" + "tooljet.com";
|
||||
selectAndAddDataSource("databases", amazonSesText.AmazonSES, data.dsName);
|
||||
|
||||
cy.get(".react-select__dropdown-indicator").eq(1).click();
|
||||
cy.get(".react-select__option").contains("US West (N. California)").click();
|
||||
|
||||
fillDataSourceTextField(
|
||||
amazonSesText.labelAccesskey,
|
||||
amazonSesText.placeholderAccessKey,
|
||||
Cypress.env("amazonSes_accessKey")
|
||||
);
|
||||
fillDataSourceTextField(
|
||||
amazonSesText.labelSecretKey,
|
||||
amazonSesText.placeholderSecretKey,
|
||||
Cypress.env("amazonSes_secretKey")
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave).click();
|
||||
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
cy.get(
|
||||
`[data-cy="cypress-${data.dsName}-amazon-ses-button"]`
|
||||
).verifyVisibleElement("have.text", `cypress-${data.dsName}-amazon-ses`);
|
||||
cy.wait(1000);
|
||||
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
cy.get(commonSelectors.appCreateButton).click();
|
||||
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
|
||||
cy.get(commonSelectors.createAppButton).click();
|
||||
cy.skipWalkthrough();
|
||||
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
cy.get(".css-4e90k9").type(`${data.dsName}`);
|
||||
cy.contains(`[id*="react-select-"]`, data.dsName).click();
|
||||
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
|
||||
|
||||
cy.get(pluginSelectors.operationDropdown)
|
||||
.click()
|
||||
.type("Email service{enter}");
|
||||
|
||||
cy.wait(500);
|
||||
|
||||
cy.get(pluginSelectors.sendEmailInputField)
|
||||
.realClick()
|
||||
.realType('{{["', { force: true, delay: 0 })
|
||||
.realType("mekhla@tooljet.com", { force: true, delay: 0 });
|
||||
|
||||
cy.get(pluginSelectors.ccEmailInputField)
|
||||
.realClick()
|
||||
.realType('{{["', { force: true, delay: 0 })
|
||||
.realType("mani@tooljet.com", { force: true, delay: 0 });
|
||||
|
||||
cy.get(pluginSelectors.bccEmailInputField)
|
||||
.realClick()
|
||||
.realType('{{["', { force: true, delay: 0 })
|
||||
.realType("midhun@tooljet.com", { force: true, delay: 0 });
|
||||
|
||||
cy.get(pluginSelectors.sendEmailFromInputField)
|
||||
.realClick()
|
||||
.realType("adish", { force: true, delay: 0 })
|
||||
.realType("@", { force: true, delay: 0 })
|
||||
.realType("tooljet.com", { force: true, delay: 0 });
|
||||
|
||||
cy.get(pluginSelectors.emailSubjetInputField).clearAndTypeOnCodeMirror(
|
||||
"Testmail for amazon ses"
|
||||
);
|
||||
|
||||
cy.get(pluginSelectors.emailbodyInputField).clearAndTypeOnCodeMirror(
|
||||
"Body text for amazon ses"
|
||||
);
|
||||
|
||||
cy.wait(1000);
|
||||
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,308 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { postgreSqlSelector } from "Selectors/postgreSql";
|
||||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { appwriteText } from "Texts/appWrite";
|
||||
import { appWriteSelectors } from "Selectors/Plugins";
|
||||
import { commonSelectors } from "Selectors/common";
|
||||
import { commonText } from "Texts/common";
|
||||
|
||||
import {
|
||||
fillDataSourceTextField,
|
||||
selectAndAddDataSource,
|
||||
} from "Support/utils/postgreSql";
|
||||
|
||||
import {
|
||||
verifyCouldnotConnectWithAlert,
|
||||
deleteDatasource,
|
||||
closeDSModal,
|
||||
addQuery,
|
||||
addDsAndAddQuery,
|
||||
} from "Support/utils/dataSource";
|
||||
|
||||
import { openQueryEditor } from "Support/utils/dataSource";
|
||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||
|
||||
const data = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source AppWrite", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on appwrite connection form", () => {
|
||||
const Host = Cypress.env("appwrite_host");
|
||||
const ProjectID = Cypress.env("appwrite_projectID");
|
||||
const DatabaseID = Cypress.env("appwrite_databaseID");
|
||||
const SecretKey = Cypress.env("appwrite_secretkey");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.commonlyUsed
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.apiLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allApis
|
||||
);
|
||||
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allCloudStorage
|
||||
);
|
||||
|
||||
selectAndAddDataSource("databases", appwriteText.appwrite, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
appwriteText.host,
|
||||
appwriteText.hostPlaceholder,
|
||||
Host
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
appwriteText.ProjectID,
|
||||
appwriteText.projectIdPlaceholder,
|
||||
ProjectID
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
appwriteText.DatabaseID,
|
||||
appwriteText.databaseIdPlaceholder,
|
||||
DatabaseID
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
appwriteText.SecretKey,
|
||||
appwriteText.SecretKeyPlaceholder,
|
||||
SecretKey
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonTestConnection).click();
|
||||
cy.get(postgreSqlSelector.textConnectionVerified, {
|
||||
timeout: 10000,
|
||||
}).should("have.text", postgreSqlText.labelConnectionVerified);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-Appwrite`);
|
||||
});
|
||||
|
||||
it("Should verify the functionality of appwrite connection form.", () => {
|
||||
const Host = Cypress.env("appwrite_host");
|
||||
const ProjectID = Cypress.env("appwrite_projectID");
|
||||
const DatabaseID = Cypress.env("appwrite_databaseID");
|
||||
const SecretKey = Cypress.env("appwrite_secretkey");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
selectAndAddDataSource("databases", appwriteText.appwrite, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
appwriteText.host,
|
||||
appwriteText.hostPlaceholder,
|
||||
Host
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
appwriteText.ProjectID,
|
||||
appwriteText.projectIdPlaceholder,
|
||||
ProjectID
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
appwriteText.DatabaseID,
|
||||
appwriteText.databaseIdPlaceholder,
|
||||
DatabaseID
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
appwriteText.SecretKey,
|
||||
appwriteText.SecretKeyPlaceholder,
|
||||
SecretKey
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonTestConnection).click();
|
||||
cy.get(postgreSqlSelector.textConnectionVerified, {
|
||||
timeout: 10000,
|
||||
}).should("have.text", postgreSqlText.labelConnectionVerified);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
deleteDatasource(`cypress-${data.dsName}-Appwrite`);
|
||||
});
|
||||
|
||||
it("Should be able to run the query with a valid connection", () => {
|
||||
const Host = Cypress.env("appwrite_host");
|
||||
const ProjectID = Cypress.env("appwrite_projectID");
|
||||
const DatabaseID = Cypress.env("appwrite_databaseID");
|
||||
const SecretKey = Cypress.env("appwrite_secretkey");
|
||||
const CollectionID = Cypress.env("appwrite_collectionID");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
selectAndAddDataSource("databases", appwriteText.appwrite, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
appwriteText.host,
|
||||
appwriteText.hostPlaceholder,
|
||||
Host
|
||||
);
|
||||
fillDataSourceTextField(
|
||||
appwriteText.ProjectID,
|
||||
appwriteText.projectIdPlaceholder,
|
||||
ProjectID
|
||||
);
|
||||
fillDataSourceTextField(
|
||||
appwriteText.DatabaseID,
|
||||
appwriteText.databaseIdPlaceholder,
|
||||
DatabaseID
|
||||
);
|
||||
fillDataSourceTextField(
|
||||
appwriteText.SecretKey,
|
||||
appwriteText.SecretKeyPlaceholder,
|
||||
SecretKey
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonTestConnection).click();
|
||||
|
||||
cy.get(postgreSqlSelector.textConnectionVerified, {
|
||||
timeout: 10000,
|
||||
}).should("have.text", postgreSqlText.labelConnectionVerified);
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
cy.get(
|
||||
`[data-cy="cypress-${data.dsName}-appwrite-button"]`
|
||||
).verifyVisibleElement("have.text", `cypress-${data.dsName}-appwrite`);
|
||||
cy.wait(1000);
|
||||
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
cy.get(commonSelectors.appCreateButton).click();
|
||||
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
|
||||
cy.get(commonSelectors.createAppButton).click();
|
||||
cy.skipWalkthrough();
|
||||
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
cy.get(".css-4e90k9").type(`${data.dsName}`);
|
||||
cy.contains(`[id*="react-select-"]`, data.dsName).click();
|
||||
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
|
||||
|
||||
// Create API document for delete operation
|
||||
|
||||
cy.request({
|
||||
method: "POST",
|
||||
url: `https://cloud.appwrite.io/v1/databases/${DatabaseID}/collections/${CollectionID}/documents`,
|
||||
headers: {
|
||||
"X-Appwrite-Project": ProjectID,
|
||||
"X-Appwrite-Key": SecretKey,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: {
|
||||
documentId: "unique()",
|
||||
data: {
|
||||
User_name: "test",
|
||||
User_ID: 30,
|
||||
},
|
||||
permissions: ['read("any")'],
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.eq(201);
|
||||
cy.wrap(response.body.$id).as("documentId");
|
||||
});
|
||||
|
||||
// Verify all operations
|
||||
const operations = [
|
||||
"List documents",
|
||||
"Get document",
|
||||
"Add Document to Collection",
|
||||
"Update document",
|
||||
"Delete document",
|
||||
];
|
||||
|
||||
cy.get("@documentId").then((documentId) => {
|
||||
operations.forEach((operation) => {
|
||||
cy.get(".react-select__input")
|
||||
.eq(1)
|
||||
.type(`${operation}{enter}`, { force: true });
|
||||
|
||||
if (operation === "Get document") {
|
||||
cy.get(appWriteSelectors.collectionId).clearAndTypeOnCodeMirror(
|
||||
CollectionID
|
||||
);
|
||||
|
||||
cy.get(appWriteSelectors.documentId).clearAndTypeOnCodeMirror(
|
||||
Cypress.env("appwrite_documentID")
|
||||
);
|
||||
}
|
||||
|
||||
if (operation === "Add Document to Collection") {
|
||||
cy.get(appWriteSelectors.collectionId).clearAndTypeOnCodeMirror(
|
||||
CollectionID
|
||||
);
|
||||
cy.get(appWriteSelectors.bodyInput).clearAndTypeOnCodeMirror(
|
||||
'{"User_name": "John Updated", "User_ID": 35}'
|
||||
);
|
||||
}
|
||||
|
||||
if (operation === "Update document") {
|
||||
cy.get(appWriteSelectors.collectionId).clearAndTypeOnCodeMirror(
|
||||
CollectionID
|
||||
);
|
||||
|
||||
cy.get(appWriteSelectors.documentId).clearAndTypeOnCodeMirror(
|
||||
Cypress.env("appwrite_documentID")
|
||||
);
|
||||
cy.get(appWriteSelectors.bodyInput).clearAndTypeOnCodeMirror(
|
||||
'{"User_name": "John Updated", "User_ID": 35}'
|
||||
);
|
||||
}
|
||||
|
||||
if (operation === "List documents") {
|
||||
cy.get(appWriteSelectors.collectionId).clearAndTypeOnCodeMirror(
|
||||
CollectionID
|
||||
);
|
||||
}
|
||||
|
||||
if (operation === "Delete document") {
|
||||
cy.get(appWriteSelectors.collectionId).clearAndTypeOnCodeMirror(
|
||||
CollectionID
|
||||
);
|
||||
cy.get(appWriteSelectors.documentId).clearAndTypeOnCodeMirror(
|
||||
documentId
|
||||
);
|
||||
}
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
|
||||
// Verify toast message
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { postgreSqlSelector } from "Selectors/postgreSql";
|
||||
import { pluginSelectors, baserowSelectors } from "Selectors/plugins";
|
||||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { amazonSesText } from "Texts/amazonSes";
|
||||
import { baseRowText } from "Texts/baseRow";
|
||||
import { amazonAthenaText } from "Texts/amazonAthena";
|
||||
import { commonSelectors } from "Selectors/common";
|
||||
import { commonText } from "Texts/common";
|
||||
|
||||
import {
|
||||
fillDataSourceTextField,
|
||||
selectAndAddDataSource,
|
||||
} from "Support/utils/postgreSql";
|
||||
|
||||
import {
|
||||
verifyCouldnotConnectWithAlert,
|
||||
deleteDatasource,
|
||||
closeDSModal,
|
||||
addQuery,
|
||||
addDsAndAddQuery,
|
||||
} from "Support/utils/dataSource";
|
||||
|
||||
import { openQueryEditor } from "Support/utils/dataSource";
|
||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||
|
||||
const data = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source baserow", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.intercept("POST", "/api/data_queries").as("createQuery");
|
||||
});
|
||||
|
||||
it("Should verify elements on baserow connection form", () => {
|
||||
const Apikey = Cypress.env("baserow_apikey");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
cy.get(postgreSqlSelector.allDatasourceLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allDataSources()
|
||||
);
|
||||
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.commonlyUsed
|
||||
);
|
||||
cy.get(postgreSqlSelector.databaseLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allDatabase()
|
||||
);
|
||||
cy.get(postgreSqlSelector.apiLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allApis
|
||||
);
|
||||
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allCloudStorage
|
||||
);
|
||||
|
||||
selectAndAddDataSource("databases", baseRowText.baserow, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
baseRowText.lableApiToken,
|
||||
baseRowText.placeholderApiToken,
|
||||
Apikey
|
||||
);
|
||||
|
||||
cy.get(".react-select__control").eq(1).click();
|
||||
|
||||
cy.get(".react-select__option").contains("Baserow Cloud").click();
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-baserow`);
|
||||
});
|
||||
|
||||
it("Should verify the functionality of baserow connection form.", () => {
|
||||
const Apikey = Cypress.env("baserow_apikey");
|
||||
|
||||
selectAndAddDataSource("databases", baseRowText.baserow, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
baseRowText.lableApiToken,
|
||||
baseRowText.placeholderApiToken,
|
||||
Apikey
|
||||
);
|
||||
|
||||
cy.get(".react-select__control").eq(1).click();
|
||||
|
||||
cy.get(".react-select__option").contains("Baserow Cloud").click();
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
deleteDatasource(`cypress-${data.dsName}-baserow`);
|
||||
});
|
||||
|
||||
it("Should be able to run the query with a valid connection", () => {
|
||||
const baserowTableID = Cypress.env("baserow_tableid");
|
||||
const baserowRowID = Cypress.env("baserow_rowid");
|
||||
const Apikey = Cypress.env("baserow_apikey");
|
||||
|
||||
selectAndAddDataSource("databases", baseRowText.baserow, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
baseRowText.lableApiToken,
|
||||
baseRowText.placeholderApiToken,
|
||||
Apikey
|
||||
);
|
||||
|
||||
cy.get(".react-select__control").eq(1).click();
|
||||
cy.get(".react-select__option").contains("Baserow Cloud").click();
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
cy.get(
|
||||
`[data-cy="cypress-${data.dsName}-baserow-button"]`
|
||||
).verifyVisibleElement("have.text", `cypress-${data.dsName}-baserow`);
|
||||
cy.wait(1000);
|
||||
|
||||
cy.log("Baserow Table ID:", baserowTableID);
|
||||
cy.log("Row ID:", baserowRowID);
|
||||
cy.log("API Key:", Apikey);
|
||||
|
||||
if (!baserowTableID || !Apikey) {
|
||||
throw new Error("Missing required environment variables!");
|
||||
}
|
||||
|
||||
cy.request({
|
||||
method: "POST",
|
||||
url: `https://api.baserow.io/api/database/rows/table/${baserowTableID}/`,
|
||||
headers: { Authorization: `Token ${Apikey}` },
|
||||
body: {
|
||||
field_1: "Sample Data",
|
||||
field_2: "Another Value",
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.eq(200);
|
||||
const rowId = response.body.id;
|
||||
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
cy.get(commonSelectors.appCreateButton).click();
|
||||
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
|
||||
cy.get(commonSelectors.createAppButton).click();
|
||||
cy.skipWalkthrough();
|
||||
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
cy.get(".css-4e90k9").type(`${data.dsName}`);
|
||||
cy.contains(`[id*="react-select-"]`, data.dsName).click();
|
||||
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
|
||||
|
||||
// Verify delete operation (Need to uncomment after bug fixes)
|
||||
|
||||
// cy.get('[data-cy="operation-select-dropdown"]').click();
|
||||
// cy.get(".react-select__option").contains("Delete row").click();
|
||||
|
||||
// cy.get(baserowSelectors.baserowTabelId).clearAndTypeOnCodeMirror(baserowTableID);
|
||||
// cy.get(baserowSelectors.rowIdinputfield).clearAndTypeOnCodeMirror(rowId.toString());
|
||||
|
||||
// cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
// cy.verifyToastMessage(commonSelectors.toastMessage, `Query (${data.dsName}) completed.`);
|
||||
});
|
||||
|
||||
// Verify other operations
|
||||
const operations = [
|
||||
"List fields",
|
||||
"List rows",
|
||||
"Get row",
|
||||
"Create row",
|
||||
"Update row",
|
||||
"Move row",
|
||||
];
|
||||
|
||||
operations.forEach((operation) => {
|
||||
cy.get(pluginSelectors.operationDropdown).click();
|
||||
cy.get(".react-select__option").contains(operation).click();
|
||||
|
||||
cy.get(baserowSelectors.table).clearAndTypeOnCodeMirror(baserowTableID);
|
||||
|
||||
if (operation === "Get row") {
|
||||
cy.get(baserowSelectors.rowIdinputfield).clearAndTypeOnCodeMirror(
|
||||
baserowRowID
|
||||
);
|
||||
}
|
||||
if (operation === "Move row") {
|
||||
cy.get('[data-cy="before-id-input-field"]').clearAndTypeOnCodeMirror(
|
||||
"1"
|
||||
);
|
||||
}
|
||||
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { postgreSqlSelector } from "Selectors/postgreSql";
|
||||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { minioText } from "Texts/minio";
|
||||
import { minioSelectors } from "Selectors/Plugins";
|
||||
import { commonSelectors } from "Selectors/common";
|
||||
import { commonText } from "Texts/common";
|
||||
|
||||
import {
|
||||
fillDataSourceTextField,
|
||||
selectAndAddDataSource,
|
||||
} from "Support/utils/postgreSql";
|
||||
|
||||
import {
|
||||
verifyCouldnotConnectWithAlert,
|
||||
deleteDatasource,
|
||||
closeDSModal,
|
||||
addQuery,
|
||||
addDsAndAddQuery,
|
||||
} from "Support/utils/dataSource";
|
||||
|
||||
import { openQueryEditor } from "Support/utils/dataSource";
|
||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||
|
||||
const data = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source minio", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
});
|
||||
|
||||
it("Should verify elements on minio connection form", () => {
|
||||
const Host = Cypress.env("minio_host");
|
||||
const Port = Cypress.env("minio_port");
|
||||
const AccessKey = Cypress.env("minio_accesskey");
|
||||
const SecretKey = Cypress.env("minio_secretkey");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.commonlyUsed
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.apiLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allApis
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allCloudStorage
|
||||
);
|
||||
|
||||
selectAndAddDataSource("databases", minioText.minio, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.hostLabel,
|
||||
minioText.hostInputPlaceholder,
|
||||
Host
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.portLabel,
|
||||
minioText.portPlaceholder,
|
||||
Port
|
||||
);
|
||||
|
||||
cy.get(`[${minioSelectors.sslToggle}]`).click();
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.labelAccesskey,
|
||||
minioText.placeholderAccessKey,
|
||||
AccessKey
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.labelSecretKey,
|
||||
minioText.placeholderSecretKey,
|
||||
SecretKey
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonTestConnection).click();
|
||||
cy.get(postgreSqlSelector.textConnectionVerified, {
|
||||
timeout: 10000,
|
||||
}).should("have.text", postgreSqlText.labelConnectionVerified);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-minio`);
|
||||
});
|
||||
|
||||
it("Should verify functionality of minio connection form", () => {
|
||||
const Host = Cypress.env("minio_host");
|
||||
const Port = Cypress.env("minio_port");
|
||||
const AccessKey = Cypress.env("minio_accesskey");
|
||||
const SecretKey = Cypress.env("minio_secretkey");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
selectAndAddDataSource("databases", minioText.minio, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.hostLabel,
|
||||
minioText.hostInputPlaceholder,
|
||||
Host
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.portLabel,
|
||||
minioText.portPlaceholder,
|
||||
Port
|
||||
);
|
||||
|
||||
cy.get(`[${minioSelectors.sslToggle}]`).click();
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.labelAccesskey,
|
||||
minioText.placeholderAccessKey,
|
||||
AccessKey
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.labelSecretKey,
|
||||
minioText.placeholderSecretKey,
|
||||
SecretKey
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonTestConnection).click();
|
||||
cy.get(postgreSqlSelector.textConnectionVerified, {
|
||||
timeout: 10000,
|
||||
}).should("have.text", postgreSqlText.labelConnectionVerified);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-minio`);
|
||||
});
|
||||
|
||||
it("Should be able to run the query with a valid connection", () => {
|
||||
const Host = Cypress.env("minio_host");
|
||||
const Port = Cypress.env("minio_port");
|
||||
const AccessKey = Cypress.env("minio_accesskey");
|
||||
const SecretKey = Cypress.env("minio_secretkey");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
selectAndAddDataSource("databases", minioText.minio, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.hostLabel,
|
||||
minioText.hostInputPlaceholder,
|
||||
Host
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.portLabel,
|
||||
minioText.portPlaceholder,
|
||||
Port
|
||||
);
|
||||
|
||||
cy.get(`[${minioSelectors.sslToggle}]`).click();
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.labelAccesskey,
|
||||
minioText.placeholderAccessKey,
|
||||
AccessKey
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
minioText.labelSecretKey,
|
||||
minioText.placeholderSecretKey,
|
||||
SecretKey
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonTestConnection).click();
|
||||
cy.get(postgreSqlSelector.textConnectionVerified, {
|
||||
timeout: 10000,
|
||||
}).should("have.text", postgreSqlText.labelConnectionVerified);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
cy.get(commonSelectors.appCreateButton).click();
|
||||
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
|
||||
cy.get(commonSelectors.createAppButton).click();
|
||||
cy.skipWalkthrough();
|
||||
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
cy.get(".css-4e90k9").type(`${data.dsName}`);
|
||||
cy.contains(`[id*="react-select-"]`, data.dsName).click();
|
||||
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
|
||||
|
||||
const operationsMinio = [
|
||||
"List buckets",
|
||||
"Put object",
|
||||
"List objects in a bucket",
|
||||
"Read object",
|
||||
"Presigned url for download",
|
||||
"Presigned url for upload",
|
||||
"Remove object",
|
||||
];
|
||||
|
||||
operationsMinio.forEach((operation) => {
|
||||
cy.get(".react-select__input")
|
||||
.eq(1)
|
||||
.type(`${operation}{enter}`, { force: true });
|
||||
|
||||
if (operation === "List objects in a bucket") {
|
||||
cy.get(minioSelectors.bucketNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.bucketName
|
||||
);
|
||||
}
|
||||
if (operation === "Read object" || operation === "Remove object") {
|
||||
cy.get(minioSelectors.bucketNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.bucketName
|
||||
);
|
||||
cy.get(minioSelectors.objectNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.objectName
|
||||
);
|
||||
}
|
||||
if (operation === "Put object") {
|
||||
cy.get(minioSelectors.bucketNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.bucketName
|
||||
);
|
||||
cy.get(minioSelectors.objectNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.objectName
|
||||
);
|
||||
cy.get(minioSelectors.contentTypeInputField).clearAndTypeOnCodeMirror(
|
||||
'"string"'
|
||||
);
|
||||
cy.get(minioSelectors.dataInput).clearAndTypeOnCodeMirror(`test`);
|
||||
}
|
||||
if (
|
||||
operation === "Presigned url for download" ||
|
||||
operation === "Presigned url for upload"
|
||||
) {
|
||||
cy.get(minioSelectors.bucketNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.bucketName
|
||||
);
|
||||
cy.get(minioSelectors.objectNameInputField).clearAndTypeOnCodeMirror(
|
||||
minioText.objectName
|
||||
);
|
||||
}
|
||||
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -123,7 +123,7 @@ describe("Data sources", () => {
|
|||
);
|
||||
|
||||
cy.clearAndType(
|
||||
'[data-cy="data-source-name-input-filed"]',
|
||||
'[data-cy="data-source-name-input-field"]',
|
||||
postgreSqlText.psqlName
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ const data = {};
|
|||
|
||||
describe("Data sources AWS S3", () => {
|
||||
beforeEach(() => {
|
||||
cy.appUILogin();
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
data.dataSourceName = fake.lastName
|
||||
.toLowerCase()
|
||||
.replaceAll("[^A-Za-z]", "");
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ describe("Data sources", () => {
|
|||
selectAndAddDataSource(postgreSqlText.postgreSQL);
|
||||
|
||||
cy.clearAndType(
|
||||
'[data-cy="data-source-name-input-filed"]',
|
||||
'[data-cy="data-source-name-input-field"]',
|
||||
postgreSqlText.psqlName
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,189 @@
|
|||
import { fake } from "Fixtures/fake";
|
||||
import { postgreSqlSelector } from "Selectors/postgreSql";
|
||||
import { postgreSqlText } from "Texts/postgreSql";
|
||||
import { twilioText } from "Texts/twilio";
|
||||
import { twilioSelectors } from "Selectors/Plugins";
|
||||
import { commonSelectors } from "Selectors/common";
|
||||
import { commonText } from "Texts/common";
|
||||
|
||||
import {
|
||||
fillDataSourceTextField,
|
||||
selectAndAddDataSource,
|
||||
} from "Support/utils/postgreSql";
|
||||
|
||||
import {
|
||||
verifyCouldnotConnectWithAlert,
|
||||
deleteDatasource,
|
||||
closeDSModal,
|
||||
addQuery,
|
||||
addDsAndAddQuery,
|
||||
} from "Support/utils/dataSource";
|
||||
|
||||
import { openQueryEditor } from "Support/utils/dataSource";
|
||||
import { dataSourceSelector } from "../../../../../constants/selectors/dataSource";
|
||||
import { pluginSelectors } from "Selectors/plugins";
|
||||
|
||||
const data = {};
|
||||
data.dsName = fake.lastName.toLowerCase().replaceAll("[^A-Za-z]", "");
|
||||
|
||||
describe("Data source Twilio", () => {
|
||||
beforeEach(() => {
|
||||
cy.apiLogin();
|
||||
cy.defaultWorkspaceLogin();
|
||||
});
|
||||
|
||||
it("Should verify elements on Twilio connection form", () => {
|
||||
const AuthToken = Cypress.env("twilio_auth_token");
|
||||
const AccountSID = Cypress.env("twilio_account_SID");
|
||||
const MessageSID = Cypress.env("twilio_messaging_service_SID");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
cy.get(postgreSqlSelector.commonlyUsedLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.commonlyUsed
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.apiLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allApis
|
||||
);
|
||||
cy.get(postgreSqlSelector.cloudStorageLabelAndCount).should(
|
||||
"have.text",
|
||||
postgreSqlText.allCloudStorage
|
||||
);
|
||||
|
||||
selectAndAddDataSource("databases", twilioText.twilio, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.authTokenLabel,
|
||||
twilioText.authTokenPlaceholder,
|
||||
AuthToken
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.accountSidLabel,
|
||||
twilioText.accountSidPlaceholder,
|
||||
AccountSID
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.messagingSIDLabel,
|
||||
twilioText.messagingSIDPalceholder,
|
||||
MessageSID
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-twilio`);
|
||||
});
|
||||
|
||||
it("Should verify functionality of Twilio connection form", () => {
|
||||
const AuthToken = Cypress.env("twilio_auth_token");
|
||||
const AccountSID = Cypress.env("twilio_account_SID");
|
||||
const MessageSID = Cypress.env("twilio_messaging_service_SID");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
selectAndAddDataSource("databases", twilioText.twilio, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.authTokenLabel,
|
||||
twilioText.authTokenPlaceholder,
|
||||
AuthToken
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.accountSidLabel,
|
||||
twilioText.accountSidPlaceholder,
|
||||
AccountSID
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.messagingSIDLabel,
|
||||
twilioText.messagingSIDPalceholder,
|
||||
MessageSID
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
deleteDatasource(`cypress-${data.dsName}-twilio`);
|
||||
});
|
||||
|
||||
it("Should be able to run the query with a valid connection", () => {
|
||||
const AuthToken = Cypress.env("twilio_auth_token");
|
||||
const AccountSID = Cypress.env("twilio_account_SID");
|
||||
const MessageSID = Cypress.env("twilio_messaging_service_SID");
|
||||
const MessageNumber = Cypress.env("twilio_message_number");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
closeDSModal();
|
||||
|
||||
selectAndAddDataSource("databases", twilioText.twilio, data.dsName);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.authTokenLabel,
|
||||
twilioText.authTokenPlaceholder,
|
||||
AuthToken
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.accountSidLabel,
|
||||
twilioText.accountSidPlaceholder,
|
||||
AccountSID
|
||||
);
|
||||
|
||||
fillDataSourceTextField(
|
||||
twilioText.messagingSIDLabel,
|
||||
twilioText.messagingSIDPalceholder,
|
||||
MessageSID
|
||||
);
|
||||
|
||||
cy.get(postgreSqlSelector.buttonSave)
|
||||
.verifyVisibleElement("have.text", postgreSqlText.buttonTextSave)
|
||||
.click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
postgreSqlText.toastDSSaved
|
||||
);
|
||||
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
cy.get(commonSelectors.appCreateButton).click();
|
||||
cy.get(commonSelectors.appNameInput).click().type(data.dsName);
|
||||
cy.get(commonSelectors.createAppButton).click();
|
||||
cy.skipWalkthrough();
|
||||
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
cy.get(".css-4e90k9").type(`${data.dsName}`);
|
||||
cy.contains(`[id*="react-select-"]`, data.dsName).click();
|
||||
cy.get('[data-cy="query-rename-input"]').clear().type(data.dsName);
|
||||
|
||||
cy.get(pluginSelectors.operationDropdown).click().type("Send SMS{enter}");
|
||||
|
||||
cy.get(twilioSelectors.toNumberInputField).clearAndTypeOnCodeMirror(
|
||||
MessageNumber
|
||||
);
|
||||
cy.get(twilioSelectors.bodyInput).clearAndTypeOnCodeMirror(
|
||||
twilioText.messageText
|
||||
);
|
||||
cy.get(dataSourceSelector.queryPreviewButton).click();
|
||||
cy.verifyToastMessage(
|
||||
commonSelectors.toastMessage,
|
||||
`Query (${data.dsName}) completed.`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -10,7 +10,7 @@ export const connectMongo = () => {
|
|||
selectAndAddDataSource(mongoDbText.mongoDb);
|
||||
|
||||
cy.clearAndType(
|
||||
'[data-cy="data-source-name-input-filed"]',
|
||||
'[data-cy="data-source-name-input-field"]',
|
||||
mongoDbText.cypressMongoDb
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { commonSelectors } from "../../constants/selectors/common";
|
|||
|
||||
export const searchPage = (pageName) => {
|
||||
cy.get('[title="Search"]').click();
|
||||
cy.get('[data-cy="search-input-filed"]').type(pageName);
|
||||
cy.get('[data-cy="search-input-field"]').type(pageName);
|
||||
};
|
||||
|
||||
export const clearSearch = () => {
|
||||
|
|
|
|||
|
|
@ -48,27 +48,25 @@ export const selectAndAddDataSource = (
|
|||
dataSourceName
|
||||
) => {
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
cy.wait(1000)
|
||||
cy.wait(1000);
|
||||
cy.get(`[data-cy="${cyParamName(dscategory)}-datasource-button"]`).click();
|
||||
cy.wait(500)
|
||||
cy.wait(500);
|
||||
cy.get(postgreSqlSelector.dataSourceSearchInputField).type(dataSource);
|
||||
cy.get(`[data-cy="data-source-${(dataSource).toLowerCase()}"]`)
|
||||
cy.get(`[data-cy="data-source-${dataSource.toLowerCase()}"]`)
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.get(
|
||||
`[data-cy="data-source-${(
|
||||
dataSource
|
||||
).toLowerCase()}"]>>>.datasource-card-title`
|
||||
`[data-cy="data-source-${dataSource.toLowerCase()}"]>>>.datasource-card-title`
|
||||
).realHover("mouse");
|
||||
cy.get(
|
||||
`[data-cy="${cyParamName(dataSource).toLowerCase()}-add-button"]`
|
||||
).click();
|
||||
});
|
||||
|
||||
cy.wait(1000)
|
||||
cy.get(postgreSqlSelector.buttonSave).should("be.disabled")
|
||||
cy.wait(1000);
|
||||
cy.get(postgreSqlSelector.buttonSave).should("be.disabled");
|
||||
cy.clearAndType(
|
||||
'[data-cy="data-source-name-input-filed"]',
|
||||
'[data-cy="data-source-name-input-field"]',
|
||||
cyParamName(`cypress-${dataSourceName}-${dataSource}`)
|
||||
);
|
||||
cy.get(postgreSqlSelector.buttonSave).click();
|
||||
|
|
@ -184,4 +182,4 @@ export const addWidgetsToAddUser = () => {
|
|||
addEventHandlerToRunQuery("add_data_using_widgets");
|
||||
};
|
||||
|
||||
export const addListviewToVerifyData = () => { };
|
||||
export const addListviewToVerifyData = () => {};
|
||||
|
|
|
|||
|
|
@ -62,8 +62,40 @@ FROM debian:11
|
|||
RUN apt-get update -yq \
|
||||
&& apt-get install curl 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
|
||||
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/*
|
||||
|
||||
# Install PostgREST from official Docker image
|
||||
COPY --from=postgrest/postgrest:v12.2.0 /bin/postgrest /bin
|
||||
|
||||
RUN apt-get update && apt-get install -y supervisor
|
||||
|
||||
# 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" | sed 's/ //' > /etc/supervisor/conf.d/supervisord.conf
|
||||
|
||||
# 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 curl -O https://nodejs.org/dist/v18.18.2/node-v18.18.2-linux-x64.tar.xz \
|
||||
&& tar -xf node-v18.18.2-linux-x64.tar.xz \
|
||||
|
|
@ -152,6 +184,25 @@ RUN mkdir -p /tmp/.npm/npm-cache/_logs \
|
|||
&& chmod g+s /tmp/.npm/npm-cache/_logs \
|
||||
&& chmod -R g=u /tmp/.npm/npm-cache/_logs
|
||||
|
||||
# Create Redis data, log, and configuration directories
|
||||
RUN mkdir -p /var/lib/redis /var/log/redis /etc/redis \
|
||||
&& chown -R appuser:0 /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
|
||||
|
||||
# Switch back to appuser
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export const ConfigHandle = ({
|
|||
showHandle,
|
||||
componentType,
|
||||
visibility,
|
||||
subContainerIndex,
|
||||
}) => {
|
||||
const shouldFreeze = useStore((state) => state.getShouldFreeze());
|
||||
const componentName = useStore((state) => state.getComponentDefinition(id)?.component?.name || '', shallow);
|
||||
|
|
@ -40,10 +41,12 @@ export const ConfigHandle = ({
|
|||
const anyComponentHovered = state.getHoveredComponentForGrid() !== '' || state.hoveredComponentBoundaryId !== '';
|
||||
// If one component is hovered and one is selected, show the handle for the hovered component
|
||||
return (
|
||||
isWidgetHovered ||
|
||||
(showHandle && (!isMultipleComponentsSelected || (isModal && isModalOpen)) && !anyComponentHovered)
|
||||
(subContainerIndex === 0 || subContainerIndex === null) &&
|
||||
(isWidgetHovered ||
|
||||
(showHandle && (!isMultipleComponentsSelected || (isModal && isModalOpen)) && !anyComponentHovered))
|
||||
);
|
||||
}, shallow);
|
||||
|
||||
let height = visibility === false ? 10 : widgetHeight;
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ const WidgetWrapper = memo(
|
|||
showHandle={isWidgetActive}
|
||||
componentType={componentType}
|
||||
visibility={visibility}
|
||||
subContainerIndex={subContainerIndex}
|
||||
/>
|
||||
)}
|
||||
<RenderWidget
|
||||
|
|
|
|||
|
|
@ -248,6 +248,12 @@ const getSelectedText = () => {
|
|||
|
||||
// TODO: Move this function to componentSlice
|
||||
export const copyComponents = ({ isCut = false, isCloning = false }) => {
|
||||
const selectedText = window.getSelection()?.toString().trim();
|
||||
if (selectedText) {
|
||||
navigator.clipboard.writeText(selectedText);
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedComponents = useStore.getState().getSelectedComponentsDefinition();
|
||||
if (selectedComponents.length < 1) return getSelectedText();
|
||||
const allComponents = useStore.getState().getCurrentPageComponents();
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ export function getSuggestionKeys(refState) {
|
|||
'setVariable',
|
||||
'getVariable',
|
||||
'unSetVariable',
|
||||
'unsetAllVariables',
|
||||
'showAlert',
|
||||
'logout',
|
||||
'showModal',
|
||||
|
|
@ -85,6 +86,7 @@ export function getSuggestionKeys(refState) {
|
|||
'setPageVariable',
|
||||
'getPageVariable',
|
||||
'unsetPageVariable',
|
||||
'unsetAllPageVariables',
|
||||
'switchPage',
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -294,13 +294,9 @@ const PreviewContainer = ({
|
|||
...restProps
|
||||
}) => {
|
||||
const { validationSchema, isWorkspaceVariable, errorStateActive, previewPlacement, validationFn } = restProps;
|
||||
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
|
||||
const typeofError = getCurrentNodeType(errorMessage);
|
||||
|
||||
const errorMsg = typeofError === 'Array' ? errorMessage[0] : errorMessage;
|
||||
|
||||
const darkMode = localStorage.getItem('darkMode') === 'true';
|
||||
const popover = (
|
||||
<Popover
|
||||
|
|
@ -423,10 +419,12 @@ const PreviewContainer = ({
|
|||
<>
|
||||
{!isPortalOpen && (
|
||||
<Overlay
|
||||
placement="left"
|
||||
placement={previewPlacement || 'left'}
|
||||
{...(previewRef?.current ? { target: previewRef.current } : {})}
|
||||
show={showPreview}
|
||||
rootClose
|
||||
shouldUpdatePosition={true}
|
||||
container={document.body}
|
||||
popperConfig={{
|
||||
modifiers: [
|
||||
{
|
||||
|
|
@ -441,6 +439,7 @@ const PreviewContainer = ({
|
|||
{
|
||||
name: 'preventOverflow',
|
||||
options: {
|
||||
enabled: true,
|
||||
boundary: 'viewport',
|
||||
altAxis: true,
|
||||
tether: false,
|
||||
|
|
@ -449,10 +448,17 @@ const PreviewContainer = ({
|
|||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [33, 15],
|
||||
offset: [0, 3],
|
||||
},
|
||||
},
|
||||
],
|
||||
onFirstUpdate: (state) => {
|
||||
// Force position update on first render
|
||||
// This is done to avoid scroll issue
|
||||
if (state.elements.popper) {
|
||||
state.elements.popper.style.position = 'fixed';
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
{(props) => React.cloneElement(popover, props)}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/* eslint-disable import/no-unresolved */
|
||||
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { PreviewBox } from './PreviewBox';
|
||||
import { ToolTip } from '@/Editor/Inspector/Elements/Components/ToolTip';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
|
@ -31,6 +31,7 @@ const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...r
|
|||
const [currentValue, setCurrentValue] = useState('');
|
||||
const [errorStateActive, setErrorStateActive] = useState(false);
|
||||
const [cursorInsidePreview, setCursorInsidePreview] = useState(false);
|
||||
const [showSuggestions, setShowSuggestions] = useState(true);
|
||||
const validationFn = restProps?.validationFn;
|
||||
const componentDefinition = useStore((state) => state.getComponentDefinition(componentId), shallow);
|
||||
const parentId = componentDefinition?.component?.parent;
|
||||
|
|
@ -38,6 +39,30 @@ const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...r
|
|||
|
||||
const customVariables = customResolvables?.[parentId]?.[0] || {};
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
if (entry.intersectionRatio < 1) {
|
||||
setShowPreview(false);
|
||||
setShowSuggestions(false);
|
||||
} else {
|
||||
setShowSuggestions(true);
|
||||
}
|
||||
},
|
||||
{ root: null, threshold: [1] } // Fires when any part of the element is out of view
|
||||
);
|
||||
|
||||
if (wrapperRef.current) {
|
||||
observer.observe(wrapperRef.current);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (wrapperRef.current) {
|
||||
observer.unobserve(wrapperRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const isPreviewFocused = useRef(false);
|
||||
const wrapperRef = useRef(null);
|
||||
|
||||
|
|
@ -136,6 +161,7 @@ const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...r
|
|||
componentName={componentName}
|
||||
setShowPreview={setShowPreview}
|
||||
showPreview={showPreview}
|
||||
showSuggestions={showSuggestions}
|
||||
{...restProps}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -168,6 +194,7 @@ const EditorInput = ({
|
|||
previewRef,
|
||||
setShowPreview,
|
||||
onInputChange,
|
||||
showSuggestions,
|
||||
}) => {
|
||||
const getSuggestions = useStore((state) => state.getSuggestions, shallow);
|
||||
function autoCompleteExtensionConfig(context) {
|
||||
|
|
@ -223,7 +250,7 @@ const EditorInput = ({
|
|||
defaultKeymap: true,
|
||||
positionInfo: () => {
|
||||
return {
|
||||
class: 'cm-completionInfo-top cm-custom-completion-info',
|
||||
class: 'cm-completionInfo-top cm-custom-completion-info cm-custom-singleline-completion-info',
|
||||
};
|
||||
},
|
||||
maxRenderedOptions: 10,
|
||||
|
|
@ -286,7 +313,7 @@ const EditorInput = ({
|
|||
const isInsideQueryPane = !!currentEditorHeightRef?.current?.closest('.query-details');
|
||||
const showLineNumbers = lang == 'jsx' || type === 'extendedSingleLine' || false;
|
||||
|
||||
const customClassNames = cx('codehinter-input', {
|
||||
const customClassNames = cx('codehinter-input single-line-codehinter-input', {
|
||||
'border-danger': error,
|
||||
focused: isFocused,
|
||||
'focus-box-shadow-active': firstTimeFocus,
|
||||
|
|
@ -336,18 +363,9 @@ const EditorInput = ({
|
|||
<div
|
||||
ref={currentEditorHeightRef}
|
||||
className={`cm-codehinter ${darkMode && 'cm-codehinter-dark-themed'} ${disabled ? 'disabled-cursor' : ''}`}
|
||||
data-cy={`${cyLabel}-input-field`}
|
||||
data-cy={`${cyLabel.replace(/_/g, '-')}-input-field`}
|
||||
>
|
||||
{/* sticky element to position the preview box correctly on top without flowing out of container */}
|
||||
<div
|
||||
style={{
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: 1000,
|
||||
}}
|
||||
ref={previewRef}
|
||||
></div>
|
||||
{usePortalEditor && (
|
||||
<CodeHinter.PopupIcon
|
||||
callback={handleTogglePopupExapand}
|
||||
|
|
@ -372,39 +390,55 @@ const EditorInput = ({
|
|||
callgpt={null}
|
||||
>
|
||||
<ErrorBoundary>
|
||||
<CodeMirror
|
||||
value={currentValue}
|
||||
placeholder={placeholder}
|
||||
height={isInsideQueryPane ? '100%' : showLineNumbers ? '400px' : '100%'}
|
||||
width="100%"
|
||||
extensions={[
|
||||
javascript({ jsx: lang === 'jsx' }),
|
||||
autoCompleteConfig,
|
||||
keymap.of([...customKeyMaps]),
|
||||
customTabKeymap,
|
||||
]}
|
||||
onChange={(val) => {
|
||||
setFirstTimeFocus(false);
|
||||
handleOnChange(val);
|
||||
onInputChange && onInputChange(val);
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
basicSetup={{
|
||||
lineNumbers: showLineNumbers,
|
||||
syntaxHighlighting: true,
|
||||
bracketMatching: true,
|
||||
foldGutter: false,
|
||||
highlightActiveLine: false,
|
||||
autocompletion: true,
|
||||
completionKeymap: true,
|
||||
searchKeymap: false,
|
||||
}}
|
||||
onMouseDown={() => handleFocus()}
|
||||
onBlur={() => handleOnBlur()}
|
||||
className={customClassNames}
|
||||
theme={theme}
|
||||
indentWithTab={false}
|
||||
readOnly={disabled}
|
||||
/>
|
||||
className="check-here"
|
||||
ref={previewRef}
|
||||
>
|
||||
<CodeMirror
|
||||
value={currentValue}
|
||||
placeholder={placeholder}
|
||||
height={isInsideQueryPane ? '100%' : showLineNumbers ? '400px' : '100%'}
|
||||
width="100%"
|
||||
extensions={
|
||||
showSuggestions
|
||||
? [
|
||||
javascript({ jsx: lang === 'jsx' }),
|
||||
autoCompleteConfig,
|
||||
keymap.of([...customKeyMaps]),
|
||||
customTabKeymap,
|
||||
]
|
||||
: [javascript({ jsx: lang === 'jsx' })]
|
||||
}
|
||||
onChange={(val) => {
|
||||
setFirstTimeFocus(false);
|
||||
handleOnChange(val);
|
||||
onInputChange && onInputChange(val);
|
||||
}}
|
||||
basicSetup={{
|
||||
lineNumbers: showLineNumbers,
|
||||
syntaxHighlighting: true,
|
||||
bracketMatching: true,
|
||||
foldGutter: false,
|
||||
highlightActiveLine: false,
|
||||
autocompletion: showSuggestions,
|
||||
completionKeymap: true,
|
||||
searchKeymap: false,
|
||||
}}
|
||||
onMouseDown={() => handleFocus()}
|
||||
onBlur={() => handleOnBlur()}
|
||||
className={customClassNames}
|
||||
theme={theme}
|
||||
indentWithTab={false}
|
||||
readOnly={disabled}
|
||||
/>
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
</CodeHinter.Portal>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -655,6 +655,11 @@
|
|||
background-color: #F28F2D !important;
|
||||
}
|
||||
|
||||
|
||||
.cm-custom-singleline-completion-info {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tjdb-hinter-portal{
|
||||
.cm-theme{
|
||||
height: 100% ;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ export const BaseLeftSidebar = ({
|
|||
resetUnreadErrorCount,
|
||||
toggleLeftSidebar,
|
||||
isSidebarOpen,
|
||||
isDraggingQueryPane,
|
||||
] = useStore(
|
||||
(state) => [
|
||||
state.isLeftSideBarPinned,
|
||||
|
|
@ -46,6 +47,7 @@ export const BaseLeftSidebar = ({
|
|||
state.debugger.resetUnreadErrorCount,
|
||||
state.toggleLeftSidebar,
|
||||
state.isSidebarOpen,
|
||||
state.queryPanel.isDraggingQueryPane,
|
||||
],
|
||||
shallow
|
||||
);
|
||||
|
|
@ -68,11 +70,15 @@ export const BaseLeftSidebar = ({
|
|||
};
|
||||
|
||||
useEffect(() => {
|
||||
setPopoverContentHeight(
|
||||
((window.innerHeight - (queryPanelHeight == 0 ? 40 : queryPanelHeight) - 45) / window.innerHeight) * 100
|
||||
);
|
||||
if (!isDraggingQueryPane) {
|
||||
setPopoverContentHeight(
|
||||
((window.innerHeight - (queryPanelHeight == 0 ? 40 : queryPanelHeight) - 45) / window.innerHeight) * 100
|
||||
);
|
||||
} else {
|
||||
setPopoverContentHeight(100);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [queryPanelHeight]);
|
||||
}, [queryPanelHeight, isDraggingQueryPane]);
|
||||
|
||||
const renderPopoverContent = () => {
|
||||
if (selectedSidebarItem === null || !isSidebarOpen) return null;
|
||||
|
|
|
|||
|
|
@ -108,7 +108,8 @@ export const Transformation = ({ changeOption, options, darkMode, queryId, rende
|
|||
const [codeEditorKey, setCodeEditorKey] = useState(uuidv4());
|
||||
const [state, setState] = useState({
|
||||
...defaultValue,
|
||||
[options.transformationLanguage ?? 'javascript']: options?.transformation,
|
||||
...(options?.transformation ? { [options.transformationLanguage ?? 'javascript']: options?.transformation } : {}),
|
||||
...options?.transformations,
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
|
@ -119,7 +120,6 @@ export const Transformation = ({ changeOption, options, darkMode, queryId, rende
|
|||
useEffect(() => {
|
||||
if (lang !== (options.transformationLanguage ?? 'javascript')) {
|
||||
changeOption('transformationLanguage', lang);
|
||||
changeOption('transformation', state[lang]);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [lang]);
|
||||
|
|
@ -127,20 +127,24 @@ export const Transformation = ({ changeOption, options, darkMode, queryId, rende
|
|||
useEffect(() => {
|
||||
if (prevQueryId.current === queryId) {
|
||||
lang !== (options.transformationLanguage ?? 'javascript') && changeOption('transformationLanguage', lang);
|
||||
setState({ ...state, [lang]: options.transformation ?? state[lang] ?? defaultValue[lang] });
|
||||
setState((prevState) => {
|
||||
return {
|
||||
...prevState,
|
||||
...(options?.transformation
|
||||
? { [options.transformationLanguage ?? 'javascript']: options?.transformation }
|
||||
: {}),
|
||||
...options?.transformations,
|
||||
};
|
||||
});
|
||||
}
|
||||
prevQueryId.current = queryId;
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [JSON.stringify(options.transformation)]);
|
||||
}, [JSON.stringify(options?.transformation || {}), JSON.stringify(options.transformations)]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedQueryId !== queryId) {
|
||||
const nonLangdefaultCode = getNonActiveTransformations(options?.transformationLanguage ?? 'javascript');
|
||||
const finalState = _.merge(
|
||||
{},
|
||||
{ [options?.transformationLanguage ?? lang]: options.transformation ?? defaultValue[lang] },
|
||||
nonLangdefaultCode
|
||||
);
|
||||
const olderTransformation = options?.transformation ? { [lang]: options?.transformation } : {};
|
||||
const finalState = _.merge({}, defaultValue, olderTransformation, options?.transformations);
|
||||
|
||||
setState(finalState);
|
||||
}
|
||||
|
|
@ -206,8 +210,6 @@ export const Transformation = ({ changeOption, options, darkMode, queryId, rende
|
|||
activeKey={lang}
|
||||
onSelect={(value) => {
|
||||
setLang(value);
|
||||
changeOption('transformationLanguage', value);
|
||||
changeOption('transformation', state[value]);
|
||||
}}
|
||||
defaultActiveKey="javascript"
|
||||
>
|
||||
|
|
@ -250,7 +252,7 @@ export const Transformation = ({ changeOption, options, darkMode, queryId, rende
|
|||
height={400}
|
||||
className="query-hinter"
|
||||
onChange={(value) => {
|
||||
changeOption('transformation', value);
|
||||
changeOption('transformations', { ...state, [lang]: value });
|
||||
}}
|
||||
renderCopilot={renderCopilot}
|
||||
componentName={`transformation`}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export default ({
|
|||
return (
|
||||
<>
|
||||
<div className="row-container query-manager-border-color" key={index}>
|
||||
<div className="fields-container mb-1">
|
||||
<div className="fields-container mb-1 restapi-key-value">
|
||||
<div className="field col-4 rounded-start rest-api-codehinter-key-field">
|
||||
<CodeHinter
|
||||
type="basic"
|
||||
|
|
@ -52,7 +52,7 @@ export default ({
|
|||
/>
|
||||
</div>
|
||||
<button
|
||||
className={`d-flex justify-content-center align-items-center delete-field-option bg-transparent border-0 rounded-0 border-top border-bottom border-end rounded-end ${
|
||||
className={`d-flex justify-content-center align-items-center delete-field-option bg-transparent border-0 rounded-0 border-top border-bottom border-end rounded-end qm-delete-btn ${
|
||||
darkMode ? 'delete-field-option-dark' : ''
|
||||
}`}
|
||||
role="button"
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ const DropDownSelect = ({
|
|||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className={`col-auto ${buttonClasses}`} id={popoverBtnId.current}>
|
||||
<div className={`col-auto ${buttonClasses} h-100`} id={popoverBtnId.current}>
|
||||
<ButtonSolid
|
||||
size="sm"
|
||||
variant="tertiary"
|
||||
|
|
@ -322,6 +322,8 @@ const DropDownSelect = ({
|
|||
},
|
||||
'gap-0',
|
||||
'w-100',
|
||||
'h-100',
|
||||
'align-items-start',
|
||||
'rounded-0',
|
||||
'position-relative',
|
||||
'font-weight-normal',
|
||||
|
|
|
|||
|
|
@ -645,10 +645,9 @@ const JoinOn = ({
|
|||
</div>
|
||||
{index > 0 && (
|
||||
<ButtonSolid
|
||||
customStyles={{ height: '30px' }}
|
||||
size="sm"
|
||||
variant="ghostBlack"
|
||||
className="px-1 rounded-0 border border-start-0 rounded-end"
|
||||
className="px-1 rounded-0 border border-start-0 rounded-en qm-delete-btn"
|
||||
onClick={onRemove}
|
||||
>
|
||||
<Trash fill="var(--slate9)" style={{ height: '16px' }} />
|
||||
|
|
|
|||
|
|
@ -340,10 +340,7 @@ const JsonBfieldsForSelect = ({ selectedJsonbColumns, handleJSonChange, table })
|
|||
<ButtonSolid
|
||||
size="sm"
|
||||
variant="ghostBlack"
|
||||
className="px-1 rounded-0 border rounded-end"
|
||||
customStyles={{
|
||||
height: '30px',
|
||||
}}
|
||||
className="px-1 rounded-0 border rounded-end qm-delete-btn"
|
||||
onClick={() => handleRemove(colDetails.id, colDetails.name, colDetails.table)}
|
||||
>
|
||||
<Trash fill="var(--slate9)" style={{ height: '16px' }} />
|
||||
|
|
|
|||
|
|
@ -164,10 +164,7 @@ export default function JoinSort({ darkMode }) {
|
|||
<ButtonSolid
|
||||
size="sm"
|
||||
variant="ghostBlack"
|
||||
className="px-1 rounded-0 border rounded-end"
|
||||
customStyles={{
|
||||
height: '30px',
|
||||
}}
|
||||
className="px-1 rounded-0 border rounded-end qm-delete-btn"
|
||||
onClick={() => setJoinOrderByOptions(joinOrderByOptions.filter((opt, idx) => idx !== i))}
|
||||
>
|
||||
<Trash fill="var(--slate9)" style={{ height: '16px' }} />
|
||||
|
|
|
|||
|
|
@ -535,12 +535,11 @@ const RenderFilterSection = ({ darkMode }) => {
|
|||
|
||||
<ButtonSolid
|
||||
customStyles={{
|
||||
height: '30px',
|
||||
maxWidth: '30px',
|
||||
}}
|
||||
size="sm"
|
||||
variant="ghostBlack"
|
||||
className="px-1 rounded-0 border rounded-end col-2"
|
||||
className="px-1 rounded-0 border rounded-end col-2 qm-delete-btn"
|
||||
onClick={() => removeFilterConditionEntry(index)}
|
||||
>
|
||||
<Trash fill="var(--slate9)" style={{ height: '16px' }} />
|
||||
|
|
|
|||
|
|
@ -54,10 +54,7 @@ const RenderColumnUI = ({
|
|||
<ButtonSolid
|
||||
size="sm"
|
||||
variant="ghostBlack"
|
||||
className="px-1 rounded-0 border rounded-end"
|
||||
customStyles={{
|
||||
height: '30px',
|
||||
}}
|
||||
className="px-1 rounded-0 border rounded-end qm-delete-btn"
|
||||
onClick={() => removeColumnOptionsPair(id)}
|
||||
>
|
||||
<Trash fill="var(--slate9)" style={{ height: '16px' }} />
|
||||
|
|
|
|||
|
|
@ -117,10 +117,7 @@ const RenderFilterSectionUI = ({
|
|||
<ButtonSolid
|
||||
size="sm"
|
||||
variant="ghostBlack"
|
||||
className="px-1 rounded-0 border rounded-end"
|
||||
customStyles={{
|
||||
height: '30px',
|
||||
}}
|
||||
className="px-1 rounded-0 border rounded-end qm-delete-btn"
|
||||
onClick={() => removeFilterConditionPair(id)}
|
||||
>
|
||||
<Trash fill="var(--slate9)" style={{ height: '16px' }} />
|
||||
|
|
|
|||
|
|
@ -86,10 +86,7 @@ const RenderSortUI = ({
|
|||
<ButtonSolid
|
||||
size="sm"
|
||||
variant="ghostBlack"
|
||||
className="px-1 rounded-0 border rounded-end"
|
||||
customStyles={{
|
||||
height: '30px',
|
||||
}}
|
||||
className="px-1 rounded-0 border rounded-end qm-delete-btn"
|
||||
onClick={() => removeSortConditionPair(id)}
|
||||
>
|
||||
<Trash fill="var(--slate9)" style={{ height: '16px' }} />
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@ export const QueryPanel = ({ darkMode }) => {
|
|||
id="query-manager"
|
||||
style={{
|
||||
height: `calc(100% - ${isExpanded ? height : 100}%)`,
|
||||
maxHeight: '93.5%',
|
||||
cursor: isDraggingQueryPane || isTopOfQueryPanel ? 'row-resize' : 'default',
|
||||
...(!isExpanded && {
|
||||
border: 'none',
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ export function Select({ componentMeta, darkMode, ...restProps }) {
|
|||
</div>
|
||||
<div className="field mb-2" data-cy={`input-and-label-column-name`}>
|
||||
<CodeHinter
|
||||
initialValue={isMultiSelect ? `{{${markedAsDefault?.includes(item.value)}}}` : item?.default?.value}
|
||||
initialValue={isMultiSelect ? `{{${markedAsDefault?.includes(item?.value)}}}` : item?.default?.value}
|
||||
theme={darkMode ? 'monokai' : 'default'}
|
||||
mode="javascript"
|
||||
lineNumbers={false}
|
||||
|
|
@ -372,7 +372,7 @@ export function Select({ componentMeta, darkMode, ...restProps }) {
|
|||
<div className="w-100" {...droppableProps} ref={innerRef}>
|
||||
{options?.map((item, index) => {
|
||||
return (
|
||||
<Draggable key={item.value} draggableId={item.value} index={index}>
|
||||
<Draggable key={item?.value} draggableId={item?.value} index={index}>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
key={index}
|
||||
|
|
@ -386,8 +386,13 @@ export function Select({ componentMeta, darkMode, ...restProps }) {
|
|||
placement="left"
|
||||
rootClose
|
||||
overlay={_renderOverlay(item, index)}
|
||||
onToggle={(isOpen) => {
|
||||
if (!isOpen) {
|
||||
document.activeElement?.blur(); // Manually trigger blur when popover closes
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div key={item.value}>
|
||||
<div key={item?.value}>
|
||||
<ListGroup.Item
|
||||
style={{ marginBottom: '8px', backgroundColor: 'var(--slate3)' }}
|
||||
onMouseEnter={() => setHoveredOptionIndex(index)}
|
||||
|
|
@ -399,7 +404,7 @@ export function Select({ componentMeta, darkMode, ...restProps }) {
|
|||
<SortableList.DragHandle show />
|
||||
</div>
|
||||
<div className="col text-truncate cursor-pointer" style={{ padding: '0px' }}>
|
||||
{getResolvedValue(item.label)}
|
||||
{getResolvedValue(item?.label)}
|
||||
</div>
|
||||
<div className="col-auto">
|
||||
{index === hoveredOptionIndex && (
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ class TableComponent extends React.Component {
|
|||
style={{
|
||||
width: '280px',
|
||||
maxHeight: resolveReferences(column.isEditable) ? '100vh' : 'inherit',
|
||||
overflowY: 'auto',
|
||||
// overflowY: 'auto',
|
||||
zIndex: '9999',
|
||||
}}
|
||||
>
|
||||
|
|
@ -327,7 +327,12 @@ class TableComponent extends React.Component {
|
|||
placement="left"
|
||||
rootClose={this.state.actionPopOverRootClose}
|
||||
overlay={this.actionPopOver(action, index)}
|
||||
onToggle={(showing) => this.setState({ showPopOver: showing })}
|
||||
onToggle={(showing) => {
|
||||
if (!showing) {
|
||||
document.activeElement?.blur(); // Manually trigger blur when popover closes
|
||||
}
|
||||
this.setState({ showPopOver: showing });
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<List>
|
||||
|
|
@ -649,6 +654,7 @@ class TableComponent extends React.Component {
|
|||
if (show) {
|
||||
this.handleToggleColumnPopover(index);
|
||||
} else {
|
||||
document.activeElement?.blur(); // Manually trigger blur when popover closes
|
||||
this.handleToggleColumnPopover(null);
|
||||
}
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -127,6 +127,13 @@ export const buttonGroupConfig = {
|
|||
exposedVariables: {
|
||||
selected: [1],
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setSelected',
|
||||
displayName: 'Select option',
|
||||
params: [{ handle: 'selected', displayName: 'Value' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const listviewConfig = {
|
|||
top: 15,
|
||||
left: 3,
|
||||
height: 100,
|
||||
width: 7,
|
||||
},
|
||||
properties: ['source'],
|
||||
accessorKey: 'imageURL',
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const tabsConfig = {
|
|||
top: 60,
|
||||
left: 17,
|
||||
height: 100,
|
||||
width: 7,
|
||||
},
|
||||
tab: 0,
|
||||
properties: ['source'],
|
||||
|
|
|
|||
|
|
@ -507,7 +507,7 @@ export const createComponentsSlice = (set, get) => ({
|
|||
|
||||
const resolvedMandatory = getResolvedValue(mandatory, customResolveObjects) || false;
|
||||
|
||||
if (resolvedMandatory == true && !widgetValue) {
|
||||
if (resolvedMandatory == true && !widgetValue && widgetValue !== 0) {
|
||||
return {
|
||||
isValid: false,
|
||||
validationError: `Field cannot be empty`,
|
||||
|
|
|
|||
|
|
@ -690,6 +690,12 @@ export const createEventsSlice = (set, get) => ({
|
|||
return getVariable(key);
|
||||
}
|
||||
|
||||
case 'unset-all-custom-variables': {
|
||||
const { unsetAllVariables } = get();
|
||||
unsetAllVariables();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
case 'unset-custom-variable': {
|
||||
const { unsetVariable } = get();
|
||||
const key = getResolvedValue(event.key, customVariables);
|
||||
|
|
@ -746,6 +752,12 @@ export const createEventsSlice = (set, get) => ({
|
|||
return getPageVariable(key);
|
||||
}
|
||||
|
||||
case 'unset-all-page-variables': {
|
||||
const { unsetAllPageVariables } = get();
|
||||
unsetAllPageVariables();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
case 'unset-page-variable': {
|
||||
const { unsetPageVariable } = get();
|
||||
const key = getResolvedValue(event.key, customVariables);
|
||||
|
|
@ -953,6 +965,13 @@ export const createEventsSlice = (set, get) => ({
|
|||
}
|
||||
};
|
||||
|
||||
const unsetAllVariables = () => {
|
||||
const event = {
|
||||
actionId: 'unset-all-custom-variables',
|
||||
};
|
||||
return executeAction(event, mode, {});
|
||||
};
|
||||
|
||||
const unSetVariable = (key = '') => {
|
||||
if (key) {
|
||||
const event = {
|
||||
|
|
@ -1066,6 +1085,13 @@ export const createEventsSlice = (set, get) => ({
|
|||
return executeAction(event, mode, {});
|
||||
};
|
||||
|
||||
const unsetAllPageVariables = () => {
|
||||
const event = {
|
||||
actionId: 'unset-all-page-variables',
|
||||
};
|
||||
return executeAction(event, mode, {});
|
||||
};
|
||||
|
||||
const unsetPageVariable = (key = '') => {
|
||||
const event = {
|
||||
actionId: 'unset-page-variable',
|
||||
|
|
@ -1133,6 +1159,7 @@ export const createEventsSlice = (set, get) => ({
|
|||
runQuery,
|
||||
setVariable,
|
||||
getVariable,
|
||||
unsetAllVariables,
|
||||
unSetVariable,
|
||||
showAlert,
|
||||
logout,
|
||||
|
|
@ -1144,6 +1171,7 @@ export const createEventsSlice = (set, get) => ({
|
|||
generateFile,
|
||||
setPageVariable,
|
||||
getPageVariable,
|
||||
unsetAllPageVariables,
|
||||
unsetPageVariable,
|
||||
switchPage,
|
||||
logInfo,
|
||||
|
|
|
|||
|
|
@ -140,6 +140,21 @@ export const createResolvedSlice = (set, get) => ({
|
|||
get().updateDependencyValues(`variables.${key}`);
|
||||
},
|
||||
|
||||
unsetAllVariables: (moduleId = 'canvas') => {
|
||||
const variables = get().resolvedStore.modules[moduleId].exposedValues.variables;
|
||||
set(
|
||||
(state) => {
|
||||
state.resolvedStore.modules[moduleId].exposedValues.variables = {};
|
||||
},
|
||||
false,
|
||||
'unsetAllVariables'
|
||||
);
|
||||
Object.keys(variables).forEach((key) => {
|
||||
get().removeNode(`variables.${key}`);
|
||||
get().updateDependencyValues(`variables.${key}`);
|
||||
});
|
||||
},
|
||||
|
||||
// page.variables
|
||||
setPageVariable: (key, value, moduleId = 'canvas') => {
|
||||
set(
|
||||
|
|
@ -167,6 +182,21 @@ export const createResolvedSlice = (set, get) => ({
|
|||
get().updateDependencyValues(`page.variables.${key}`);
|
||||
},
|
||||
|
||||
unsetAllPageVariables: (moduleId = 'canvas') => {
|
||||
const pageVariables = get().resolvedStore.modules[moduleId].exposedValues.page.variables;
|
||||
set(
|
||||
(state) => {
|
||||
state.resolvedStore.modules[moduleId].exposedValues.page.variables = {};
|
||||
},
|
||||
false,
|
||||
'unsetAllPageVariables'
|
||||
);
|
||||
Object.keys(pageVariables).forEach((key) => {
|
||||
get().removeNode(`page.variables.${key}`);
|
||||
get().updateDependencyValues(`page.variables.${key}`);
|
||||
});
|
||||
},
|
||||
|
||||
setResolvedQuery: (queryId, details, moduleId = 'canvas') => {
|
||||
set(
|
||||
(state) => {
|
||||
|
|
|
|||
|
|
@ -473,6 +473,7 @@ export function createReferencesLookup(currentState, forQueryParams = false, ini
|
|||
const actions = [
|
||||
'runQuery',
|
||||
'setVariable',
|
||||
'unsetAllVariables',
|
||||
'unSetVariable',
|
||||
'showAlert',
|
||||
'logout',
|
||||
|
|
@ -483,6 +484,7 @@ export function createReferencesLookup(currentState, forQueryParams = false, ini
|
|||
'goToApp',
|
||||
'generateFile',
|
||||
'setPageVariable',
|
||||
'unsetAllPageVariables',
|
||||
'unsetPageVariable',
|
||||
'switchPage',
|
||||
'logInfo',
|
||||
|
|
|
|||
|
|
@ -78,6 +78,10 @@ export const ActionTypes = [
|
|||
{ name: 'value', type: 'code', default: '' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Unset all variables',
|
||||
id: 'unset-all-custom-variables',
|
||||
},
|
||||
{
|
||||
name: 'Unset variable',
|
||||
id: 'unset-custom-variable',
|
||||
|
|
@ -96,6 +100,10 @@ export const ActionTypes = [
|
|||
{ name: 'value', type: 'code', default: '' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Unset all page variables',
|
||||
id: 'unset-all-page-variables',
|
||||
},
|
||||
{
|
||||
name: 'Unset page variable',
|
||||
id: 'unset-page-variable',
|
||||
|
|
@ -104,6 +112,7 @@ export const ActionTypes = [
|
|||
{ name: 'value', type: 'code', default: '' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'Control component',
|
||||
id: 'control-component',
|
||||
|
|
|
|||
|
|
@ -66,6 +66,34 @@ export const ButtonGroup = function Button({
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [multiSelection]);
|
||||
|
||||
const setSelected = (selected) => {
|
||||
if (multiSelection) {
|
||||
if (Array.isArray(selected)) {
|
||||
const filteredItems = selected.filter((item) => values.includes(item));
|
||||
setDefaultActive(filteredItems);
|
||||
setExposedVariable('selected', filteredItems.join(','));
|
||||
} else if ((typeof selected === 'string' || typeof selected === 'number') && values.includes(selected)) {
|
||||
setDefaultActive([selected]);
|
||||
setExposedVariable('selected', String(selected));
|
||||
}
|
||||
} else {
|
||||
if (Array.isArray(selected)) {
|
||||
const filteredItems = selected.filter((item) => values.includes(item));
|
||||
if (filteredItems?.length >= 1) {
|
||||
setDefaultActive([filteredItems[0]]);
|
||||
setExposedVariable('selected', String(filteredItems[0]));
|
||||
}
|
||||
} else if ((typeof selected === 'string' || typeof selected === 'number') && values.includes(selected)) {
|
||||
setDefaultActive([selected]);
|
||||
setExposedVariable('selected', String(selected));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setExposedVariable('setSelected', setSelected);
|
||||
}, [multiSelection, values]);
|
||||
|
||||
const buttonClick = (index) => {
|
||||
if (defaultActive?.includes(values[index]) && multiSelection) {
|
||||
const copyDefaultActive = [...defaultActive];
|
||||
|
|
|
|||
|
|
@ -236,8 +236,6 @@ export const TextInput = function TextInput({
|
|||
value: properties.value,
|
||||
isMandatory: isMandatory,
|
||||
isLoading: loading,
|
||||
isVisible: visibility,
|
||||
isDisabled: disable,
|
||||
};
|
||||
|
||||
setExposedVariables(exposedVariables);
|
||||
|
|
@ -245,6 +243,17 @@ export const TextInput = function TextInput({
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Fix for "visibility is not defined" in production because there's a naming conflict in the code.
|
||||
// The issue is in the exposedVariables object where we had both a function named visibility and a property isVisible that depends on the state variable with the same name.
|
||||
const exposedVariables = {
|
||||
isVisible: visibility,
|
||||
isDisabled: disable,
|
||||
};
|
||||
setExposedVariables(exposedVariables);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const setInputValue = (value) => {
|
||||
setValue(value);
|
||||
setExposedVariable('value', value);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const listviewConfig = {
|
|||
top: 15,
|
||||
left: 3,
|
||||
height: 100,
|
||||
width: 7,
|
||||
},
|
||||
properties: ['source'],
|
||||
accessorKey: 'imageURL',
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const tabsConfig = {
|
|||
top: 60,
|
||||
left: 17,
|
||||
height: 100,
|
||||
width: 7,
|
||||
},
|
||||
tab: 0,
|
||||
properties: ['source'],
|
||||
|
|
|
|||
|
|
@ -572,6 +572,7 @@ const DynamicForm = ({
|
|||
'd-flex': isHorizontalLayout,
|
||||
'dynamic-form-row': isHorizontalLayout,
|
||||
})}
|
||||
data-cy={`${key.replace(/_/g, '-')}-section`}
|
||||
key={key}
|
||||
>
|
||||
{!isSpecificComponent && (
|
||||
|
|
@ -628,6 +629,7 @@ const DynamicForm = ({
|
|||
{...getElementProps(obj[key])}
|
||||
{...computedProps[propertyKey]}
|
||||
data-cy={`${String(label).toLocaleLowerCase().replace(/\s+/g, '-')}-text-field`}
|
||||
dataCy={obj[key].key.replace(/_/g, '-')}
|
||||
//to be removed after whole ui is same
|
||||
isHorizontalLayout={isHorizontalLayout}
|
||||
/>
|
||||
|
|
@ -669,7 +671,7 @@ const DynamicForm = ({
|
|||
</label>
|
||||
)}
|
||||
|
||||
<div data-cy={'query-select-dropdown'} className={cx({ 'flex-grow-1': isHorizontalLayout })}>
|
||||
<div data-cy={`${String(flipComponentDropdown.label).toLocaleLowerCase().replace(/\s+/g, '-')}-select-dropdown`} className={cx({ 'flex-grow-1': isHorizontalLayout })}>
|
||||
<Select
|
||||
{...getElementProps(flipComponentDropdown)}
|
||||
styles={computeSelectStyles ? computeSelectStyles('100%') : {}}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export default function EncryptedFieldWrapper({
|
|||
return (
|
||||
<>
|
||||
<div className="d-flex align-items-center mt-3">
|
||||
<label className="form-label">{label}</label>
|
||||
<label className="form-label" data-cy={`label-${String(label).toLowerCase().replace(/\s+/g, '-')}`}>{label}</label>
|
||||
<div className="mx-1 col">
|
||||
<ButtonSolid
|
||||
className="datasource-edit-btn mb-2"
|
||||
|
|
@ -38,6 +38,7 @@ export default function EncryptedFieldWrapper({
|
|||
target="_blank"
|
||||
rel="noreferrer"
|
||||
onClick={() => handleEncryptedFieldsToggle(name)}
|
||||
data-cy={`button-${(disabled ? 'Edit' : 'Cancel').toLowerCase().replace(/\s+/g, '-')}`}
|
||||
>
|
||||
{disabled ? 'Edit' : 'Cancel'}
|
||||
</ButtonSolid>
|
||||
|
|
|
|||
|
|
@ -242,18 +242,20 @@ export function resolveReferences(
|
|||
} else {
|
||||
const dynamicVariables = getDynamicVariables(object);
|
||||
|
||||
for (const dynamicVariable of dynamicVariables) {
|
||||
const value = resolveString(
|
||||
dynamicVariable,
|
||||
state,
|
||||
customObjects,
|
||||
reservedKeyword,
|
||||
withError,
|
||||
forPreviewBox
|
||||
);
|
||||
if (dynamicVariables) {
|
||||
for (const dynamicVariable of dynamicVariables) {
|
||||
const value = resolveString(
|
||||
dynamicVariable,
|
||||
state,
|
||||
customObjects,
|
||||
reservedKeyword,
|
||||
withError,
|
||||
forPreviewBox
|
||||
);
|
||||
|
||||
if (typeof value !== 'function') {
|
||||
object = object.replace(dynamicVariable, value);
|
||||
if (typeof value !== 'function') {
|
||||
object = object.replace(dynamicVariable, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -701,6 +701,7 @@
|
|||
.sidebar-h-100-popover {
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
overflow-y:scroll !important;
|
||||
margin-top: 0px;
|
||||
border-radius: 0px !important;
|
||||
|
||||
|
|
|
|||
|
|
@ -1856,8 +1856,9 @@ $border-radius: 4px;
|
|||
.tjdb-codhinter-wrapper{
|
||||
.codehinter-input{
|
||||
.cm-editor{
|
||||
height: 30px !important;
|
||||
// height: 30px !important;
|
||||
min-height: 30px !important;
|
||||
max-height:100px !important;
|
||||
border-radius: 0 !important;
|
||||
border-right: 0 ;
|
||||
}
|
||||
|
|
@ -1865,8 +1866,9 @@ $border-radius: 4px;
|
|||
}
|
||||
.tjdb-limit-offset-codehinter{
|
||||
.cm-editor{
|
||||
height: 30px !important;
|
||||
// height: 30px !important;
|
||||
min-height: 30px !important;
|
||||
max-height:100px !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1904,4 +1906,19 @@ $border-radius: 4px;
|
|||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.qm-delete-btn {
|
||||
min-height: 30px;
|
||||
height: 100% !important;
|
||||
align-items: flex-start !important;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.restapi-key-value {
|
||||
.code-hinter-wrapper, .code-editor-basic-wrapper, .codehinter-container, .cm-codehinter, .code-editor-query-panel{
|
||||
height:100%;
|
||||
max-height: 100px;
|
||||
}
|
||||
}
|
||||
|
|
@ -1543,7 +1543,7 @@ button {
|
|||
.tab-content {
|
||||
overflow-y: auto;
|
||||
// TAB HEADER HEIGHT + FOOTER HEIGHT + Extra padding = 120px
|
||||
height: calc(100vh - 7.5rem);
|
||||
height: calc(100vh - 10.4rem);
|
||||
// Hide scrollbar
|
||||
-ms-overflow-style: none;
|
||||
/* IE and Edge */
|
||||
|
|
@ -15823,6 +15823,7 @@ tbody {
|
|||
}
|
||||
|
||||
.rest-api-options-codehinter {
|
||||
height: 100%;
|
||||
.cm-content>.cm-line {
|
||||
// max-width: 357px !important;
|
||||
}
|
||||
|
|
@ -18576,6 +18577,12 @@ section.ai-message-prompt-input-wrapper {
|
|||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.cm-tooltip {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
|
||||
.workspace-constant-value {
|
||||
position: relative;
|
||||
|
||||
|
|
@ -18624,3 +18631,10 @@ section.ai-message-prompt-input-wrapper {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.single-line-codehinter-input {
|
||||
.cm-editor {
|
||||
max-height: 100px !important;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import cx from 'classnames';
|
||||
import React, { useEffect } from "react";
|
||||
import cx from "classnames";
|
||||
|
||||
const AccordionItem = ({ open = true, index, title, children }) => {
|
||||
const [show, setShow] = React.useState(open);
|
||||
|
|
@ -13,7 +13,7 @@ const AccordionItem = ({ open = true, index, title, children }) => {
|
|||
function isNotEmpty(item) {
|
||||
if (Array.isArray(item)) {
|
||||
return item.some(isNotEmpty); // Check if any element in the array is not empty
|
||||
} else if (typeof item === 'object') {
|
||||
} else if (typeof item === "object") {
|
||||
return Object.keys(item).some((key) => isNotEmpty(item[key])); // Check if any key in the object is not empty
|
||||
} else {
|
||||
return Boolean(item); // Check if the item itself is truthy
|
||||
|
|
@ -23,7 +23,7 @@ const AccordionItem = ({ open = true, index, title, children }) => {
|
|||
function removeEmptyItems(input) {
|
||||
if (Array.isArray(input)) {
|
||||
return input.filter(isNotEmpty);
|
||||
} else if (typeof input === 'object') {
|
||||
} else if (typeof input === "object") {
|
||||
return isNotEmpty(input) ? input : null;
|
||||
} else {
|
||||
return input;
|
||||
|
|
@ -31,22 +31,38 @@ const AccordionItem = ({ open = true, index, title, children }) => {
|
|||
}
|
||||
return (
|
||||
<div className="accordion-item">
|
||||
<h2 className="accordion-header" id={`heading-${index}`} data-cy={`widget-accordion-${title.toLowerCase()}`}>
|
||||
<div className={cx('accordion-button inspector')}>
|
||||
<span className="text-capitalize accordion-title-text">{title}</span>
|
||||
<h2
|
||||
className="accordion-header"
|
||||
id={`heading-${index}`}
|
||||
data-cy={`widget-accordion-${String(title)
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, "-")}`}
|
||||
>
|
||||
<div className={cx("accordion-button inspector")}>
|
||||
<span
|
||||
className="text-capitalize accordion-title-text"
|
||||
data-cy={`label-${String(title)
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, "-")}`}
|
||||
>
|
||||
{title}
|
||||
</span>
|
||||
<div
|
||||
data-cy={`${String(title)
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, "-")}-collapse-button`}
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target={`collapse-${index}`}
|
||||
aria-expanded="false"
|
||||
className={cx('accordion-item-trigger', { collapsed: !show })}
|
||||
className={cx("accordion-item-trigger", { collapsed: !show })}
|
||||
onClick={() => setShow((prev) => !prev)}
|
||||
></div>
|
||||
</div>
|
||||
</h2>
|
||||
<div
|
||||
id={`collapse-${index}`}
|
||||
className={cx('accordion-collapse collapse', { show })}
|
||||
className={cx("accordion-collapse collapse", { show })}
|
||||
data-bs-parent="#accordion-example"
|
||||
>
|
||||
<div className="accordion-body">{newChildren}</div>
|
||||
|
|
|
|||
|
|
@ -14,13 +14,15 @@ export default ({
|
|||
workspaceConstants,
|
||||
isDisabled,
|
||||
width,
|
||||
dataCy,
|
||||
}) => {
|
||||
const darkMode = localStorage.getItem('darkMode') === 'true';
|
||||
|
||||
return (
|
||||
<div className="table-content-wrapper">
|
||||
{options.length === 0 && (
|
||||
<div className="empty-key-value">
|
||||
<div className="empty-key-value"
|
||||
data-cy="label-empty-key-value">
|
||||
<InfoIcon style={{ width: '16px', marginRight: '5px' }} />
|
||||
<span>There are no key value pairs added</span>
|
||||
</div>
|
||||
|
|
@ -29,6 +31,7 @@ export default ({
|
|||
{options.map((option, index) => (
|
||||
<div className="d-flex align-items-top row-container query-manager-border-color" key={index}>
|
||||
<Input
|
||||
data-cy={`${dataCy}-key-input-field-${index}`}
|
||||
type="text"
|
||||
className="input-control"
|
||||
onChange={(e) => keyValuePairValueChanged(e.target.value, 0, index)}
|
||||
|
|
@ -47,6 +50,7 @@ export default ({
|
|||
/>
|
||||
|
||||
<Input
|
||||
data-cy={`${dataCy}-value-input-field-${index}`}
|
||||
type="text"
|
||||
value={option[1]}
|
||||
placeholder="Value"
|
||||
|
|
@ -66,6 +70,7 @@ export default ({
|
|||
/>
|
||||
|
||||
<button
|
||||
data-cy={`${dataCy}-delete-button-${index}`}
|
||||
className={`d-flex justify-content-center align-items-center delete-field-option bg-transparent border-0 rounded-0 border-top border-bottom border-end rounded-end ${
|
||||
darkMode ? 'delete-field-option-dark' : ''
|
||||
}`}
|
||||
|
|
@ -81,6 +86,7 @@ export default ({
|
|||
|
||||
<div className="d-flex mb-2" style={{ height: '16px' }}>
|
||||
<ButtonSolid
|
||||
data-cy={`${dataCy}-add-more-button`}
|
||||
variant="ghostBlue"
|
||||
size="sm"
|
||||
onClick={() => addNewKeyValuePair(options)}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,22 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import QueryEditor from './QueryEditor';
|
||||
import SourceEditor from './SourceEditor';
|
||||
import { deepClone } from '@/_helpers/utilities/utils.helpers';
|
||||
import React from "react";
|
||||
import _ from "lodash";
|
||||
import QueryEditor from "./QueryEditor";
|
||||
import SourceEditor from "./SourceEditor";
|
||||
import { deepClone } from "@/_helpers/utilities/utils.helpers";
|
||||
|
||||
export default ({
|
||||
getter,
|
||||
options = [['', '']],
|
||||
options = [["", ""]],
|
||||
optionchanged,
|
||||
isRenderedAsQueryEditor,
|
||||
workspaceConstants,
|
||||
isDisabled,
|
||||
buttonText,
|
||||
width,
|
||||
dataCy,
|
||||
}) => {
|
||||
function addNewKeyValuePair(options) {
|
||||
const newPairs = [...options, ['', '']];
|
||||
const newPairs = [...options, ["", ""]];
|
||||
optionchanged(getter, newPairs);
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +30,9 @@ export default ({
|
|||
if (!isRenderedAsQueryEditor) {
|
||||
const newOptions = deepClone(options);
|
||||
newOptions[index][keyIndex] = value;
|
||||
options.length - 1 === index ? addNewKeyValuePair(newOptions) : optionchanged(getter, newOptions);
|
||||
options.length - 1 === index
|
||||
? addNewKeyValuePair(newOptions)
|
||||
: optionchanged(getter, newOptions);
|
||||
} else {
|
||||
let newOptions = deepClone(options);
|
||||
newOptions[index][keyIndex] = value;
|
||||
|
|
@ -44,11 +47,16 @@ export default ({
|
|||
keyValuePairValueChanged,
|
||||
isDisabled,
|
||||
buttonText,
|
||||
dataCy,
|
||||
};
|
||||
|
||||
return isRenderedAsQueryEditor ? (
|
||||
<QueryEditor {...commonProps} />
|
||||
) : (
|
||||
<SourceEditor {...commonProps} workspaceConstants={workspaceConstants} width={width} />
|
||||
<SourceEditor
|
||||
{...commonProps}
|
||||
workspaceConstants={workspaceConstants}
|
||||
width={width}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ function Label({ label, width, labelRef, color, defaultAlignment, direction, aut
|
|||
justifyContent: direction == 'right' ? 'flex-end' : 'flex-start',
|
||||
fontSize: '12px',
|
||||
height: defaultAlignment === 'top' && '20px',
|
||||
overflow: 'hidden',
|
||||
overflow: auto ? 'visible' : 'hidden',
|
||||
}}
|
||||
>
|
||||
<p
|
||||
|
|
|
|||
|
|
@ -70,8 +70,9 @@ const Authentication = ({
|
|||
return (
|
||||
<div>
|
||||
<div className="col-md-12">
|
||||
<label className="form-label text-muted mt-3">Username</label>
|
||||
<label className="form-label text-muted mt-3" data-cy="label-username">Username</label>
|
||||
<Input
|
||||
data-cy="username-input-field"
|
||||
type="text"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('username', e.target.value)}
|
||||
|
|
@ -90,6 +91,7 @@ const Authentication = ({
|
|||
label="Password"
|
||||
>
|
||||
<Input
|
||||
data-cy="password-input-field"
|
||||
type="password"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('password', e.target.value)}
|
||||
|
|
@ -113,6 +115,7 @@ const Authentication = ({
|
|||
label="Token"
|
||||
>
|
||||
<Input
|
||||
data-cy="token-input-field"
|
||||
type="password"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('bearer_token', e.target.value)}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ const CommonOAuthFields = ({ clientConfig, tokenConfig, authConfig, workspaceCon
|
|||
return (
|
||||
<>
|
||||
<div className="col-md-12">
|
||||
<label className="form-label mt-3">Access token URL</label>
|
||||
<label className="form-label mt-3" data-cy="label-access-token-url">Access token URL</label>
|
||||
<Input
|
||||
data-cy="access-token-url-input-field"
|
||||
type="text"
|
||||
placeholder="https://api.example.com/oauth/token"
|
||||
className="form-control"
|
||||
|
|
@ -26,7 +27,7 @@ const CommonOAuthFields = ({ clientConfig, tokenConfig, authConfig, workspaceCon
|
|||
</div>
|
||||
<div className="row mt-3">
|
||||
<div className="col">
|
||||
<label className="form-label pt-2">Access token URL custom headers</label>
|
||||
<label className="form-label pt-2" data-cy="label-access-token-url-custom-headers">Access token URL custom headers</label>
|
||||
</div>
|
||||
</div>
|
||||
<Headers
|
||||
|
|
@ -34,10 +35,12 @@ const CommonOAuthFields = ({ clientConfig, tokenConfig, authConfig, workspaceCon
|
|||
options={access_token_custom_headers}
|
||||
optionchanged={optionchanged}
|
||||
workspaceConstants={workspaceConstants}
|
||||
dataCy={'access-token-url-custom-headers'}
|
||||
/>
|
||||
<div className="col-md-12">
|
||||
<label className="form-label mt-3">Client ID</label>
|
||||
<label className="form-label mt-3" data-cy="label-client-id">Client ID</label>
|
||||
<Input
|
||||
data-cy="client-id-input-field"
|
||||
type="text"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('client_id', e.target.value)}
|
||||
|
|
@ -56,6 +59,7 @@ const CommonOAuthFields = ({ clientConfig, tokenConfig, authConfig, workspaceCon
|
|||
label="Client secret"
|
||||
>
|
||||
<Input
|
||||
data-cy="client-secret-input-field"
|
||||
type="password"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('client_secret', e.target.value)}
|
||||
|
|
@ -65,8 +69,9 @@ const CommonOAuthFields = ({ clientConfig, tokenConfig, authConfig, workspaceCon
|
|||
</EncryptedFieldWrapper>
|
||||
</div>
|
||||
<div className="col-md-12">
|
||||
<label className="form-label mt-3">Scope(s)</label>
|
||||
<label className="form-label mt-3" data-cy="label-scope">Scope(s)</label>
|
||||
<Input
|
||||
data-cy="scope-input-field"
|
||||
type="text"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('scopes', e.target.value)}
|
||||
|
|
@ -85,8 +90,9 @@ const ClientCredentialsFields = ({ authConfig, workspaceConfig, handlers }) => {
|
|||
|
||||
return (
|
||||
<div className="col-md-12">
|
||||
<label className="form-label mt-3">Audience</label>
|
||||
<label className="form-label mt-3" data-cy="label-audience">Audience</label>
|
||||
<Input
|
||||
data-cy="audience-input-field"
|
||||
type="text"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('audience', e.target.value)}
|
||||
|
|
@ -107,7 +113,7 @@ const AuthorizationCode = ({ authConfig, clientConfig, tokenConfig, workspaceCon
|
|||
return (
|
||||
<>
|
||||
<div className="col-md-12">
|
||||
<label className="form-label mt-3">Add access token to</label>
|
||||
<label className="form-label mt-3" data-cy="label-add-access-token-to">Add access token to</label>
|
||||
<Select
|
||||
options={[{ name: 'Request header', value: 'header' }]}
|
||||
value={add_token_to}
|
||||
|
|
@ -118,8 +124,9 @@ const AuthorizationCode = ({ authConfig, clientConfig, tokenConfig, workspaceCon
|
|||
</div>
|
||||
{add_token_to === 'header' && (
|
||||
<div className="col-md-12">
|
||||
<label className="form-label mt-3">Header prefix</label>
|
||||
<label className="form-label mt-3" data-cy="label-header-prefix">Header prefix</label>
|
||||
<Input
|
||||
data-cy="header-prefix-input-field"
|
||||
type="text"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('header_prefix', e.target.value)}
|
||||
|
|
@ -129,8 +136,9 @@ const AuthorizationCode = ({ authConfig, clientConfig, tokenConfig, workspaceCon
|
|||
</div>
|
||||
)}
|
||||
<div className="col-md-12">
|
||||
<label className="form-label mt-3">Authorization URL</label>
|
||||
<label className="form-label mt-3" data-cy="label-authorization-url">Authorization URL</label>
|
||||
<Input
|
||||
data-cy="authorization-url-input-field"
|
||||
type="text"
|
||||
placeholder="https://api.example.com/oauth/authorize"
|
||||
className="form-control"
|
||||
|
|
@ -141,7 +149,7 @@ const AuthorizationCode = ({ authConfig, clientConfig, tokenConfig, workspaceCon
|
|||
</div>
|
||||
<div className="row mt-3">
|
||||
<div className="col">
|
||||
<label className="form-label pt-2">Custom authentication parameters</label>
|
||||
<label className="form-label pt-2" data-cy="label-custom-authentication-parameters">Custom authentication parameters</label>
|
||||
</div>
|
||||
</div>
|
||||
<Headers
|
||||
|
|
@ -149,9 +157,10 @@ const AuthorizationCode = ({ authConfig, clientConfig, tokenConfig, workspaceCon
|
|||
options={custom_auth_params}
|
||||
optionchanged={optionchanged}
|
||||
workspaceConstants={workspaceConstants}
|
||||
dataCy={'custom-authentication-parameters'}
|
||||
/>
|
||||
<div className="col-md-12">
|
||||
<label className="form-label mt-3">Client authentication</label>
|
||||
<label className="form-label mt-3" data-cy="label-client-authentication">Client authentication</label>
|
||||
<Select
|
||||
options={[
|
||||
{ name: 'Send as basic auth header', value: 'header' },
|
||||
|
|
@ -166,17 +175,18 @@ const AuthorizationCode = ({ authConfig, clientConfig, tokenConfig, workspaceCon
|
|||
<div>
|
||||
<label className="form-check form-switch my-4">
|
||||
<input
|
||||
data-cy="authentication-required-for-all-users-toggle-switch"
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
checked={multiple_auth_enabled}
|
||||
onChange={() => optionchanged('multiple_auth_enabled', !multiple_auth_enabled)}
|
||||
/>
|
||||
<span className="form-check-label">Authentication required for all users</span>
|
||||
<span className="form-check-label" data-cy="label-authentication-required-for-all-users">Authentication required for all users</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="row mt-3">
|
||||
<div className="col">
|
||||
<label className="form-label pt-2">Custom query parameters</label>
|
||||
<label className="form-label pt-2" data-cy="label-custom-query-parameters">Custom query parameters</label>
|
||||
</div>
|
||||
</div>
|
||||
<Headers
|
||||
|
|
@ -184,6 +194,7 @@ const AuthorizationCode = ({ authConfig, clientConfig, tokenConfig, workspaceCon
|
|||
options={custom_query_params}
|
||||
optionchanged={optionchanged}
|
||||
workspaceConstants={workspaceConstants}
|
||||
dataCy={'custom-query-parameters'}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
@ -195,7 +206,7 @@ const OAuthConfiguration = ({ authConfig, clientConfig, tokenConfig, workspaceCo
|
|||
return (
|
||||
<div>
|
||||
<div className="row mt-3">
|
||||
<label className="form-label">Grant type</label>
|
||||
<label className="form-label" data-cy="label-grant-type">Grant type</label>
|
||||
<Select
|
||||
options={[
|
||||
{ name: 'Authorization code', value: 'authorization_code' },
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export const SearchBox = ({ onChange, ...restProps }) => {
|
|||
onChange={handleChange}
|
||||
className="form-control animate-width-change"
|
||||
placeholder={placeholder ?? t(`globals.search`, 'Search')}
|
||||
data-cy={`search-input-filed`}
|
||||
data-cy={`search-input-field`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -911,7 +911,7 @@ class DataSourceManagerComponent extends React.Component {
|
|||
className="form-control-plaintext form-control-plaintext-sm color-slate12"
|
||||
value={decodeEntities(selectedDataSource.name)}
|
||||
style={{ width: '160px' }}
|
||||
data-cy="data-source-name-input-filed"
|
||||
data-cy="data-source-name-input-field"
|
||||
autoFocus
|
||||
autoComplete="off"
|
||||
disabled={!canUpdateDataSource(selectedDataSource.id)}
|
||||
|
|
@ -1107,6 +1107,7 @@ class DataSourceManagerComponent extends React.Component {
|
|||
<SolidIcon name="logs" fill="#3E63DD" width="20" style={{ marginRight: '8px' }} />
|
||||
<a
|
||||
className="color-primary tj-docs-link tj-text-sm"
|
||||
data-cy="link-read-documentation"
|
||||
href={
|
||||
selectedDataSource?.pluginId && selectedDataSource.pluginId.trim() !== ''
|
||||
? `https://docs.tooljet.com/docs/marketplace/plugins/marketplace-plugin-${selectedDataSource.kind}/`
|
||||
|
|
|
|||
|
|
@ -8,6 +8,40 @@ if [ -f "./.env" ]; then
|
|||
export $(grep -v '^#' ./.env | xargs -d '\n') || true
|
||||
fi
|
||||
|
||||
# Start Redis server only if REDIS_HOST is localhost or not set
|
||||
if [ -z "$REDIS_HOST" ] || [ "$REDIS_HOST" = "localhost" ]; then
|
||||
echo "Starting Redis server locally..."
|
||||
redis-server /etc/redis/redis.conf &
|
||||
elif [ -n "$REDIS_URL" ]; then
|
||||
echo "REDIS_URL connection is set: $REDIS_URL"
|
||||
else
|
||||
echo "Using external Redis at $REDIS_HOST:$REDIS_PORT."
|
||||
|
||||
# Validate external Redis connection
|
||||
if ! ./server/scripts/wait-for-it.sh "$REDIS_HOST:${REDIS_PORT:-6379}" --strict --timeout=300 -- echo "Redis is up"; then
|
||||
echo "Error: Unable to connect to Redis at $REDIS_HOST:$REDIS_PORT."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if PGRST_HOST starts with "localhost"
|
||||
if [[ "$PGRST_HOST" == localhost:* ]]; then
|
||||
echo "Starting PostgREST server locally..."
|
||||
|
||||
# Generate PostgREST configuration in a writable directory
|
||||
POSTGREST_CONFIG_PATH="/tmp/postgrest.conf"
|
||||
|
||||
echo "db-uri = \"${PGRST_DB_URI}\"" > "$POSTGREST_CONFIG_PATH"
|
||||
echo "db-pre-config = \"postgrest.pre_config\"" >> "$POSTGREST_CONFIG_PATH"
|
||||
echo "server-port = \"${PGRST_SERVER_PORT}\"" >> "$POSTGREST_CONFIG_PATH"
|
||||
|
||||
# Starting PostgREST
|
||||
echo "Starting PostgREST..."
|
||||
postgrest "$POSTGREST_CONFIG_PATH" &
|
||||
else
|
||||
echo "Using external PostgREST at $PGRST_HOST."
|
||||
fi
|
||||
|
||||
# Check WORKLOW_WORKER and skip SETUP_CMD if true
|
||||
if [ "${WORKFLOW_WORKER}" == "true" ]; then
|
||||
echo "WORKFLOW_WORKER is set to true. Running worker process."
|
||||
|
|
@ -31,19 +65,6 @@ else
|
|||
./server/scripts/wait-for-it.sh "$PG_HOST:$PG_PORT" --strict --timeout=300 -- echo "PostgreSQL is up"
|
||||
fi
|
||||
|
||||
# Note: This Redis connection check changes are only for EE repo
|
||||
|
||||
# Check Redis connection
|
||||
if [ -z "$REDIS_URL" ]; then
|
||||
if [ -z "$REDIS_HOST" ] || [ -z "$REDIS_PORT" ]; then
|
||||
echo "Waiting for Redis connection..."
|
||||
fi
|
||||
|
||||
./server/scripts/wait-for-it.sh $REDIS_HOST:${REDIS_PORT:-6379} --strict --timeout=300 -- echo "Redis is up"
|
||||
else
|
||||
echo "REDIS_URL connection is set"
|
||||
fi
|
||||
|
||||
# Run setup command if defined
|
||||
if [ -n "$SETUP_CMD" ]; then
|
||||
$SETUP_CMD
|
||||
|
|
|
|||
|
|
@ -127,6 +127,14 @@ export const buttonGroupConfig = {
|
|||
exposedVariables: {
|
||||
selected: [1],
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setSelected',
|
||||
displayName: 'Select option',
|
||||
params: [{ handle: 'selected', displayName: 'Value' }],
|
||||
},
|
||||
],
|
||||
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const listviewConfig = {
|
|||
top: 15,
|
||||
left: 3,
|
||||
height: 100,
|
||||
width: 7,
|
||||
},
|
||||
properties: ['source'],
|
||||
accessorKey: 'imageURL',
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const tabsConfig = {
|
|||
top: 60,
|
||||
left: 17,
|
||||
height: 100,
|
||||
width: 7,
|
||||
},
|
||||
tab: 0,
|
||||
properties: ['source'],
|
||||
|
|
|
|||
Loading…
Reference in a new issue