mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 17:08:34 +00:00
Merge pull request #8406 from ToolJet/merge-dev/main
Merge main to develop
This commit is contained in:
commit
3b79373f93
107 changed files with 38919 additions and 152180 deletions
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
|
|
@ -38,10 +38,10 @@ jobs:
|
|||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js 18.3.0
|
||||
- name: Use Node.js 18.18.2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: 18.18.2
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
|
|
@ -68,10 +68,10 @@ jobs:
|
|||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js 18.3.0
|
||||
- name: Use Node.js 18.18.2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: 18.18.2
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
|
|
@ -93,7 +93,7 @@ jobs:
|
|||
unit-test:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
container: node:18.3.0-buster
|
||||
container: node:18.18.2-buster
|
||||
services:
|
||||
postgres:
|
||||
image: postgres
|
||||
|
|
@ -131,7 +131,7 @@ jobs:
|
|||
e2e-test:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
container: node:18.3.0-buster
|
||||
container: node:18.18.2-buster
|
||||
services:
|
||||
postgres:
|
||||
image: postgres
|
||||
|
|
|
|||
2
.github/workflows/cypress-appbuilder.yml
vendored
2
.github/workflows/cypress-appbuilder.yml
vendored
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: 18.18.2
|
||||
|
||||
- name: Set up Docker
|
||||
uses: docker-practice/actions-setup-docker@master
|
||||
|
|
|
|||
2
.github/workflows/cypress-platform.yml
vendored
2
.github/workflows/cypress-platform.yml
vendored
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18.3.0
|
||||
node-version: 18.18.2
|
||||
|
||||
- name: Set up Docker
|
||||
uses: docker-practice/actions-setup-docker@master
|
||||
|
|
|
|||
2
.nvmrc
2
.nvmrc
|
|
@ -1 +1 @@
|
|||
v18.3.0
|
||||
v18.18.2
|
||||
2
.version
2
.version
|
|
@ -1 +1 @@
|
|||
2.26.2
|
||||
2.27.0
|
||||
|
|
|
|||
12470
cli/package-lock.json
generated
12470
cli/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -70,7 +70,7 @@ Cypress.Commands.add("apiCreateApp", (appName = "testApp") => {
|
|||
url: "http://localhost:3000/api/apps",
|
||||
headers: {
|
||||
"Tj-Workspace-Id": Cypress.env("workspaceId"),
|
||||
Cookie: `tj_auth_token=${cookie.value}`,
|
||||
Cookie: `tj_auth_token = ${cookie.value}`,
|
||||
},
|
||||
body: {
|
||||
created_at: "",
|
||||
|
|
@ -212,3 +212,27 @@ Cypress.Commands.add("userInviteApi", (userName, userEmail) => {
|
|||
});
|
||||
});
|
||||
});
|
||||
Cypress.Commands.add("addQueryApi", (queryName, query, dataQueryId) => {
|
||||
cy.getCookie("tj_auth_token").then((cookie) => {
|
||||
const headers = {
|
||||
"Tj-Workspace-Id": Cypress.env("workspaceId"),
|
||||
Cookie: `tj_auth_token=${cookie.value}`,
|
||||
};
|
||||
cy.request({
|
||||
method: "PATCH",
|
||||
url: `http://localhost:3000/api/data_queries/${dataQueryId}`,
|
||||
headers: headers,
|
||||
body: {
|
||||
name: queryName,
|
||||
options: {
|
||||
mode: "sql",
|
||||
transformationLanguage: "javascript",
|
||||
enableTransformation: false,
|
||||
query: query,
|
||||
},
|
||||
},
|
||||
}).then((patchResponse) => {
|
||||
expect(patchResponse.status).to.equal(200);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export const s3Text = {
|
|||
alertRegionIsMissing: "Region is missing",
|
||||
cypressAwsS3: "cypress-aws-s3",
|
||||
placeholderEnterAccessKey: "Enter access key",
|
||||
placeholderEnterSecretKey: "Enter secret key",
|
||||
placeholderEnterSecretKey: "**************",
|
||||
labelRegion: "Region",
|
||||
region: "N. california",
|
||||
alertInvalidUrl: "Invalid URL",
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ export const bigqueryText = {
|
|||
cypressBigQuery: "cypress-bigquery",
|
||||
errorInvalidEmailId:
|
||||
"The incoming JSON object does not contain a client_email field",
|
||||
placehlderPrivateKey: "Enter JSON private key for service account",
|
||||
placehlderPrivateKey: "**************",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export const dataSourceText = {
|
|||
allDataSources: "All data sources (41)",
|
||||
allDatabase: "Databases (17)",
|
||||
allApis: "APIs (20)",
|
||||
allCloudStorage: "Cloud Storage (4)",
|
||||
allCloudStorage: "Cloud Storages (4)",
|
||||
pluginsLabelAndCount: "Plugins (0)",
|
||||
|
||||
postgreSQL: "PostgreSQL",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export const dynamoDbText = {
|
|||
accessKey: "Access key",
|
||||
placeHolderAccessKey: "Enter access key",
|
||||
secretKey: "Secret key",
|
||||
placeholderSecretKey: "Enter secret key",
|
||||
placeholderSecretKey: "**************",
|
||||
|
||||
errorMissingRegion: "Missing region in config",
|
||||
errorInvalidToken: "The security token included in the request is invalid.",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ export const firestoreText = {
|
|||
cypressFirestore: "cypress-firestore",
|
||||
labelPrivateKey: "Private key",
|
||||
privateKey: "Private key",
|
||||
placeholderPrivateKey: "Enter private key",
|
||||
placeholderPrivateKey: "**************",
|
||||
|
||||
errorGcpKeyCouldNotBeParsed:
|
||||
"GCP key could not be parsed as a valid JSON object",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export const postgreSqlText = {
|
|||
allDataSources: "All data sources (43)",
|
||||
allDatabase: "Databases (19)",
|
||||
allApis: "APIs (20)",
|
||||
allCloudStorage: "Cloud Storage (4)",
|
||||
allCloudStorage: "Cloud Storages (4)",
|
||||
|
||||
postgreSQL: "PostgreSQL",
|
||||
labelHost: "Host",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@ export const redisText = {
|
|||
|
||||
errorMaxRetries:
|
||||
'Reached the max retries per request limit (which is 1). Refer to "maxRetriesPerRequest" option for details.',
|
||||
errorPort: "Port should be >= 0 and < 65536. Received 108299.",
|
||||
errorPort: "Port should be >= 0 and < 65536. Received type number (108299).",
|
||||
errorInvalidUserOrPassword: "WRONGPASS invalid username-password pair",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import {
|
|||
closeDSModal,
|
||||
deleteDatasource,
|
||||
addQuery,
|
||||
addQueryN,
|
||||
verifyValueOnInspector,
|
||||
} from "Support/utils/dataSource";
|
||||
import { dataSourceSelector } from "Selectors/dataSource";
|
||||
|
|
@ -38,12 +37,8 @@ describe("Global Datasource Manager", () => {
|
|||
cy.viewport(1200, 1300);
|
||||
});
|
||||
before(() => {
|
||||
cy.apiLogin();
|
||||
cy.apiCreateApp();
|
||||
cy.openApp();
|
||||
cy.renameApp(data.appName);
|
||||
cy.dragAndDropWidget("Table", 250, 250);
|
||||
cy.get(commonSelectors.editorPageLogo).click();
|
||||
cy.defaultWorkspaceLogin();
|
||||
cy.apiCreateApp(data.appName);
|
||||
addNewUserMW(data.firstName, data.email);
|
||||
logout();
|
||||
});
|
||||
|
|
@ -72,7 +67,7 @@ describe("Global Datasource Manager", () => {
|
|||
);
|
||||
cy.get(dataSourceSelector.querySearchBar)
|
||||
.invoke("attr", "placeholder")
|
||||
.should("eq", "Search Databases");
|
||||
.should("eq", "Search data sources");
|
||||
|
||||
cy.get(dataSourceSelector.apiLabelAndCount)
|
||||
.verifyVisibleElement("have.text", dataSourceText.allApis)
|
||||
|
|
@ -81,20 +76,14 @@ describe("Global Datasource Manager", () => {
|
|||
"have.text",
|
||||
" APIs"
|
||||
);
|
||||
cy.get(dataSourceSelector.querySearchBar)
|
||||
.invoke("attr", "placeholder")
|
||||
.should("eq", "Search APIs");
|
||||
|
||||
cy.get(dataSourceSelector.cloudStorageLabelAndCount)
|
||||
.verifyVisibleElement("have.text", dataSourceText.allCloudStorage)
|
||||
.click();
|
||||
cy.get(commonSelectors.breadcrumbPageTitle).verifyVisibleElement(
|
||||
"have.text",
|
||||
" Cloud Storage"
|
||||
" Cloud Storages"
|
||||
);
|
||||
cy.get(dataSourceSelector.querySearchBar)
|
||||
.invoke("attr", "placeholder")
|
||||
.should("eq", "Search Cloud Storage");
|
||||
|
||||
cy.get(dataSourceSelector.pluginsLabelAndCount)
|
||||
.verifyVisibleElement("have.text", dataSourceText.pluginsLabelAndCount)
|
||||
|
|
@ -103,9 +92,6 @@ describe("Global Datasource Manager", () => {
|
|||
"have.text",
|
||||
" Plugins"
|
||||
);
|
||||
cy.get(dataSourceSelector.querySearchBar)
|
||||
.invoke("attr", "placeholder")
|
||||
.should("eq", "Search Plugins");
|
||||
|
||||
cy.get('[data-cy="added-ds-label"]').should(($el) => {
|
||||
expect($el.contents().first().text().trim()).to.eq("Data sources added");
|
||||
|
|
@ -178,6 +164,7 @@ describe("Global Datasource Manager", () => {
|
|||
|
||||
deleteDatasource(`cypress-${data.dsName1}-postgresql1`);
|
||||
});
|
||||
|
||||
it("Should verify the Datasource connection and query creation using global data source", () => {
|
||||
selectAndAddDataSource(
|
||||
"databases",
|
||||
|
|
@ -198,10 +185,7 @@ describe("Global Datasource Manager", () => {
|
|||
);
|
||||
cy.wait("@datasource");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).click();
|
||||
cy.get(commonSelectors.dashboardIcon).click();
|
||||
navigateToAppEditor(data.appName);
|
||||
|
||||
cy.openApp();
|
||||
pinInspector();
|
||||
|
||||
addQuery(
|
||||
|
|
@ -223,24 +207,22 @@ describe("Global Datasource Manager", () => {
|
|||
.should("be.visible")
|
||||
.and("have.text", "+ Add new Data source");
|
||||
cy.get(".p-2 > .tj-base-btn").click();
|
||||
cy.get('[data-cy="databases-datasource-button"]').should("be.visible");
|
||||
|
||||
selectAndAddDataSource(
|
||||
"databases",
|
||||
dataSourceText.postgreSQL,
|
||||
data.dsName2
|
||||
cy.apiCreateGDS(
|
||||
"http://localhost:3000/api/v2/data_sources",
|
||||
`cypress-${data.dsName2}-postgresql`,
|
||||
"postgresql",
|
||||
[
|
||||
{ key: "host", value: Cypress.env("pg_host") },
|
||||
{ key: "port", value: 5432 },
|
||||
{ key: "database", value: Cypress.env("pg_user") },
|
||||
{ key: "username", value: Cypress.env("pg_user") },
|
||||
{ key: "password", value: Cypress.env("pg_password"), encrypted: true },
|
||||
{ key: "ssl_enabled", value: false, encrypted: false },
|
||||
{ key: "ssl_certificate", value: "none", encrypted: false },
|
||||
]
|
||||
);
|
||||
cy.intercept("GET", "api/v2/data_sources").as("datasource");
|
||||
fillConnectionForm(
|
||||
{
|
||||
Host: Cypress.env("pg_host"),
|
||||
Port: "5432",
|
||||
"Database Name": Cypress.env("pg_user"),
|
||||
Username: Cypress.env("pg_user"),
|
||||
Password: Cypress.env("pg_password"),
|
||||
},
|
||||
".form-switch"
|
||||
);
|
||||
cy.wait("@datasource");
|
||||
|
||||
navigateToManageGroups();
|
||||
cy.get(groupsSelector.appSearchBox).click();
|
||||
|
|
@ -265,7 +247,7 @@ describe("Global Datasource Manager", () => {
|
|||
it("Should validate the user's global data source permissions on apps created by admin", () => {
|
||||
logout();
|
||||
cy.apiLogin(data.email, "password");
|
||||
cy.visit('/my-workspace')
|
||||
cy.visit("/my-workspace");
|
||||
|
||||
cy.get(commonSelectors.globalDataSourceIcon).should("not.exist");
|
||||
|
||||
|
|
@ -281,8 +263,7 @@ describe("Global Datasource Manager", () => {
|
|||
cy.get(dataSourceSelector.queryCreateAndRunButton).click();
|
||||
verifyValueOnInspector("table_preview", "7 items ");
|
||||
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
addQueryN(
|
||||
addQuery(
|
||||
"student_data",
|
||||
`SELECT * FROM student_data;`,
|
||||
`cypress-${data.dsName2}-postgresql`
|
||||
|
|
@ -293,16 +274,14 @@ describe("Global Datasource Manager", () => {
|
|||
"student_data "
|
||||
);
|
||||
cy.get(dataSourceSelector.queryCreateAndRunButton).click();
|
||||
verifyValueOnInspector("student_data", "8 items ");
|
||||
verifyValueOnInspector("student_data", "4 items ");
|
||||
});
|
||||
it("Should verify the query creation and scope changing functionality.", () => {
|
||||
data.appName = `${fake.companyName}-App`;
|
||||
logout();
|
||||
cy.apiLogin(data.email, "password");
|
||||
cy.visit('/my-workspace')
|
||||
cy.apiCreateApp(data.appName);
|
||||
cy.openApp();
|
||||
cy.dragAndDropWidget("Table", 250, 250);
|
||||
|
||||
addQuery(
|
||||
"table_preview",
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ describe("Data sources", () => {
|
|||
);
|
||||
fillDataSourceTextField(
|
||||
"Key",
|
||||
"Enter your key",
|
||||
"**************",
|
||||
Cypress.env("cosmosdb_key")
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ describe("Data source Elasticsearch", () => {
|
|||
|
||||
fillDataSourceTextField(
|
||||
postgreSqlText.labelPassword,
|
||||
"Enter password",
|
||||
"**************",
|
||||
Cypress.env("elasticsearch_password")
|
||||
);
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ describe("Data source Elasticsearch", () => {
|
|||
|
||||
fillDataSourceTextField(
|
||||
postgreSqlText.labelPassword,
|
||||
"Enter password",
|
||||
"**************",
|
||||
"elasticsearch_password"
|
||||
);
|
||||
|
||||
|
|
@ -173,7 +173,7 @@ describe("Data source Elasticsearch", () => {
|
|||
);
|
||||
fillDataSourceTextField(
|
||||
postgreSqlText.labelPassword,
|
||||
"Enter password",
|
||||
"**************",
|
||||
Cypress.env("elasticsearch_password")
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ describe("Data sources", () => {
|
|||
);
|
||||
fillDataSourceTextField(
|
||||
postgreSqlText.labelPassword,
|
||||
"Enter password",
|
||||
"**************",
|
||||
Cypress.env("mariadb_password")
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ describe("Data sources MySql", () => {
|
|||
);
|
||||
fillDataSourceTextField(
|
||||
postgreSqlText.labelPassword,
|
||||
"Enter password",
|
||||
"**************",
|
||||
Cypress.env("mysql_password")
|
||||
);
|
||||
|
||||
|
|
@ -169,7 +169,7 @@ describe("Data sources MySql", () => {
|
|||
|
||||
fillDataSourceTextField(
|
||||
postgreSqlText.labelPassword,
|
||||
"Enter password",
|
||||
"**************",
|
||||
Cypress.env("mysql_password")
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ describe("Data sources", () => {
|
|||
);
|
||||
fillDataSourceTextField(
|
||||
postgreSqlText.labelPassword,
|
||||
"Enter password",
|
||||
"**************",
|
||||
Cypress.env("pg_password")
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ describe("Data source Redis", () => {
|
|||
|
||||
fillDataSourceTextField(
|
||||
postgreSqlText.labelPassword,
|
||||
"Enter password",
|
||||
"**************",
|
||||
Cypress.env("redis_password")
|
||||
);
|
||||
|
||||
|
|
@ -156,7 +156,7 @@ describe("Data source Redis", () => {
|
|||
|
||||
fillDataSourceTextField(
|
||||
postgreSqlText.labelPassword,
|
||||
"Enter password",
|
||||
"**************",
|
||||
"redis_password"
|
||||
);
|
||||
|
||||
|
|
@ -168,7 +168,7 @@ describe("Data source Redis", () => {
|
|||
|
||||
fillDataSourceTextField(
|
||||
postgreSqlText.labelPassword,
|
||||
"Enter password",
|
||||
"**************",
|
||||
Cypress.env("redis_password")
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ describe("Data source SMTP", () => {
|
|||
|
||||
fillDataSourceTextField(
|
||||
postgreSqlText.labelPassword,
|
||||
"Enter password",
|
||||
"**************",
|
||||
Cypress.env("smtp_password")
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ describe("Data sources", () => {
|
|||
);
|
||||
cy.get('[data-cy="connection-alert-text"]').should(
|
||||
"have.text",
|
||||
"Network error. Could not reach Snowflake."
|
||||
"Invalid account. The specified value must be a valid subdomain string."
|
||||
);
|
||||
deleteDatasource(`cypress-${data.lastName}-snowflake`);
|
||||
});
|
||||
|
|
@ -124,7 +124,7 @@ describe("Data sources", () => {
|
|||
);
|
||||
fillDataSourceTextField(
|
||||
"Password",
|
||||
"Enter password",
|
||||
"**************",
|
||||
Cypress.env("snowflake_password")
|
||||
);
|
||||
fillDataSourceTextField(
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ describe("Data sources", () => {
|
|||
|
||||
fillDataSourceTextField(
|
||||
postgreSqlText.labelPassword,
|
||||
"Enter password",
|
||||
"**************",
|
||||
Cypress.env("sqlserver_password")
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -100,17 +100,20 @@ describe("Redirection error pages", () => {
|
|||
cy.visit(`http://localhost:8082/applications/${data.slug}`);
|
||||
cy.get(commonSelectors.modalHeader).verifyVisibleElement(
|
||||
"have.text",
|
||||
"URL unavailable"
|
||||
"App URL Unavailable"
|
||||
);
|
||||
cy.get(commonSelectors.modalDescription).verifyVisibleElement(
|
||||
"have.text",
|
||||
"This URL is not accessible because it has not been released yet. Please either release it or contact admin for access."
|
||||
'The app URL is currently unavailable because the app has not been released. Please either release it or contact admin for access.'
|
||||
);
|
||||
cy.get('[data-cy="open-app-button"]').verifyVisibleElement("have.text", "Open app")
|
||||
|
||||
cy.get(commonSelectors.backToHomeButton).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Back to home page"
|
||||
);
|
||||
cy.url().should("eq", "http://localhost:8082/error/url-unavailable");
|
||||
|
||||
cy.url().should("eq", `http://localhost:8082/error/url-unavailable?appSlug=${data.slug}`);
|
||||
cy.get(commonSelectors.backToHomeButton).click();
|
||||
cy.get(commonSelectors.pageSectionHeader).should("be.visible");
|
||||
|
||||
|
|
@ -127,6 +130,8 @@ describe("Redirection error pages", () => {
|
|||
"have.text",
|
||||
"You don’t have access to this app. Kindly contact admin to know more."
|
||||
);
|
||||
// cy.get('[data-cy="open-app-button"]').verifyVisibleElement("have.text", "Open app")
|
||||
|
||||
cy.get(commonSelectors.backToHomeButton).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Back to home page"
|
||||
|
|
@ -157,17 +162,17 @@ describe("Redirection error pages", () => {
|
|||
cy.visit(`http://localhost:8082/applications/${data.slug}`);
|
||||
cy.get(commonSelectors.modalHeader).verifyVisibleElement(
|
||||
"have.text",
|
||||
"URL unavailable"
|
||||
"App URL Unavailable"
|
||||
);
|
||||
cy.get(commonSelectors.modalDescription).verifyVisibleElement(
|
||||
"have.text",
|
||||
"This URL is not accessible because it has not been released yet. Please either release it or contact admin for access."
|
||||
'The app URL is currently unavailable because the app has not been released. Please either release it or contact admin for access.'
|
||||
);
|
||||
cy.get(commonSelectors.backToHomeButton).verifyVisibleElement(
|
||||
"have.text",
|
||||
"Back to home page"
|
||||
);
|
||||
cy.url().should("eq", "http://localhost:8082/error/url-unavailable");
|
||||
cy.url().should("eq", `http://localhost:8082/error/url-unavailable?appSlug=${data.slug}`);
|
||||
cy.get(commonSelectors.backToHomeButton).click();
|
||||
cy.get(commonSelectors.pageSectionHeader).should("be.visible");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export const deleteComponentAndVerify = (widgetName) => {
|
|||
});
|
||||
cy.verifyToastMessage(
|
||||
`[class=go3958317564]`,
|
||||
"Component deleted! (⌘ + Z to undo)"
|
||||
"Component deleted! (ctrl + Z to undo)"
|
||||
);
|
||||
cy.notVisible(commonWidgetSelector.draggableWidget(widgetName));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -72,33 +72,44 @@ export const closeDSModal = () => {
|
|||
});
|
||||
};
|
||||
|
||||
export const addQuery = (queryName, query, dbName) => {
|
||||
export const addQueryN = (queryName, query, dbName) => {
|
||||
cy.get("body").then(($body) => {
|
||||
if ($body.find('[data-cy="gds-querymanager-search-bar"]').length > 0) {
|
||||
cy.clearAndType('[data-cy="gds-querymanager-search-bar"]', `${dbName}`);
|
||||
}
|
||||
});
|
||||
cy.intercept("POST", "http://localhost:3000/api/data_queries").as(
|
||||
"createQuery"
|
||||
);
|
||||
|
||||
cy.get(`[data-cy="${dbName}-add-query-card"] > .text-truncate`).click();
|
||||
cy.get('[data-cy="query-rename-input"]').clear().type(queryName);
|
||||
cy.forceClickOnCanvas();
|
||||
|
||||
cy.get(dataSourceSelector.queryInputField)
|
||||
.realMouseDown({ position: "center" })
|
||||
.realType(" ");
|
||||
cy.get(dataSourceSelector.queryInputField).clearAndTypeOnCodeMirror(query);
|
||||
cy.get(dataSourceSelector.queryCreateAndRunButton).click();
|
||||
cy.wait("@createQuery").then((interception) => {
|
||||
const dataQueryId = interception.response.body.id;
|
||||
cy.visit("/my-workspace");
|
||||
cy.addQueryApi(queryName, query, dataQueryId);
|
||||
cy.openApp();
|
||||
});
|
||||
};
|
||||
|
||||
export const addQueryN = (queryName, query, dbName) => {
|
||||
export const addQuery = (queryName, query, dbName) => {
|
||||
cy.get('[data-cy="show-ds-popover-button"]').click();
|
||||
cy.get(".css-1rrkggf-Input").type(`${dbName}`);
|
||||
cy.intercept("POST", "http://localhost:3000/api/data_queries").as(
|
||||
"createQuery"
|
||||
);
|
||||
cy.contains(`[id*="react-select-"]`, dbName).click();
|
||||
|
||||
cy.get('[data-cy="query-rename-input"]').clear().type(queryName);
|
||||
|
||||
cy.get(dataSourceSelector.queryInputField)
|
||||
.realMouseDown({ position: "center" })
|
||||
.realType(" ");
|
||||
cy.get(dataSourceSelector.queryInputField).clearAndTypeOnCodeMirror(query);
|
||||
cy.get(dataSourceSelector.queryCreateAndRunButton).click();
|
||||
cy.wait("@createQuery").then((interception) => {
|
||||
const dataQueryId = interception.response.body.id;
|
||||
cy.visit("/my-workspace");
|
||||
cy.addQueryApi(queryName, query, dataQueryId);
|
||||
cy.openApp();
|
||||
});
|
||||
};
|
||||
|
||||
export const verifyValueOnInspector = (queryName, value) => {
|
||||
|
|
@ -119,4 +130,4 @@ export const verifyValueOnInspector = (queryName, value) => {
|
|||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
|
|
|||
6779
cypress-tests/package-lock.json
generated
6779
cypress-tests/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -7,7 +7,7 @@ sudo apt-get -y install --no-install-recommends wget gnupg ca-certificates apt-u
|
|||
curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||
nvm install 18.3.0
|
||||
nvm install 18.18.2
|
||||
sudo ln -s "$(which node)" /usr/bin/node
|
||||
sudo ln -s "$(which npm)" /usr/bin/npm
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ mv /tmp/.env ~/app/.env
|
|||
mv /tmp/setup_app ~/app/setup_app
|
||||
sudo chmod +x ~/app/setup_app
|
||||
|
||||
npm install -g npm@8.11.0
|
||||
npm install -g npm@9.8.1
|
||||
|
||||
# Building ToolJet app
|
||||
npm install -g @nestjs/cli
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
# pull official base image
|
||||
FROM node:18.3.0-buster
|
||||
FROM node:18.18.2-buster
|
||||
|
||||
ENV NODE_ENV=development
|
||||
|
||||
RUN npm i -g npm@8.11.0
|
||||
RUN npm i -g npm@9.8.1
|
||||
|
||||
# set working directory
|
||||
WORKDIR /app
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# pull official base image
|
||||
FROM node:18.3.0-buster
|
||||
FROM node:18.18.2-buster
|
||||
|
||||
RUN npm i -g npm@8.11.0
|
||||
RUN npm i -g npm@9.8.1
|
||||
|
||||
# set working directory
|
||||
WORKDIR /app
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:18.3.0-buster AS builder
|
||||
FROM node:18.18.2-buster AS builder
|
||||
# Fix for JS heap limit allocation issue
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ COPY ./server/ ./server/
|
|||
RUN npm install -g @nestjs/cli
|
||||
RUN npm --prefix server run build
|
||||
|
||||
FROM node:18.3.0-buster
|
||||
FROM node:18.18.2-buster
|
||||
# copy postgrest executable
|
||||
COPY --from=postgrest/postgrest:v10.1.1.20221215 /bin/postgrest /bin
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
FROM node:18.3.0-buster AS builder
|
||||
FROM node:18.18.2-buster AS builder
|
||||
|
||||
# Fix for JS heap limit allocation issue
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
|
||||
RUN npm i -g npm@8.11.0
|
||||
RUN npm i -g npm@9.8.1
|
||||
RUN mkdir -p /app
|
||||
|
||||
WORKDIR /app
|
||||
|
|
@ -42,12 +42,12 @@ RUN apt-get update -yq \
|
|||
&& apt-get clean -y
|
||||
|
||||
|
||||
RUN curl -O https://nodejs.org/dist/v18.3.0/node-v18.3.0-linux-x64.tar.xz \
|
||||
&& tar -xf node-v18.3.0-linux-x64.tar.xz \
|
||||
&& mv node-v18.3.0-linux-x64 /usr/local/lib/nodejs \
|
||||
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 \
|
||||
&& mv node-v18.18.2-linux-x64 /usr/local/lib/nodejs \
|
||||
&& echo 'export PATH="/usr/local/lib/nodejs/bin:$PATH"' >> /etc/profile.d/nodejs.sh \
|
||||
&& /bin/bash -c "source /etc/profile.d/nodejs.sh" \
|
||||
&& rm node-v18.3.0-linux-x64.tar.xz
|
||||
&& rm node-v18.18.2-linux-x64.tar.xz
|
||||
ENV PATH=/usr/local/lib/nodejs/bin:$PATH
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
FROM node:18.3.0-buster as builder
|
||||
FROM node:18.18.2-buster as builder
|
||||
|
||||
# Fix for JS heap limit allocation issue
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
|
||||
RUN npm i -g npm@8.11.0
|
||||
RUN npm i -g npm@9.8.1
|
||||
RUN npm install -g @nestjs/cli
|
||||
|
||||
RUN mkdir -p /app
|
||||
|
|
@ -32,12 +32,12 @@ RUN apt-get update -yq \
|
|||
&& apt-get install -yq build-essential \
|
||||
&& apt-get clean -y
|
||||
|
||||
RUN curl -O https://nodejs.org/dist/v18.3.0/node-v18.3.0-linux-x64.tar.xz \
|
||||
&& tar -xf node-v18.3.0-linux-x64.tar.xz \
|
||||
&& mv node-v18.3.0-linux-x64 /usr/local/lib/nodejs \
|
||||
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 \
|
||||
&& mv node-v18.18.2-linux-x64 /usr/local/lib/nodejs \
|
||||
&& echo 'export PATH="/usr/local/lib/nodejs/bin:$PATH"' >> /etc/profile.d/nodejs.sh \
|
||||
&& /bin/bash -c "source /etc/profile.d/nodejs.sh" \
|
||||
&& rm node-v18.3.0-linux-x64.tar.xz
|
||||
&& rm node-v18.18.2-linux-x64.tar.xz
|
||||
ENV PATH=/usr/local/lib/nodejs/bin:$PATH
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# pull official base image
|
||||
FROM node:18.3.0-buster
|
||||
FROM node:18.18.2-buster
|
||||
RUN apt-get update && apt-get install -y postgresql-client freetds-dev libaio1 wget
|
||||
|
||||
# Install Instantclient Basic Light Oracle and Dependencies
|
||||
|
|
@ -19,7 +19,7 @@ WORKDIR /
|
|||
ENV NODE_ENV=development
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
|
||||
RUN npm i -g npm@8.11.0
|
||||
RUN npm i -g npm@9.8.1
|
||||
RUN mkdir -p /app
|
||||
WORKDIR /app
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ module.exports = {
|
|||
'import/no-unresolved': [
|
||||
'error',
|
||||
{
|
||||
ignore: ['^@/', 'react-hot-toast', 'react-i18next'],
|
||||
ignore: ['^@/', 'react-hot-toast', 'react-i18next', 'react-loading-skeleton', 'react-spring'],
|
||||
},
|
||||
],
|
||||
'react/no-unknown-property': 'off',
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
2.26.2
|
||||
2.27.0
|
||||
|
|
|
|||
82863
frontend/package-lock.json
generated
82863
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -31,6 +31,7 @@
|
|||
"draft-js-export-html": "^1.4.1",
|
||||
"driver.js": "^0.9.8",
|
||||
"emoji-mart": "^5.5.2",
|
||||
"file-loader": "^6.2.0",
|
||||
"focus-trap-react": "^10.0.2",
|
||||
"fuse.js": "^6.6.2",
|
||||
"html-loader": "^4.2.0",
|
||||
|
|
@ -97,6 +98,7 @@
|
|||
"react-zoom-pan-pinch": "^2.6.1",
|
||||
"rxjs": "^7.8.0",
|
||||
"semver": "^7.3.8",
|
||||
"string-hash": "^1.1.3",
|
||||
"superstruct": "^1.0.3",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"url-join": "^5.0.0",
|
||||
|
|
|
|||
|
|
@ -191,7 +191,8 @@ class DataSourceManagerComponent extends React.Component {
|
|||
};
|
||||
|
||||
createDataSource = () => {
|
||||
const { appId, options, selectedDataSource, selectedDataSourcePluginId } = this.state;
|
||||
const { appId, options, selectedDataSource, selectedDataSourcePluginId, dataSourceMeta, dataSourceSchema } =
|
||||
this.state;
|
||||
const name = selectedDataSource.name;
|
||||
const kind = selectedDataSource.kind;
|
||||
const pluginId = selectedDataSourcePluginId;
|
||||
|
|
@ -200,7 +201,7 @@ class DataSourceManagerComponent extends React.Component {
|
|||
const scope = this.state?.scope || selectedDataSource?.scope;
|
||||
|
||||
const parsedOptions = Object?.keys(options)?.map((key) => {
|
||||
const keyMeta = selectedDataSource.options[key];
|
||||
const keyMeta = dataSourceMeta.options[key];
|
||||
return {
|
||||
key: key,
|
||||
value: options[key].value,
|
||||
|
|
|
|||
|
|
@ -62,10 +62,12 @@ import { EMPTY_ARRAY, useEditorActions, useEditorStore } from '@/_stores/editorS
|
|||
import { useAppDataActions, useAppInfo, useAppDataStore } from '@/_stores/appDataStore';
|
||||
import { useMounted } from '@/_hooks/use-mount';
|
||||
import EditorSelecto from './EditorSelecto';
|
||||
import { useSocketOpen } from '@/_hooks/use-socket-open';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { diff } from 'deep-object-diff';
|
||||
|
||||
import useDebouncedArrowKeyPress from '@/_hooks/useDebouncedArrowKeyPress';
|
||||
import { getQueryParams } from '@/_helpers/routes';
|
||||
import RightSidebarTabManager from './RightSidebarTabManager';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
|
|
@ -80,6 +82,7 @@ const decimalToHex = (alpha) => (alpha === 0 ? '00' : Math.round(255 * alpha).to
|
|||
|
||||
const EditorComponent = (props) => {
|
||||
const { socket } = createWebsocketConnection(props?.params?.id);
|
||||
const isSocketOpen = useSocketOpen(socket);
|
||||
const mounted = useMounted();
|
||||
|
||||
const {
|
||||
|
|
@ -338,7 +341,14 @@ const EditorComponent = (props) => {
|
|||
const fetchApps = async (page) => {
|
||||
const { apps } = await appService.getAll(page);
|
||||
|
||||
updateState({ apps: apps.map((app) => ({ id: app.id, name: app.name, slug: app.slug })) });
|
||||
updateState({
|
||||
apps: apps.map((app) => ({
|
||||
id: app.id,
|
||||
name: app.name,
|
||||
slug: app.slug,
|
||||
current_version_id: app.current_version_id,
|
||||
})),
|
||||
});
|
||||
};
|
||||
|
||||
const fetchOrgEnvironmentVariables = () => {
|
||||
|
|
@ -613,12 +623,14 @@ const EditorComponent = (props) => {
|
|||
const onVersionRelease = (versionId) => {
|
||||
useAppVersionStore.getState().actions.updateReleasedVersionId(versionId);
|
||||
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
event: 'events',
|
||||
data: { message: 'versionReleased', appId: appId },
|
||||
})
|
||||
);
|
||||
if (socket instanceof WebSocket && socket?.readyState === WebSocket.OPEN) {
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
event: 'events',
|
||||
data: { message: 'versionReleased', appId: appId },
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const computeCanvasBackgroundColor = () => {
|
||||
|
|
@ -1367,11 +1379,21 @@ const EditorComponent = (props) => {
|
|||
useCurrentStateStore.getState().actions.setCurrentState({ globals, page });
|
||||
};
|
||||
|
||||
const navigateToPage = (queryParams = [], handle) => {
|
||||
const appId = useAppDataStore.getState()?.appId;
|
||||
const queryParamsString = queryParams.map(([key, value]) => `${key}=${value}`).join('&');
|
||||
|
||||
props?.navigate(`/${getWorkspaceId()}/apps/${slug ?? appId}/${handle}?${queryParamsString}`, {
|
||||
state: {
|
||||
isSwitchingPage: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const switchPage = (pageId, queryParams = []) => {
|
||||
// This are fetched from store to handle runQueriesOnAppLoad
|
||||
const currentPageId = useEditorStore.getState().currentPageId;
|
||||
const appDefinition = useEditorStore.getState().appDefinition;
|
||||
const appId = useAppDataStore.getState()?.appId;
|
||||
const pageHandle = getCurrentState().pageHandle;
|
||||
|
||||
if (currentPageId === pageId && pageHandle === appDefinition?.pages[pageId]?.handle) {
|
||||
|
|
@ -1381,13 +1403,7 @@ const EditorComponent = (props) => {
|
|||
|
||||
if (!name || !handle) return;
|
||||
const copyOfAppDefinition = JSON.parse(JSON.stringify(appDefinition));
|
||||
const queryParamsString = queryParams.map(([key, value]) => `${key}=${value}`).join('&');
|
||||
|
||||
props?.navigate(`/${getWorkspaceId()}/apps/${slug ?? appId}/${handle}?${queryParamsString}`, {
|
||||
state: {
|
||||
isSwitchingPage: true,
|
||||
},
|
||||
});
|
||||
navigateToPage(queryParams, handle);
|
||||
|
||||
const page = {
|
||||
id: pageId,
|
||||
|
|
@ -1396,6 +1412,7 @@ const EditorComponent = (props) => {
|
|||
variables: copyOfAppDefinition.pages[pageId]?.variables ?? {},
|
||||
};
|
||||
|
||||
const queryParamsString = queryParams.map(([key, value]) => `${key}=${value}`).join('&');
|
||||
const globals = {
|
||||
...currentState.globals,
|
||||
urlparams: JSON.parse(JSON.stringify(queryString.parse(queryParamsString))),
|
||||
|
|
@ -1590,6 +1607,9 @@ const EditorComponent = (props) => {
|
|||
appDefinitionChanged(newDefinition, {
|
||||
pageDefinitionChanged: true,
|
||||
});
|
||||
|
||||
const queryParams = getQueryParams();
|
||||
navigateToPage(Object.entries(queryParams), newHandle);
|
||||
};
|
||||
|
||||
const updateOnSortingPages = (newSortedPages) => {
|
||||
|
|
@ -1698,6 +1718,7 @@ const EditorComponent = (props) => {
|
|||
appName={appName}
|
||||
appId={appId}
|
||||
slug={slug}
|
||||
isSocketOpen={isSocketOpen}
|
||||
/>
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<div className="sub-section">
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ export default function EditorHeader({
|
|||
onVersionDelete,
|
||||
slug,
|
||||
darkMode,
|
||||
isSocketOpen,
|
||||
}) {
|
||||
const currentUser = useCurrentUser();
|
||||
|
||||
|
|
@ -193,14 +194,16 @@ export default function EditorHeader({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="nav-item dropdown promote-release-btn">
|
||||
<ReleaseVersionButton
|
||||
appId={appId}
|
||||
appName={appName}
|
||||
onVersionRelease={onVersionRelease}
|
||||
saveEditingVersion={saveEditingVersion}
|
||||
/>
|
||||
</div>
|
||||
{isSocketOpen && (
|
||||
<div className="nav-item dropdown promote-release-btn">
|
||||
<ReleaseVersionButton
|
||||
appId={appId}
|
||||
appName={appName}
|
||||
onVersionRelease={onVersionRelease}
|
||||
saveEditingVersion={saveEditingVersion}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ export const EventManager = ({
|
|||
function getAllApps() {
|
||||
let appsOptionsList = [];
|
||||
apps
|
||||
.filter((item) => item.slug !== undefined && item.id !== appId)
|
||||
.filter((item) => item.slug !== undefined && item.id !== appId && item.current_version_id)
|
||||
.forEach((item) => {
|
||||
appsOptionsList.push({
|
||||
name: item.name,
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ class ViewerComponent extends React.Component {
|
|||
redirectToErrorPage(ERROR_TYPES.INVALID);
|
||||
} else if (error?.statusCode === 403) {
|
||||
redirectToErrorPage(ERROR_TYPES.RESTRICTED);
|
||||
} else {
|
||||
} else if (error?.statusCode !== 401) {
|
||||
redirectToErrorPage(ERROR_TYPES.UNKNOWN);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import React, { useContext, useRef, useState, useEffect } from 'react';
|
||||
import cx from 'classnames';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { Sidebar } from '../Sidebar';
|
||||
import { GlobalDataSourcesContext } from '..';
|
||||
import { DataSourceManager } from '@/Editor/DataSourceManager';
|
||||
import { DataBaseSources, ApiSources, CloudStorageSources } from '@/Editor/DataSourceManager/SourceComponents';
|
||||
import { pluginsService, globalDatasourceService } from '@/_services';
|
||||
import { pluginsService, globalDatasourceService, authenticationService } from '@/_services';
|
||||
import { Card } from '@/_ui/Card';
|
||||
import { SegregatedList } from '../SegregatedList';
|
||||
import { SearchBox } from '@/_components';
|
||||
|
|
@ -21,7 +22,11 @@ export const GlobalDataSourcesPage = ({ darkMode = false, updateSelectedDatasour
|
|||
const [filteredDataSources, setFilteredDataSources] = useState([]);
|
||||
const [queryString, setQueryString] = useState('');
|
||||
const [addingDataSource, setAddingDataSource] = useState(false);
|
||||
const [suggestingDataSource, setSuggestingDataSource] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const { admin } = authenticationService.currentSessionValue;
|
||||
const marketplaceEnabled = admin && window.public_config?.ENABLE_MARKETPLACE_FEATURE == 'true';
|
||||
const [modalProps, setModalProps] = useState({
|
||||
backdrop: false,
|
||||
dialogClassName: `datasource-edit-modal`,
|
||||
|
|
@ -98,15 +103,22 @@ export const GlobalDataSourcesPage = ({ darkMode = false, updateSelectedDatasour
|
|||
const searchQuery = e.target.value;
|
||||
setQueryString(searchQuery);
|
||||
|
||||
const arr = [];
|
||||
const filteredDatasources = datasourcesGroups().filter((group) => group.key === activeDatasourceList)[0].list;
|
||||
let arr = [];
|
||||
|
||||
filteredDatasources.forEach((datasource) => {
|
||||
if (datasource.name.toLowerCase().includes(searchQuery.toLowerCase())) {
|
||||
arr.push(datasource);
|
||||
}
|
||||
const filtered = datasourcesGroups().map((datasourceGroup) => {
|
||||
datasourceGroup.list.map((dataSource) => {
|
||||
if (dataSource.name.toLowerCase().includes(searchQuery.toLowerCase())) {
|
||||
arr.push({ ...dataSource, type: datasourceGroup.type });
|
||||
}
|
||||
});
|
||||
datasourceGroup.list = [...arr];
|
||||
(datasourceGroup.renderDatasources = () => renderCardGroup(datasourceGroup.list, datasourceGroup.type)),
|
||||
(arr = []);
|
||||
return datasourceGroup;
|
||||
});
|
||||
setFilteredDataSources([...arr]);
|
||||
const filteredDsList = filtered.reduce((acc, filteredGroup) => [...acc, ...filteredGroup.list], []);
|
||||
filteredDsList.length >= 1 ? setSuggestingDataSource(false) : setSuggestingDataSource(true);
|
||||
setFilteredDataSources([...filtered]);
|
||||
};
|
||||
|
||||
const createDataSource = (dataSource) => {
|
||||
|
|
@ -165,8 +177,7 @@ export const GlobalDataSourcesPage = ({ darkMode = false, updateSelectedDatasour
|
|||
};
|
||||
|
||||
const segregateDataSources = () => {
|
||||
const datasources = datasourcesGroups();
|
||||
const searchPlaceholder = datasources.filter((ds) => ds.key === activeDatasourceList)[0];
|
||||
const datasources = queryString && queryString.length > 0 ? filteredDataSources : datasourcesGroups();
|
||||
|
||||
return (
|
||||
<div className="datasource-list-container">
|
||||
|
|
@ -176,21 +187,40 @@ export const GlobalDataSourcesPage = ({ darkMode = false, updateSelectedDatasour
|
|||
dataCy={`home-page`}
|
||||
className="border-0 homepage-search"
|
||||
darkMode={darkMode}
|
||||
placeholder={`Search ${searchPlaceholder?.type || 'datasources'}`}
|
||||
placeholder={`Search data sources`}
|
||||
initialValue={queryString}
|
||||
width={'100%'}
|
||||
callBack={handleSearch}
|
||||
onClearCallback={() => setQueryString('')}
|
||||
onClearCallback={() => {
|
||||
setQueryString('');
|
||||
setSuggestingDataSource(false);
|
||||
}}
|
||||
/>
|
||||
<div className="liner mb-4"></div>
|
||||
</div>
|
||||
{datasources
|
||||
.filter((ds) => ds.key === activeDatasourceList)
|
||||
.map((dataSource) => {
|
||||
{suggestingDataSource ? (
|
||||
<center className="empty-ds-container">
|
||||
<div>
|
||||
<p className="mt-2 tj-text-lg font-weight-500 tj-text">{`No results for "${queryString}"`}</p>
|
||||
</div>
|
||||
<img src="assets/images/icons/no-results.svg" width="200" height="200" />
|
||||
</center>
|
||||
) : (
|
||||
datasources.map((dataSource) => {
|
||||
{
|
||||
return dataSource.renderDatasources();
|
||||
return (
|
||||
(dataSource.list.length > 0 || (!queryString && dataSource.type === 'Plugins')) && (
|
||||
<>
|
||||
<div id={dataSource.key} className="tj-text-md font-weight-500 tj-text">
|
||||
{dataSource.type}
|
||||
</div>
|
||||
{dataSource.renderDatasources()}
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
})}
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -200,10 +230,17 @@ export const GlobalDataSourcesPage = ({ darkMode = false, updateSelectedDatasour
|
|||
const dataSourceList = datasourcesGroups().splice(0, 5);
|
||||
const handleOnSelect = (activekey, type) => {
|
||||
setQueryString('');
|
||||
setSuggestingDataSource(false);
|
||||
toggleDataSourceManagerModal(false);
|
||||
setActiveDatasourceList(activekey);
|
||||
updateSidebarNAV(type);
|
||||
setSelectedDataSource(null);
|
||||
setTimeout(() => {
|
||||
const element = document.getElementById(activekey);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
|
|
@ -216,7 +253,35 @@ export const GlobalDataSourcesPage = ({ darkMode = false, updateSelectedDatasour
|
|||
);
|
||||
};
|
||||
|
||||
const renderCardGroup = (source) => {
|
||||
const renderCardGroup = (source, type) => {
|
||||
if (type === 'Plugins' && source.length === 0) {
|
||||
return (
|
||||
<div className="add-plugins-container">
|
||||
<div className="warning-container mb-2">
|
||||
<SolidIcon name="warning" />
|
||||
</div>
|
||||
<div className="tj-text-sm font-weight-500 tj-text">No plugins added</div>
|
||||
{admin && (
|
||||
<>
|
||||
<div className="tj-text-xsm font-weight-400 mt-2 mb-3">
|
||||
Browse through plugins in marketplace to add them as a Data Source.{' '}
|
||||
</div>
|
||||
<ButtonSolid
|
||||
onClick={() => {
|
||||
marketplaceEnabled
|
||||
? navigate('/integrations')
|
||||
: toast.error('Please enable marketplace to add plugins');
|
||||
}}
|
||||
style={{ margin: 'auto' }}
|
||||
variant="secondary"
|
||||
>
|
||||
Add plugins
|
||||
</ButtonSolid>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const addDataSourceBtn = (item) => (
|
||||
<ButtonSolid
|
||||
disabled={addingDataSource}
|
||||
|
|
@ -230,39 +295,6 @@ export const GlobalDataSourcesPage = ({ darkMode = false, updateSelectedDatasour
|
|||
</ButtonSolid>
|
||||
);
|
||||
|
||||
if (queryString && queryString.length > 0) {
|
||||
const filteredDatasources = filteredDataSources?.map((datasource) => {
|
||||
const src = datasource?.iconFile?.data
|
||||
? `data:image/svg+xml;base64,${datasource.iconFile?.data}`
|
||||
: datasource.kind.toLowerCase();
|
||||
|
||||
return {
|
||||
...datasource,
|
||||
src,
|
||||
title: datasource.name,
|
||||
};
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<div className="row row-deck mt-4 ">
|
||||
{filteredDatasources?.map((item) => (
|
||||
<Card
|
||||
key={item.key}
|
||||
title={item.title}
|
||||
src={item.src}
|
||||
usePluginIcon={isEmpty(item?.iconFile?.data)}
|
||||
height="35px"
|
||||
width="35px"
|
||||
actionButton={addDataSourceBtn(item)}
|
||||
className="datasource-card"
|
||||
titleClassName={'datasource-card-title'}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const datasources = source.map((datasource) => {
|
||||
const src = datasource?.iconFile?.data
|
||||
? `data:image/svg+xml;base64,${datasource.iconFile?.data}`
|
||||
|
|
@ -277,7 +309,7 @@ export const GlobalDataSourcesPage = ({ darkMode = false, updateSelectedDatasour
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="row row-deck mt-4">
|
||||
<div className="row row-deck mt-3">
|
||||
{datasources.map((item) => (
|
||||
<Card
|
||||
key={item.key}
|
||||
|
|
@ -305,17 +337,6 @@ export const GlobalDataSourcesPage = ({ darkMode = false, updateSelectedDatasour
|
|||
filteredDatasources: filteredDataSources,
|
||||
};
|
||||
const dataSourceList = [
|
||||
{
|
||||
type: 'All Datasources',
|
||||
key: '#alldatasources',
|
||||
list: [
|
||||
...allDataSourcesList.databases,
|
||||
...allDataSourcesList.apis,
|
||||
...allDataSourcesList.cloudStorages,
|
||||
...allDataSourcesList.plugins,
|
||||
],
|
||||
renderDatasources: () => renderCardGroup(allDataSourcesList, 'All Datasources'),
|
||||
},
|
||||
{
|
||||
type: 'Databases',
|
||||
key: '#databases',
|
||||
|
|
@ -329,7 +350,7 @@ export const GlobalDataSourcesPage = ({ darkMode = false, updateSelectedDatasour
|
|||
renderDatasources: () => renderCardGroup(allDataSourcesList.apis, 'APIs'),
|
||||
},
|
||||
{
|
||||
type: 'Cloud Storage',
|
||||
type: 'Cloud Storages',
|
||||
key: '#cloudstorage',
|
||||
list: allDataSourcesList.cloudStorages,
|
||||
renderDatasources: () => renderCardGroup(allDataSourcesList.cloudStorages, 'Cloud Storages'),
|
||||
|
|
@ -340,12 +361,6 @@ export const GlobalDataSourcesPage = ({ darkMode = false, updateSelectedDatasour
|
|||
list: allDataSourcesList.plugins,
|
||||
renderDatasources: () => renderCardGroup(allDataSourcesList.plugins, 'Plugins'),
|
||||
},
|
||||
{
|
||||
type: 'Filtered Datasources',
|
||||
key: '#filtereddatasources',
|
||||
list: allDataSourcesList.filteredDatasources,
|
||||
renderDatasources: () => renderCardGroup(filteredDataSources, activeDatasourceList),
|
||||
},
|
||||
];
|
||||
|
||||
return dataSourceList;
|
||||
|
|
|
|||
|
|
@ -4,33 +4,36 @@ import useGlobalDatasourceUnsavedChanges from '@/_hooks/useGlobalDatasourceUnsav
|
|||
|
||||
export const SegregatedList = ({ dataSources, activeDatasourceList, handleOnSelect }) => {
|
||||
const { handleActions } = useGlobalDatasourceUnsavedChanges();
|
||||
const totalDataSources = dataSources.reduce((acc, filteredGroup) => [...acc, ...filteredGroup.list], []).length;
|
||||
return (
|
||||
<>
|
||||
<div className="datasources-info tj-text-xsm datasource-list-header" data-cy="datasource-list-header">
|
||||
All data sources {dataSources[0].list.length > 0 && `(${dataSources[0].list.length})`}
|
||||
All data sources {totalDataSources > 0 && `(${totalDataSources})`}
|
||||
</div>
|
||||
{dataSources.slice(1, 5).map((dataSource, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={cx('mx-3 rounded-3 datasources-list', {
|
||||
'datasources-list-item': activeDatasourceList === dataSource.key,
|
||||
})}
|
||||
>
|
||||
{dataSources
|
||||
.filter((ds) => ds.list.length > 0 || ds.type === 'Plugins')
|
||||
.map((dataSource, index) => (
|
||||
<div
|
||||
role="button"
|
||||
onClick={() => handleActions(() => handleOnSelect(dataSource.key, dataSource.type))}
|
||||
className="col d-flex align-items-center overflow-hidden"
|
||||
data-cy={`${dataSource.key
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(/[^a-zA-Z0-9-]/g, '')}-datasource-button`}
|
||||
key={index}
|
||||
className={cx('mx-3 rounded-3 datasources-list', {
|
||||
'datasources-list-item': activeDatasourceList === dataSource.key,
|
||||
})}
|
||||
>
|
||||
<div className="font-400 tj-text-xsm text-truncate" style={{ paddingLeft: '6px' }}>
|
||||
{`${dataSource.type} (${dataSource.list.length})`}
|
||||
<div
|
||||
role="button"
|
||||
onClick={() => handleActions(() => handleOnSelect(dataSource.key, dataSource.type))}
|
||||
className="col d-flex align-items-center overflow-hidden"
|
||||
data-cy={`${dataSource.key
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(/[^a-zA-Z0-9-]/g, '')}-datasource-button`}
|
||||
>
|
||||
<div className="font-400 tj-text-xsm text-truncate" style={{ paddingLeft: '6px' }}>
|
||||
{`${dataSource.type} (${dataSource.list.length})`}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -56,10 +56,22 @@ export const GlobalDatasources = (props) => {
|
|||
globalDatasourceService
|
||||
.getAll()
|
||||
.then((data) => {
|
||||
const orderedDataSources = data.data_sources.sort((a, b) => a.name.localeCompare(b.name));
|
||||
const orderedDataSources = data.data_sources
|
||||
.map((ds) => {
|
||||
if (ds.options && ds.options.connection_limit) {
|
||||
return {
|
||||
...ds,
|
||||
options: {
|
||||
...ds.options,
|
||||
connectionLimit: ds.options.connection_limit,
|
||||
},
|
||||
};
|
||||
}
|
||||
return ds;
|
||||
})
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
setDataSources([...(orderedDataSources ?? [])]);
|
||||
const ds = dataSource && orderedDataSources.find((ds) => ds.id === dataSource.id);
|
||||
|
||||
if (!resetSelection && ds) {
|
||||
setEditing(true);
|
||||
setSelectedDataSource(ds);
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ class HomePageComponent extends React.Component {
|
|||
_self.setState({ renamingApp: true });
|
||||
try {
|
||||
await appsService.saveApp(appId, { name: newAppName });
|
||||
await this.fetchApps();
|
||||
await this.fetchApps(this.state.currentPage, this.state.currentFolder.id);
|
||||
toast.success('App name has been updated!');
|
||||
_self.setState({ renamingApp: false });
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -139,9 +139,11 @@ class LoginPageComponent extends React.Component {
|
|||
setRedirectUrlToCookie() {
|
||||
// Page is loaded inside an iframe
|
||||
const iframe = window !== window.top;
|
||||
const redirectPath = getRedirectTo(
|
||||
iframe ? new URL(window.location.href).searchParams : new URL(location.href).searchParams
|
||||
);
|
||||
|
||||
if (iframe) {
|
||||
const redirectPath = getRedirectTo();
|
||||
window.parent.postMessage(
|
||||
{
|
||||
type: 'redirectTo',
|
||||
|
|
@ -153,9 +155,6 @@ class LoginPageComponent extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
const params = iframe ? new URL(window.location.href).searchParams : new URL(location.href).searchParams;
|
||||
const redirectPath = params.get('redirectTo');
|
||||
|
||||
authenticationService.saveLoginOrganizationId(this.organizationId);
|
||||
authenticationService.saveLoginOrganizationSlug(this.organizationSlug);
|
||||
redirectPath && setCookie('redirectPath', redirectPath, iframe);
|
||||
|
|
|
|||
|
|
@ -108,10 +108,10 @@ const DynamicForm = ({
|
|||
|
||||
Object.keys(fields).length > 0 &&
|
||||
Object.keys(fields).map((key) => {
|
||||
const { type, encrypted } = fields[key];
|
||||
if ((type === 'password' || encrypted) && !(key in computedProps)) {
|
||||
const { type, encrypted, key: propertyKey } = fields[key];
|
||||
if ((type === 'password' || encrypted) && !(propertyKey in computedProps)) {
|
||||
//Editable encrypted fields only if datasource doesn't exists
|
||||
encrpytedFieldsProps[key] = {
|
||||
encrpytedFieldsProps[propertyKey] = {
|
||||
disabled: !!selectedDataSource?.id,
|
||||
};
|
||||
}
|
||||
|
|
@ -182,6 +182,7 @@ const DynamicForm = ({
|
|||
ignoreBraces = false,
|
||||
className,
|
||||
controller,
|
||||
encrypted,
|
||||
}) => {
|
||||
const source = schema?.source?.kind;
|
||||
const darkMode = localStorage.getItem('darkMode') === 'true';
|
||||
|
|
@ -191,12 +192,14 @@ const DynamicForm = ({
|
|||
switch (type) {
|
||||
case 'password':
|
||||
case 'text':
|
||||
case 'textarea':
|
||||
case 'textarea': {
|
||||
const useEncrypted =
|
||||
(options?.[key]?.encrypted !== undefined ? options?.[key].encrypted : encrypted) || type === 'password';
|
||||
return {
|
||||
type,
|
||||
placeholder: options?.[key]?.encrypted ? '**************' : description,
|
||||
placeholder: useEncrypted ? '**************' : description,
|
||||
className: `form-control${handleToggle(controller)}`,
|
||||
value: options?.[key]?.value,
|
||||
value: options?.[key]?.value || '',
|
||||
...(type === 'textarea' && { rows: rows }),
|
||||
...(helpText && { helpText }),
|
||||
onChange: (e) => optionchanged(key, e.target.value, true), //shouldNotAutoSave is true because autosave should occur during onBlur, not after each character change (in optionchanged).
|
||||
|
|
@ -204,7 +207,9 @@ const DynamicForm = ({
|
|||
isGDS,
|
||||
workspaceVariables,
|
||||
workspaceConstants: currentOrgEnvironmentConstants,
|
||||
encrypted: useEncrypted,
|
||||
};
|
||||
}
|
||||
case 'toggle':
|
||||
return {
|
||||
defaultChecked: options?.[key],
|
||||
|
|
@ -221,6 +226,7 @@ const DynamicForm = ({
|
|||
useMenuPortal: queryName ? true : false,
|
||||
styles: computeSelectStyles ? computeSelectStyles('100%') : {},
|
||||
useCustomStyles: computeSelectStyles ? true : false,
|
||||
encrypted: options?.[key]?.encrypted,
|
||||
};
|
||||
|
||||
case 'checkbox-group':
|
||||
|
|
@ -248,6 +254,7 @@ const DynamicForm = ({
|
|||
currentState,
|
||||
isRenderedAsQueryEditor,
|
||||
workspaceConstants: currentOrgEnvironmentConstants,
|
||||
encrypted: options?.[key]?.encrypted,
|
||||
};
|
||||
}
|
||||
case 'react-component-oauth-authentication':
|
||||
|
|
@ -275,6 +282,9 @@ const DynamicForm = ({
|
|||
multiple_auth_enabled: options?.multiple_auth_enabled?.value,
|
||||
optionchanged,
|
||||
workspaceConstants: currentOrgEnvironmentConstants,
|
||||
options,
|
||||
optionsChanged,
|
||||
selectedDataSource,
|
||||
};
|
||||
case 'react-component-google-sheets':
|
||||
case 'react-component-slack':
|
||||
|
|
@ -286,6 +296,7 @@ const DynamicForm = ({
|
|||
isSaving,
|
||||
selectedDataSource,
|
||||
workspaceConstants: currentOrgEnvironmentConstants,
|
||||
optionsChanged,
|
||||
};
|
||||
case 'tooljetdb-operations':
|
||||
return {
|
||||
|
|
@ -364,7 +375,12 @@ const DynamicForm = ({
|
|||
//Send old field value if editing mode disabled for encrypted fields
|
||||
const newOptions = { ...options };
|
||||
const oldFieldValue = selectedDataSource?.['options']?.[field];
|
||||
optionsChanged({ ...newOptions, [field]: oldFieldValue });
|
||||
if (oldFieldValue) {
|
||||
optionsChanged({ ...newOptions, [field]: oldFieldValue });
|
||||
} else {
|
||||
delete newOptions[field];
|
||||
optionsChanged({ ...newOptions });
|
||||
}
|
||||
}
|
||||
setComputedProps({
|
||||
...computedProps,
|
||||
|
|
@ -378,7 +394,7 @@ const DynamicForm = ({
|
|||
return (
|
||||
<div className={`${isHorizontalLayout ? '' : 'row'}`}>
|
||||
{Object.keys(obj).map((key) => {
|
||||
const { label, type, encrypted, className } = obj[key];
|
||||
const { label, type, encrypted, className, key: propertyKey } = obj[key];
|
||||
const Element = getElement(type);
|
||||
const isSpecificComponent = ['tooljetdb-operations'].includes(type);
|
||||
|
||||
|
|
@ -415,9 +431,9 @@ const DynamicForm = ({
|
|||
variant="tertiary"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
onClick={(event) => handleEncryptedFieldsToggle(event, key)}
|
||||
onClick={(event) => handleEncryptedFieldsToggle(event, propertyKey)}
|
||||
>
|
||||
{computedProps?.[key]?.['disabled'] ? 'Edit' : 'Cancel'}
|
||||
{computedProps?.[propertyKey]?.['disabled'] ? 'Edit' : 'Cancel'}
|
||||
</ButtonSolid>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -444,7 +460,7 @@ const DynamicForm = ({
|
|||
>
|
||||
<Element
|
||||
{...getElementProps(obj[key])}
|
||||
{...computedProps[key]}
|
||||
{...computedProps[propertyKey]}
|
||||
data-cy={`${String(label).toLocaleLowerCase().replace(/\s+/g, '-')}-text-field`}
|
||||
//to be removed after whole ui is same
|
||||
isHorizontalLayout={isHorizontalLayout}
|
||||
|
|
|
|||
55
frontend/src/_components/EncyrptedFieldWrapper.jsx
Normal file
55
frontend/src/_components/EncyrptedFieldWrapper.jsx
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import React, { useState } from 'react';
|
||||
import { ButtonSolid } from './AppButton';
|
||||
|
||||
export default function EncryptedFieldWrapper({
|
||||
children,
|
||||
options,
|
||||
selectedDataSource,
|
||||
optionchanged,
|
||||
optionsChanged,
|
||||
name,
|
||||
label,
|
||||
encrypted = true,
|
||||
}) {
|
||||
const [disabled, setDisabled] = useState(true);
|
||||
|
||||
const handleEncryptedFieldsToggle = (field) => {
|
||||
const isEditing = disabled;
|
||||
if (isEditing) {
|
||||
optionchanged(field, '');
|
||||
} else {
|
||||
//Send old field value if editing mode disabled for encrypted fields
|
||||
const newOptions = { ...options };
|
||||
const oldFieldValue = selectedDataSource?.['options']?.[field];
|
||||
optionsChanged({ ...newOptions, [field]: oldFieldValue });
|
||||
}
|
||||
setDisabled(!isEditing);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="d-flex align-items-center mt-3">
|
||||
<label className="form-label text-muted">{label}</label>
|
||||
<div className="mx-1 col">
|
||||
<ButtonSolid
|
||||
className="datasource-edit-btn mb-2"
|
||||
type="a"
|
||||
variant="tertiary"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
onClick={() => handleEncryptedFieldsToggle(name)}
|
||||
>
|
||||
{disabled ? 'Edit' : 'Cancel'}
|
||||
</ButtonSolid>
|
||||
</div>
|
||||
<div className="col-auto mb-2">
|
||||
<small className="text-green mx-2">
|
||||
<img className="mx-2 encrypted-icon" src="assets/images/icons/padlock.svg" width="12" height="12" />
|
||||
Encrypted
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{React.cloneElement(children, { encrypted, disabled, placeholder: '**************' })}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { ERROR_MESSAGES } from '@/_helpers/constants';
|
||||
import { redirectToDashboard } from '@/_helpers/routes';
|
||||
import { redirectToDashboard, getPrivateRoute, getSubpath } from '@/_helpers/routes';
|
||||
import React from 'react';
|
||||
import { Modal } from 'react-bootstrap';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
|
@ -13,16 +13,28 @@ export default function ErrorPage({ darkMode }) {
|
|||
|
||||
if (!errorMsg) redirectToDashboard();
|
||||
|
||||
const searchParams = new URLSearchParams(location.search);
|
||||
const appSlug = searchParams.get('appSlug');
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
||||
<ErrorModal errorMsg={errorMsg} show={true} darkMode={darkMode} />
|
||||
<ErrorModal errorMsg={errorMsg} appSlug={appSlug} show={true} darkMode={darkMode} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const ErrorModal = ({ errorMsg, ...props }) => {
|
||||
export const ErrorModal = ({ errorMsg, appSlug, ...props }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Redirect to edit app URL in a new tab
|
||||
const openAppEditorInNewTab = () => {
|
||||
const subpath = getSubpath();
|
||||
const path = subpath
|
||||
? `${subpath}${getPrivateRoute('editor', { slug: appSlug })}`
|
||||
: getPrivateRoute('editor', { slug: appSlug });
|
||||
window.open(path, '_blank');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="custom-backdrop">
|
||||
<Modal
|
||||
|
|
@ -86,8 +98,17 @@ export const ErrorModal = ({ errorMsg, ...props }) => {
|
|||
{t('globals.workspace-modal.continue-btn', 'Retry')}
|
||||
</button>
|
||||
)}
|
||||
{appSlug && (
|
||||
<button
|
||||
className={'btn btn-primary action-btn'}
|
||||
onClick={() => openAppEditorInNewTab()}
|
||||
data-cy="open-app-button"
|
||||
>
|
||||
{t('globals.workspace-modal.continue-btn', 'Open app')}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
className={errorMsg?.retry ? 'btn btn-primary' : 'btn btn-primary action-btn'}
|
||||
className={errorMsg?.retry || appSlug ? 'btn btn-primary' : 'btn btn-primary action-btn'}
|
||||
onClick={() => redirectToDashboard()}
|
||||
data-cy="back-to-home-button"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -9,32 +9,40 @@ import _ from 'lodash';
|
|||
|
||||
export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => {
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
const [fields, setFields] = useState({ name: { value: '', error: '' }, slug: { value: null, error: '' } });
|
||||
const [name, setName] = useState({ value: null, error: '' });
|
||||
const [slug, setSlug] = useState({ value: null, error: '' });
|
||||
const [slugProgress, setSlugProgress] = useState(false);
|
||||
const [workspaceNameProgress, setWorkspaceNameProgress] = useState(false);
|
||||
const [isDisabled, setDisabled] = useState(true);
|
||||
const [isNameDisabled, setNameDisabled] = useState(true);
|
||||
const [isSlugDisabled, setSlugDisabled] = useState(true);
|
||||
const darkMode = localStorage.getItem('darkMode') === 'true';
|
||||
const { t } = useTranslation();
|
||||
|
||||
const createOrganization = () => {
|
||||
let emptyError = false;
|
||||
const fieldsTemp = fields;
|
||||
Object.keys(fields).map((key) => {
|
||||
if (!fields?.[key]?.value?.trim()) {
|
||||
fieldsTemp[key] = {
|
||||
error: `Workspace ${key} can't be empty`,
|
||||
};
|
||||
|
||||
[name, slug].map((field, index) => {
|
||||
if (!field?.value?.trim()) {
|
||||
index === 0
|
||||
? setName({
|
||||
...name,
|
||||
error: {
|
||||
error: `Workspace name can't be empty`,
|
||||
},
|
||||
})
|
||||
: setSlug({ ...slug, error: `Workspace slug can't be empty` });
|
||||
emptyError = true;
|
||||
}
|
||||
});
|
||||
setFields({ ...fields, ...fieldsTemp });
|
||||
const errorFound = !_.isEmpty(name.error) || !_.isEmpty(slug.error);
|
||||
|
||||
if (!emptyError && !Object.keys(fields).find((key) => !_.isEmpty(fields[key].error))) {
|
||||
if (!emptyError && !errorFound) {
|
||||
const slugValue = slug.value;
|
||||
setIsCreating(true);
|
||||
organizationService.createOrganization({ name: fields['name'].value, slug: fields['slug'].value }).then(
|
||||
organizationService.createOrganization({ name: name.value, slug: slugValue }).then(
|
||||
() => {
|
||||
setIsCreating(false);
|
||||
const newPath = appendWorkspaceId(fields['slug'].value, location.pathname, true);
|
||||
const newPath = appendWorkspaceId(slugValue, location.pathname, true);
|
||||
window.history.replaceState(null, null, newPath);
|
||||
window.location.reload();
|
||||
},
|
||||
|
|
@ -47,13 +55,18 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => {
|
|||
};
|
||||
|
||||
const handleInputChange = async (value, field) => {
|
||||
setFields({
|
||||
...fields,
|
||||
[field]: {
|
||||
...fields[field],
|
||||
if (field === 'slug') {
|
||||
setSlug({
|
||||
...slug,
|
||||
error: null,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
if (field === 'name') {
|
||||
setName({
|
||||
...name,
|
||||
error: null,
|
||||
});
|
||||
}
|
||||
let error = validateName(
|
||||
value,
|
||||
`Workspace ${field}`,
|
||||
|
|
@ -79,20 +92,22 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => {
|
|||
}
|
||||
}
|
||||
|
||||
setFields({
|
||||
...fields,
|
||||
[field]: {
|
||||
value,
|
||||
error: error?.errorMsg,
|
||||
},
|
||||
});
|
||||
const disabled = !error?.status;
|
||||
const updatedValue = {
|
||||
value,
|
||||
error: error?.errorMsg,
|
||||
};
|
||||
|
||||
const otherInputErrors = Object.keys(fields).find(
|
||||
(key) => (key !== field && !_.isEmpty(fields[key].error)) || (key !== field && _.isEmpty(fields[key].value))
|
||||
);
|
||||
setDisabled(!error?.status || otherInputErrors);
|
||||
field === 'slug' && setSlugProgress(false);
|
||||
field === 'name' && setWorkspaceNameProgress(false);
|
||||
if (field === 'slug') {
|
||||
setSlug(updatedValue);
|
||||
setSlugDisabled(disabled);
|
||||
setSlugProgress(false);
|
||||
}
|
||||
if (field === 'name') {
|
||||
setName(updatedValue);
|
||||
setNameDisabled(disabled);
|
||||
setWorkspaceNameProgress(false);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -104,16 +119,25 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => {
|
|||
};
|
||||
|
||||
const closeModal = () => {
|
||||
setFields({ name: { value: '', error: '' }, slug: { value: null, error: '' } });
|
||||
/* reseting states */
|
||||
setName({ value: null, error: '' });
|
||||
setSlug({ value: null, error: '' });
|
||||
setShowCreateOrg(false);
|
||||
setDisabled(true);
|
||||
setNameDisabled(true);
|
||||
setSlugDisabled(true);
|
||||
};
|
||||
|
||||
const delayedFieldChange = _.debounce(async (value, field) => {
|
||||
field === 'name' && setWorkspaceNameProgress(true);
|
||||
field === 'slug' && setSlugProgress(true);
|
||||
await handleInputChange(value, field);
|
||||
}, 500);
|
||||
const delayedSlugChange = _.debounce(async (value) => {
|
||||
setSlugProgress(true);
|
||||
await handleInputChange(value, 'slug');
|
||||
}, 300);
|
||||
|
||||
const delayedNameChange = _.debounce(async (value) => {
|
||||
setWorkspaceNameProgress(true);
|
||||
await handleInputChange(value, 'name');
|
||||
}, 300);
|
||||
|
||||
const isDisabled = isCreating || isNameDisabled || isSlugDisabled || slugProgress || workspaceNameProgress;
|
||||
|
||||
return (
|
||||
<AlertDialog
|
||||
|
|
@ -129,9 +153,9 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => {
|
|||
type="text"
|
||||
onChange={async (e) => {
|
||||
e.persist();
|
||||
await delayedFieldChange(e.target.value, 'name');
|
||||
await delayedNameChange(e.target.value);
|
||||
}}
|
||||
className={`form-control ${fields['name']?.error ? 'is-invalid' : 'is-valid'}`}
|
||||
className={`form-control ${name?.error ? 'is-invalid' : 'is-valid'}`}
|
||||
placeholder={t('header.organization.workspaceName', 'Workspace name')}
|
||||
disabled={isCreating}
|
||||
onKeyDown={handleKeyDown}
|
||||
|
|
@ -139,9 +163,9 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => {
|
|||
data-cy="workspace-name-input-field"
|
||||
autoFocus
|
||||
/>
|
||||
{fields['name']?.error ? (
|
||||
{name?.error ? (
|
||||
<label className="label tj-input-error" data-cy="workspace-error-label">
|
||||
{fields['name']?.error || ''}
|
||||
{name?.error || ''}
|
||||
</label>
|
||||
) : (
|
||||
<label className="label label-info" data-cy="workspace-name-info-label">
|
||||
|
|
@ -155,18 +179,18 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => {
|
|||
<label data-cy="slug-input-label">Unique workspace slug</label>
|
||||
<input
|
||||
type="text"
|
||||
className={`form-control ${fields['slug']?.error ? 'is-invalid' : 'is-valid'}`}
|
||||
className={`form-control ${slug?.error ? 'is-invalid' : 'is-valid'}`}
|
||||
placeholder={t('header.organization.workspaceSlug', 'Unique workspace slug')}
|
||||
disabled={isCreating}
|
||||
maxLength={50}
|
||||
onChange={async (e) => {
|
||||
e.persist();
|
||||
await delayedFieldChange(e.target.value, 'slug');
|
||||
await delayedSlugChange(e.target.value);
|
||||
}}
|
||||
data-cy="workspace-slug-input-field"
|
||||
autoFocusfields
|
||||
/>
|
||||
{!slugProgress && fields['slug'].value !== null && !fields['slug'].error && (
|
||||
{!slugProgress && slug.value !== null && !slug.error && (
|
||||
<div className="icon-container">
|
||||
<svg width="15" height="10" viewBox="0 0 15 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
|
|
@ -178,11 +202,11 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => {
|
|||
</svg>
|
||||
</div>
|
||||
)}
|
||||
{fields['slug']?.error ? (
|
||||
{slug?.error ? (
|
||||
<label className="label tj-input-error" data-cy="input-label-error">
|
||||
{fields['slug']?.error || ''}
|
||||
{slug?.error || ''}
|
||||
</label>
|
||||
) : fields['slug'].value && !slugProgress ? (
|
||||
) : slug.value && !slugProgress ? (
|
||||
<label className="label label-success" data-cy="slug-sucess-label">{`Slug accepted!`}</label>
|
||||
) : (
|
||||
<label
|
||||
|
|
@ -197,7 +221,7 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => {
|
|||
<label data-cy="workspace-link-label">Workspace link</label>
|
||||
<div className={`tj-text-input break-all ${darkMode ? 'dark' : ''}`} data-cy="slug-field">
|
||||
{!slugProgress ? (
|
||||
`${getHostURL()}/${fields['slug']?.value || '<workspace-slug>'}`
|
||||
`${getHostURL()}/${slug?.value || '<workspace-slug>'}`
|
||||
) : (
|
||||
<div className="d-flex gap-2">
|
||||
<div class="spinner-border text-secondary workspace-spinner" role="status">
|
||||
|
|
@ -208,7 +232,7 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => {
|
|||
)}
|
||||
</div>
|
||||
<label className="label label-success label-updated" data-cy="slug-error-label">
|
||||
{fields['slug'].value && !fields['slug'].error && !slugProgress ? `Link updated successfully!` : ''}
|
||||
{slug.value && !slug.error && !slugProgress ? `Link updated successfully!` : ''}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -218,7 +242,7 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => {
|
|||
{t('globals.cancel', 'Cancel')}
|
||||
</ButtonSolid>
|
||||
<ButtonSolid
|
||||
disabled={isCreating || isDisabled || slugProgress || workspaceNameProgress}
|
||||
disabled={isDisabled}
|
||||
onClick={createOrganization}
|
||||
data-cy="create-workspace-button"
|
||||
isLoading={isCreating}
|
||||
|
|
|
|||
|
|
@ -10,52 +10,56 @@ import _ from 'lodash';
|
|||
|
||||
export const EditOrganization = ({ showEditOrg, setShowEditOrg, currentValue }) => {
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
const [fields, setFields] = useState({ name: { value: '', error: '' }, slug: { value: null, error: '' } });
|
||||
const [name, setName] = useState({ value: '', error: '' });
|
||||
const [slug, setSlug] = useState({ value: '', error: '' });
|
||||
const [slugProgress, setSlugProgress] = useState(false);
|
||||
const [workspaceNameProgress, setWorkspaceNameProgress] = useState(false);
|
||||
const [isDisabled, setDisabled] = useState(true);
|
||||
const [isNameDisabled, setNameDisabled] = useState(true);
|
||||
const [isSlugDisabled, setSlugDisabled] = useState(true);
|
||||
const { t } = useTranslation();
|
||||
const darkMode = localStorage.getItem('darkMode') === 'true';
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
setFields({
|
||||
name: {
|
||||
value: currentValue?.name,
|
||||
},
|
||||
slug: {
|
||||
value: currentValue?.slug,
|
||||
},
|
||||
}),
|
||||
() => {
|
||||
setName({
|
||||
value: currentValue?.name,
|
||||
});
|
||||
setSlug({
|
||||
value: currentValue?.slug,
|
||||
});
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[currentValue]
|
||||
);
|
||||
|
||||
const editOrganization = () => {
|
||||
let emptyError = false;
|
||||
const fieldsTemp = fields;
|
||||
Object.keys(fields).map((key) => {
|
||||
if (!fields?.[key]?.value?.trim()) {
|
||||
fieldsTemp[key] = {
|
||||
error: `Workspace ${key} can't be empty`,
|
||||
};
|
||||
|
||||
[name, slug].map((field, index) => {
|
||||
if (!field?.value?.trim()) {
|
||||
index === 0
|
||||
? setName({
|
||||
...name,
|
||||
error: `Workspace name can't be empty`,
|
||||
})
|
||||
: setSlug({ ...slug, error: `Workspace slug can't be empty` });
|
||||
emptyError = true;
|
||||
}
|
||||
});
|
||||
setFields({ ...fields, ...fieldsTemp });
|
||||
const errorFound = !_.isEmpty(name.error) || !_.isEmpty(slug.error);
|
||||
|
||||
if (!emptyError && !Object.keys(fields).find((key) => !_.isEmpty(fields[key].error))) {
|
||||
if (!emptyError && !errorFound) {
|
||||
setIsCreating(true);
|
||||
const data = {
|
||||
...(fields?.name?.value && fields?.name?.value !== currentValue?.name && { name: fields.name.value.trim() }),
|
||||
...(fields?.slug?.value && fields?.slug?.value !== currentValue?.slug && { slug: fields.slug.value.trim() }),
|
||||
...(name?.value && name?.value !== currentValue?.name && { name: name.value.trim() }),
|
||||
...(slug?.value && slug?.value !== currentValue?.slug && { slug: slug.value.trim() }),
|
||||
};
|
||||
organizationService.editOrganization(data).then(
|
||||
() => {
|
||||
toast.success('Workspace updated');
|
||||
setIsCreating(false);
|
||||
setShowEditOrg(false);
|
||||
const newPath = appendWorkspaceId(fields['slug'].value, location.pathname, true);
|
||||
const newPath = appendWorkspaceId(slug.value, location.pathname, true);
|
||||
window.history.replaceState(null, null, newPath);
|
||||
window.location.reload();
|
||||
},
|
||||
|
|
@ -71,13 +75,18 @@ export const EditOrganization = ({ showEditOrg, setShowEditOrg, currentValue })
|
|||
const trimmedValue = value?.trim();
|
||||
const prevValue = field === 'name' ? currentValue?.name : currentValue?.slug;
|
||||
//reset fields
|
||||
setFields({
|
||||
...fields,
|
||||
[field]: {
|
||||
...fields[field],
|
||||
if (field === 'slug') {
|
||||
setSlug({
|
||||
...slug,
|
||||
error: null,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
if (field === 'name') {
|
||||
setName({
|
||||
...name,
|
||||
error: null,
|
||||
});
|
||||
}
|
||||
let error = validateName(
|
||||
value,
|
||||
`Workspace ${field}`,
|
||||
|
|
@ -103,32 +112,32 @@ export const EditOrganization = ({ showEditOrg, setShowEditOrg, currentValue })
|
|||
}
|
||||
}
|
||||
|
||||
setFields({
|
||||
...fields,
|
||||
[field]: {
|
||||
value,
|
||||
error: error?.errorMsg,
|
||||
},
|
||||
});
|
||||
|
||||
/* Checking for if the user entered the same value or not */
|
||||
let isValueTheSame = false;
|
||||
if (error?.status) {
|
||||
if (field === 'name') {
|
||||
isValueTheSame = trimmedValue === currentValue?.name && fields?.slug?.value === currentValue?.slug;
|
||||
isValueTheSame = trimmedValue === currentValue?.name && slug?.value === currentValue?.slug;
|
||||
} else {
|
||||
isValueTheSame = trimmedValue === currentValue?.slug && fields?.name?.value === currentValue?.name;
|
||||
isValueTheSame = trimmedValue === currentValue?.slug && name?.value === currentValue?.name;
|
||||
}
|
||||
}
|
||||
|
||||
/* recheck if the rest of fields are valid or not */
|
||||
const otherInputErrors = Object.keys(fields).find(
|
||||
(key) => (key !== field && !_.isEmpty(fields[key].error)) || (key !== field && _.isEmpty(fields[key].value))
|
||||
);
|
||||
const disabled = isValueTheSame || !error?.status;
|
||||
const updatedValue = {
|
||||
value,
|
||||
error: error?.errorMsg,
|
||||
};
|
||||
|
||||
setDisabled(isValueTheSame || !error?.status || otherInputErrors);
|
||||
field === 'slug' && setSlugProgress(false);
|
||||
field === 'name' && setWorkspaceNameProgress(false);
|
||||
if (field === 'slug') {
|
||||
setSlug(updatedValue);
|
||||
setSlugDisabled(disabled);
|
||||
setSlugProgress(false);
|
||||
}
|
||||
if (field === 'name') {
|
||||
setName(updatedValue);
|
||||
setNameDisabled(disabled);
|
||||
setWorkspaceNameProgress(false);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -140,17 +149,25 @@ export const EditOrganization = ({ showEditOrg, setShowEditOrg, currentValue })
|
|||
};
|
||||
|
||||
const closeModal = () => {
|
||||
setFields({ name: { value: currentValue?.name, error: '' }, slug: { value: currentValue?.slug, error: '' } });
|
||||
setName({ value: currentValue?.name, error: '' });
|
||||
setSlug({ value: currentValue?.slug, error: '' });
|
||||
setShowEditOrg(false);
|
||||
setDisabled(true);
|
||||
setSlugDisabled(true);
|
||||
setNameDisabled(true);
|
||||
};
|
||||
|
||||
const delayedFieldChange = _.debounce(async (value, field) => {
|
||||
field === 'name' && setWorkspaceNameProgress(true);
|
||||
field === 'slug' && setSlugProgress(true);
|
||||
await handleInputChange(value, field);
|
||||
const delayedSlugChange = _.debounce(async (value) => {
|
||||
setSlugProgress(true);
|
||||
await handleInputChange(value, 'slug');
|
||||
}, 500);
|
||||
|
||||
const delayedNameChange = _.debounce(async (value) => {
|
||||
setWorkspaceNameProgress(true);
|
||||
await handleInputChange(value, 'name');
|
||||
}, 500);
|
||||
|
||||
const isDisabled = isCreating || isNameDisabled || isSlugDisabled || slugProgress || workspaceNameProgress;
|
||||
|
||||
return (
|
||||
<AlertDialog
|
||||
show={showEditOrg}
|
||||
|
|
@ -165,20 +182,20 @@ export const EditOrganization = ({ showEditOrg, setShowEditOrg, currentValue })
|
|||
type="text"
|
||||
onChange={async (e) => {
|
||||
e.persist();
|
||||
await delayedFieldChange(e.target.value, 'name');
|
||||
await delayedNameChange(e.target.value);
|
||||
}}
|
||||
onKeyDown={handleKeyDown}
|
||||
className={`form-control ${fields['name']?.error ? 'is-invalid' : 'is-valid'}`}
|
||||
className={`form-control ${name?.error ? 'is-invalid' : 'is-valid'}`}
|
||||
placeholder={t('header.organization.workspaceName', 'Workspace name')}
|
||||
disabled={isCreating}
|
||||
maxLength={50}
|
||||
defaultValue={fields['name']?.value}
|
||||
defaultValue={name?.value}
|
||||
data-cy="workspace-name-input-field"
|
||||
autoFocus
|
||||
/>
|
||||
{fields['name']?.error ? (
|
||||
{name?.error ? (
|
||||
<label className="label tj-input-error" data-cy="workspace-error-label">
|
||||
{fields['name']?.error || ''}
|
||||
{name?.error || ''}
|
||||
</label>
|
||||
) : (
|
||||
<label className="label label-info" data-cy="workspace-name-info-label">
|
||||
|
|
@ -192,20 +209,20 @@ export const EditOrganization = ({ showEditOrg, setShowEditOrg, currentValue })
|
|||
<label data-cy="slug-input-label">Unique workspace slug</label>
|
||||
<input
|
||||
type="text"
|
||||
className={`form-control ${fields['slug']?.error ? 'is-invalid' : 'is-valid'}`}
|
||||
className={`form-control ${slug?.error ? 'is-invalid' : 'is-valid'}`}
|
||||
placeholder={t('header.organization.workspaceSlug', 'Unique workspace slug')}
|
||||
disabled={isCreating}
|
||||
maxLength={50}
|
||||
onChange={async (e) => {
|
||||
e.persist();
|
||||
await delayedFieldChange(e.target.value, 'slug');
|
||||
await delayedSlugChange(e.target.value);
|
||||
}}
|
||||
onKeyDown={handleKeyDown}
|
||||
defaultValue={fields['slug']?.value}
|
||||
defaultValue={slug?.value}
|
||||
data-cy="workspace-slug-input-field"
|
||||
autoFocusfields
|
||||
/>
|
||||
{!slugProgress && fields?.['slug']?.value !== currentValue?.slug && !fields['slug'].error && (
|
||||
{!slugProgress && slug?.value !== currentValue?.slug && !slug.error && (
|
||||
<div className="icon-container">
|
||||
<svg width="15" height="10" viewBox="0 0 15 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
|
|
@ -217,11 +234,11 @@ export const EditOrganization = ({ showEditOrg, setShowEditOrg, currentValue })
|
|||
</svg>
|
||||
</div>
|
||||
)}
|
||||
{fields['slug']?.error ? (
|
||||
{slug?.error ? (
|
||||
<label className="label tj-input-error" data-cy="input-label-error">
|
||||
{fields['slug']?.error || ''}
|
||||
{slug?.error || ''}
|
||||
</label>
|
||||
) : fields?.['slug']?.value !== currentValue?.slug && !slugProgress ? (
|
||||
) : slug?.value !== currentValue?.slug && !slugProgress ? (
|
||||
<label className="label label-success" data-cy="sucess-label">{`Slug accepted!`}</label>
|
||||
) : (
|
||||
<label
|
||||
|
|
@ -236,7 +253,7 @@ export const EditOrganization = ({ showEditOrg, setShowEditOrg, currentValue })
|
|||
<label data-cy="workspace-link-label">Workspace link</label>
|
||||
<div className={`tj-text-input break-all ${darkMode ? 'dark' : ''}`} data-cy="slug-field">
|
||||
{!slugProgress ? (
|
||||
`${getHostURL()}/${fields['slug']?.value || '<workspace-slug>'}`
|
||||
`${getHostURL()}/${slug?.value || '<workspace-slug>'}`
|
||||
) : (
|
||||
<div className="d-flex gap-2">
|
||||
<div class="spinner-border text-secondary workspace-spinner" role="status">
|
||||
|
|
@ -247,10 +264,7 @@ export const EditOrganization = ({ showEditOrg, setShowEditOrg, currentValue })
|
|||
)}
|
||||
</div>
|
||||
<label className="label label-success label-updated" data-cy="slug-success-label">
|
||||
{!slugProgress &&
|
||||
fields['slug'].value &&
|
||||
!fields['slug'].error &&
|
||||
fields?.['slug']?.value !== currentValue?.slug
|
||||
{!slugProgress && slug.value && !slug.error && slug?.value !== currentValue?.slug
|
||||
? `Link updated successfully!`
|
||||
: ''}
|
||||
</label>
|
||||
|
|
@ -261,12 +275,7 @@ export const EditOrganization = ({ showEditOrg, setShowEditOrg, currentValue })
|
|||
<ButtonSolid variant="secondary" onClick={closeModal} className="cancel-btn" data-cy="cancel-button">
|
||||
{t('globals.cancel', 'Cancel')}
|
||||
</ButtonSolid>
|
||||
<ButtonSolid
|
||||
isLoading={isCreating}
|
||||
disabled={isCreating || isDisabled || slugProgress || workspaceNameProgress}
|
||||
onClick={editOrganization}
|
||||
data-cy="save-button"
|
||||
>
|
||||
<ButtonSolid isLoading={isCreating} disabled={isDisabled} onClick={editOrganization} data-cy="save-button">
|
||||
{t('globals.save', 'Save')}
|
||||
</ButtonSolid>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -90,16 +90,15 @@ export const PrivateRoute = ({ children }) => {
|
|||
(session?.authentication_status === false || session?.authentication_failed) &&
|
||||
!location.pathname.startsWith('/applications/')
|
||||
) {
|
||||
// not logged in so redirect to login page with the return url'
|
||||
return (
|
||||
<Navigate
|
||||
to={{
|
||||
pathname: `/login${getWorkspaceId() ? `/${getWorkspaceId()}` : ''}`,
|
||||
search: `?redirectTo=${excludeWorkspaceIdFromURL(location.pathname)}`,
|
||||
state: { from: location },
|
||||
}}
|
||||
replace
|
||||
/>
|
||||
const redirectTo = `${excludeWorkspaceIdFromURL(location.pathname)}${location.search}`;
|
||||
const workspaceId = getWorkspaceId();
|
||||
return navigate(
|
||||
{
|
||||
pathname: `/login${workspaceId ? `/${workspaceId}` : ''}`,
|
||||
search: `?redirectTo=${redirectTo}`,
|
||||
state: { from: location },
|
||||
},
|
||||
{ replace: true }
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -110,6 +109,8 @@ export const PrivateRoute = ({ children }) => {
|
|||
export const AdminRoute = ({ children }) => {
|
||||
const [session, setSession] = React.useState(authenticationService.currentSessionValue);
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
const subject = authenticationService.currentSession.subscribe((newSession) => {
|
||||
setSession(newSession);
|
||||
|
|
@ -120,17 +121,16 @@ export const AdminRoute = ({ children }) => {
|
|||
|
||||
// authorised so return component
|
||||
if (session?.group_permissions) {
|
||||
// TODO-check: do we really need this route while we are having the integration menu item.?
|
||||
//check: [Marketplace route]
|
||||
if (!session?.admin) {
|
||||
return (
|
||||
<Navigate
|
||||
to={{
|
||||
pathname: '/',
|
||||
search: `?redirectTo=${location.pathname}`,
|
||||
state: { from: location },
|
||||
}}
|
||||
replace
|
||||
/>
|
||||
return navigate(
|
||||
{
|
||||
pathname: '/',
|
||||
search: `?redirectTo=${location.pathname}`,
|
||||
state: { from: location },
|
||||
},
|
||||
{ replace: true }
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -138,15 +138,14 @@ export const AdminRoute = ({ children }) => {
|
|||
} else {
|
||||
if (session?.authentication_status === false && !location.pathname.startsWith('/applications/')) {
|
||||
// not logged in so redirect to login page with the return url'
|
||||
return (
|
||||
<Navigate
|
||||
to={{
|
||||
pathname: `/login${getWorkspaceId() ? `/${getWorkspaceId()}` : ''}`,
|
||||
search: `?redirectTo=${location.pathname}`,
|
||||
state: { from: location },
|
||||
}}
|
||||
replace
|
||||
/>
|
||||
const workspaceId = getWorkspaceId();
|
||||
return navigate(
|
||||
{
|
||||
pathname: `/login${workspaceId ? `/${workspaceId}` : ''}`,
|
||||
search: `?redirectTo=${location.pathname}`,
|
||||
state: { from: location },
|
||||
},
|
||||
{ replace: true }
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,17 @@ import { toast } from 'react-hot-toast';
|
|||
import Input from '@/_ui/Input';
|
||||
import Radio from '@/_ui/Radio';
|
||||
import Button from '@/_ui/Button';
|
||||
import EncryptedFieldWrapper from './EncyrptedFieldWrapper';
|
||||
|
||||
const Zendesk = ({ optionchanged, createDataSource, options, isSaving, selectedDataSource, workspaceConstants }) => {
|
||||
const Zendesk = ({
|
||||
optionchanged,
|
||||
createDataSource,
|
||||
options,
|
||||
isSaving,
|
||||
selectedDataSource,
|
||||
workspaceConstants,
|
||||
optionsChanged,
|
||||
}) => {
|
||||
const [authStatus, setAuthStatus] = useState(null);
|
||||
|
||||
function authZendesk() {
|
||||
|
|
@ -60,20 +69,22 @@ const Zendesk = ({ optionchanged, createDataSource, options, isSaving, selectedD
|
|||
/>
|
||||
</div>
|
||||
<div className="col-md-12 mb-2">
|
||||
<label className="form-label text-muted mt-3">
|
||||
Client Secret
|
||||
<small className="text-green mx-2">
|
||||
<img className="mx-2 encrypted-icon" src="assets/images/icons/padlock.svg" width="12" height="12" />
|
||||
Encrypted
|
||||
</small>
|
||||
</label>
|
||||
<Input
|
||||
type="password"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('client_secret', e.target.value)}
|
||||
value={options?.client_secret?.value}
|
||||
workspaceConstants={workspaceConstants}
|
||||
/>
|
||||
<EncryptedFieldWrapper
|
||||
options={options}
|
||||
selectedDataSource={selectedDataSource}
|
||||
optionchanged={optionchanged}
|
||||
optionsChanged={optionsChanged}
|
||||
name="client_secret"
|
||||
label="Client Secret"
|
||||
>
|
||||
<Input
|
||||
type="password"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('client_secret', e.target.value)}
|
||||
value={options?.client_secret?.value}
|
||||
workspaceConstants={workspaceConstants}
|
||||
/>
|
||||
</EncryptedFieldWrapper>
|
||||
</div>
|
||||
|
||||
<div className="col-md-12">
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ export const ERROR_TYPES = {
|
|||
|
||||
export const ERROR_MESSAGES = {
|
||||
'url-unavailable': {
|
||||
title: 'URL unavailable',
|
||||
title: 'App URL Unavailable',
|
||||
message:
|
||||
'This URL is not accessible because it has not been released yet. Please either release it or contact admin for access.',
|
||||
'The app URL is currently unavailable because the app has not been released. Please either release it or contact admin for access.',
|
||||
cta: 'Back to home page',
|
||||
queryParams: [],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import _ from 'lodash';
|
|||
import queryString from 'query-string';
|
||||
import { ERROR_TYPES } from './constants';
|
||||
|
||||
/* appId, versionId are olny for old preview URLs */
|
||||
export const handleAppAccess = (componentType, slug, version_id) => {
|
||||
/* appId, versionId are only for old preview URLs */
|
||||
export const handleAppAccess = async (componentType, slug, version_id) => {
|
||||
const previewQueryParams = getPreviewQueryParams();
|
||||
const isOldLocalPreview = version_id ? true : false;
|
||||
const isLocalPreview = !_.isEmpty(previewQueryParams);
|
||||
|
|
@ -26,9 +26,12 @@ export const handleAppAccess = (componentType, slug, version_id) => {
|
|||
});
|
||||
} else {
|
||||
/* Released app link [launch/sharable link] */
|
||||
return appsService.validateReleasedApp(slug).catch((error) => {
|
||||
handleError(componentType, error, redirectPath);
|
||||
});
|
||||
try {
|
||||
return await appsService.validateReleasedApp(slug);
|
||||
} catch (errorResponse) {
|
||||
const editPermission = errorResponse?.error?.editPermission;
|
||||
handleError(componentType, errorResponse, redirectPath, editPermission, slug);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -45,7 +48,7 @@ const switchOrganization = (componentType, orgId, redirectPath) => {
|
|||
);
|
||||
};
|
||||
|
||||
const handleError = (componentType, error, redirectPath) => {
|
||||
const handleError = (componentType, error, redirectPath, editPermission, appSlug = null) => {
|
||||
try {
|
||||
if (error?.data) {
|
||||
const statusCode = error.data?.statusCode;
|
||||
|
|
@ -70,7 +73,11 @@ const handleError = (componentType, error, redirectPath) => {
|
|||
}
|
||||
case 501: {
|
||||
/* Restrict the users from accessing the sharable app url if the app is not released */
|
||||
redirectToErrorPage(ERROR_TYPES.URL_UNAVAILABLE, {});
|
||||
if (editPermission === true && appSlug) {
|
||||
redirectToErrorPage(ERROR_TYPES.URL_UNAVAILABLE, { appSlug });
|
||||
} else {
|
||||
redirectToErrorPage(ERROR_TYPES.URL_UNAVAILABLE, {});
|
||||
}
|
||||
return;
|
||||
}
|
||||
case 404: {
|
||||
|
|
|
|||
|
|
@ -157,9 +157,12 @@ export const getRedirectURL = (path) => {
|
|||
return redirectLoc;
|
||||
};
|
||||
|
||||
export const getRedirectTo = () => {
|
||||
const params = new URL(window.location.href).searchParams;
|
||||
return params.get('redirectTo') || '/';
|
||||
export const getRedirectTo = (paramObj) => {
|
||||
const params = paramObj || new URL(window.location.href).searchParams;
|
||||
let combined = Array.from(params.entries())
|
||||
.map((param) => param.join('='))
|
||||
.join('&');
|
||||
return params.get('redirectTo') ? combined.replace('redirectTo=', '') : '/';
|
||||
};
|
||||
|
||||
export const getPreviewQueryParams = () => {
|
||||
|
|
@ -169,14 +172,21 @@ export const getPreviewQueryParams = () => {
|
|||
};
|
||||
};
|
||||
|
||||
export const getRedirectToWithParams = () => {
|
||||
export const getRedirectToWithParams = (shouldAddCustomParams = false) => {
|
||||
const pathname = getPathname(null, true);
|
||||
const queryParams = pathname.includes('/applications/') ? getPreviewQueryParams() : {};
|
||||
const query = !_.isEmpty(queryParams) ? queryString.stringify(queryParams) : '';
|
||||
return `${pathname}${!_.isEmpty(query) ? `?${query}` : ''}`;
|
||||
let query = pathname.includes('/applications/') ? constructQueryParamsInOrder(shouldAddCustomParams) : '';
|
||||
return `${pathname}${query}`;
|
||||
};
|
||||
|
||||
export const redirectToErrorPage = (errType, queryParams) => {
|
||||
const query = !_.isEmpty(queryParams) ? queryString.stringify(queryParams) : '';
|
||||
window.location = `${getHostURL()}/error/${errType}${!_.isEmpty(query) ? `?${query}` : ''}`;
|
||||
};
|
||||
|
||||
/* TODO-reuse: Somewhere in the code we used same logic to construct preview params */
|
||||
const constructQueryParamsInOrder = (shouldAddCustomParams = false) => {
|
||||
const { version, ...rest } = getQueryParams();
|
||||
const queryStr = shouldAddCustomParams && !_.isEmpty(rest) ? queryString.stringify(rest) : '';
|
||||
const previewParams = `${version ? `?version=${version}` : ''}`;
|
||||
return `${previewParams}${queryStr ? `${previewParams ? '&' : '?'}${queryStr}` : ''}`;
|
||||
};
|
||||
|
|
|
|||
13
frontend/src/_hooks/use-socket-open.jsx
Normal file
13
frontend/src/_hooks/use-socket-open.jsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
/* Created to avoid more useEffect inside the editor */
|
||||
export const useSocketOpen = (socket) => {
|
||||
const [status, setStatus] = React.useState(false);
|
||||
React.useEffect(() => {
|
||||
if (socket instanceof WebSocket) {
|
||||
socket.addEventListener('open', () => {
|
||||
setStatus(true);
|
||||
});
|
||||
}
|
||||
}, [socket]);
|
||||
return status;
|
||||
};
|
||||
|
|
@ -262,7 +262,7 @@ function logout(avoidRedirection = false) {
|
|||
if (avoidRedirection) {
|
||||
window.location.href = loginPath;
|
||||
} else {
|
||||
const pathname = getRedirectToWithParams();
|
||||
const pathname = getRedirectToWithParams(true);
|
||||
window.location.href = loginPath + `?redirectTo=${`${pathname.indexOf('/') === 0 ? '' : '/'}${pathname}`}`;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -184,6 +184,13 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-ds-container {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
top: 30%;
|
||||
}
|
||||
}
|
||||
|
||||
.datasources-info {
|
||||
|
|
@ -220,7 +227,7 @@
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
br:first-of-type {
|
||||
display: none !important;
|
||||
}
|
||||
|
|
@ -257,3 +264,23 @@
|
|||
.delete-modal {
|
||||
z-index: 1060 !important;
|
||||
}
|
||||
|
||||
.add-plugins-container {
|
||||
padding: 10px 0px;
|
||||
margin: auto;
|
||||
width: 28%;
|
||||
height: 300px;
|
||||
text-align: center;
|
||||
|
||||
.warning-container {
|
||||
padding: 5px;
|
||||
background-color: var(--slate3);
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10206,6 +10206,7 @@ tbody {
|
|||
flex-direction: column;
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: normal;
|
||||
position: relative;
|
||||
|
||||
.text-danger {
|
||||
font-weight: 400 !important;
|
||||
|
|
@ -10275,6 +10276,21 @@ tbody {
|
|||
|
||||
}
|
||||
|
||||
.tj-app-input-wrapper {
|
||||
display: flex;
|
||||
|
||||
.eye-icon {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
padding-right: 2.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.tj-sub-helper-text {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useContext } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import SolidIcon from '../Icon/SolidIcons';
|
||||
import { BreadCrumbContext } from '../../App/App';
|
||||
import useBreadcrumbs from 'use-react-router-breadcrumbs';
|
||||
|
|
@ -7,6 +7,8 @@ import useBreadcrumbs from 'use-react-router-breadcrumbs';
|
|||
export const Breadcrumbs = ({ darkMode, dataCy }) => {
|
||||
const { sidebarNav } = useContext(BreadCrumbContext);
|
||||
const breadcrumbs = useBreadcrumbs(routes, { excludePaths: ['/'] });
|
||||
const location = useLocation();
|
||||
const search = location.search || '';
|
||||
|
||||
return (
|
||||
<ol className="breadcrumb breadcrumb-arrows">
|
||||
|
|
@ -17,7 +19,7 @@ export const Breadcrumbs = ({ darkMode, dataCy }) => {
|
|||
<p className=" tj-text-xsm ">{breadcrumb}</p>
|
||||
{sidebarNav?.length > 0 && <SolidIcon name="cheveronright" fill={darkMode ? '#FDFDFE' : '#131620'} />}
|
||||
<li className="breadcrumb-item font-weight-500">
|
||||
<Link to={breadcrumb.key} data-cy="breadcrumb-page-title">
|
||||
<Link to={`${breadcrumb.key}${search}`} data-cy="breadcrumb-page-title">
|
||||
{' '}
|
||||
{sidebarNav}
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export default ({ options, addNewKeyValuePair, removeKeyValuePair, keyValuePairV
|
|||
</div>
|
||||
);
|
||||
})}
|
||||
<ButtonSolid variant="ghostBlue" size="sm" onClick={addNewKeyValuePair}>
|
||||
<ButtonSolid variant="ghostBlue" size="sm" onClick={() => addNewKeyValuePair(options)}>
|
||||
<AddRectangle width="15" fill="#3E63DD" opacity="1" secondaryFill="#ffffff" />
|
||||
Add header
|
||||
</ButtonSolid>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export default ({ options, addNewKeyValuePair, removeKeyValuePair, keyValuePairV
|
|||
)}
|
||||
{index === 0 && (
|
||||
<td>
|
||||
<button className="btn btn-sm btn-primary" onClick={addNewKeyValuePair}>
|
||||
<button className="btn btn-sm btn-primary" onClick={() => addNewKeyValuePair(options)}>
|
||||
Add
|
||||
</button>
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import QueryEditor from './QueryEditor';
|
||||
import SourceEditor from './SourceEditor';
|
||||
|
||||
|
|
@ -10,7 +11,7 @@ export default ({
|
|||
isRenderedAsQueryEditor,
|
||||
workspaceConstants,
|
||||
}) => {
|
||||
function addNewKeyValuePair() {
|
||||
function addNewKeyValuePair(options) {
|
||||
const newPairs = [...options, ['', '']];
|
||||
optionchanged(getter, newPairs);
|
||||
}
|
||||
|
|
@ -21,13 +22,14 @@ export default ({
|
|||
}
|
||||
|
||||
function keyValuePairValueChanged(value, keyIndex, index) {
|
||||
if (!isRenderedAsQueryEditor && options.length - 1 === index) {
|
||||
setTimeout(() => {
|
||||
addNewKeyValuePair();
|
||||
}, 100);
|
||||
if (!isRenderedAsQueryEditor) {
|
||||
const newOptions = _.cloneDeep(options);
|
||||
newOptions[index][keyIndex] = value;
|
||||
options.length - 1 === index ? addNewKeyValuePair(newOptions) : optionchanged(getter, newOptions);
|
||||
} else {
|
||||
options[index][keyIndex] = value;
|
||||
optionchanged(getter, options);
|
||||
}
|
||||
options[index][keyIndex] = value;
|
||||
optionchanged(getter, options);
|
||||
}
|
||||
|
||||
const commonProps = {
|
||||
|
|
|
|||
21
frontend/src/_ui/Icon/solidIcons/EyeClosed.jsx
Normal file
21
frontend/src/_ui/Icon/solidIcons/EyeClosed.jsx
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import React from 'react';
|
||||
|
||||
const EyeClosed = ({ fill = '#C1C8CD', width = '25', className = '', viewBox = '0 0 25 25' }) => (
|
||||
<svg
|
||||
width={width}
|
||||
height={width}
|
||||
viewBox={viewBox}
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M2.99767 3.77544C2.7536 3.53136 2.7536 3.13563 2.99767 2.89155C3.24175 2.64748 3.63748 2.64748 3.88156 2.89155L17.2149 16.2249C17.459 16.469 17.459 16.8647 17.2149 17.1088C16.9708 17.3528 16.5751 17.3528 16.331 17.1088L13.9754 14.7531C12.801 15.3926 11.4896 15.8335 10.1063 15.8335C6.92669 15.8335 4.12753 13.5041 2.4977 11.7892C1.53136 10.7725 1.53136 9.2278 2.4977 8.21108C3.18922 7.4835 4.09125 6.64528 5.14352 5.92128L2.99767 3.77544ZM7.95242 8.73018C7.73249 9.10238 7.60628 9.53653 7.60628 10.0002C7.60628 11.3809 8.72557 12.5002 10.1063 12.5002C10.5699 12.5002 11.0041 12.374 11.3763 12.154L7.95242 8.73018ZM10.1063 4.16683C13.2859 4.16683 16.085 6.49627 17.7149 8.21108C18.6812 9.22781 18.6812 10.7725 17.7149 11.7892C17.3481 12.1751 16.9222 12.592 16.4461 13.0066L7.9502 4.5107C8.64143 4.29396 9.36347 4.16683 10.1063 4.16683Z"
|
||||
fill={fill}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default EyeClosed;
|
||||
|
|
@ -1,13 +1,41 @@
|
|||
import React, { useState } from 'react';
|
||||
import OrgConstantVariablesPreviewBox from '../../_components/OrgConstantsVariablesResolver';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import cx from 'classnames';
|
||||
import OrgConstantVariablesPreviewBox from '@/_components/OrgConstantsVariablesResolver';
|
||||
import SolidIcon from '../Icon/SolidIcons';
|
||||
|
||||
const Input = ({ helpText, ...props }) => {
|
||||
const { workspaceVariables, workspaceConstants, value } = props;
|
||||
const { workspaceVariables, workspaceConstants, value, type, disabled, encrypted } = props;
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const [showPasswordProps, setShowPasswordProps] = useState({
|
||||
inputType: type,
|
||||
iconType: 'eyedisable',
|
||||
});
|
||||
|
||||
const toggleShowPassword = () => {
|
||||
if (inputType !== 'text') {
|
||||
setShowPasswordProps({ inputType: 'text', iconType: 'eye' });
|
||||
} else {
|
||||
setShowPasswordProps({ inputType: 'password', iconType: 'eyedisable' });
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (disabled && encrypted) setShowPasswordProps({ inputType: 'password', iconType: 'eyedisable' });
|
||||
}, [disabled]);
|
||||
|
||||
const { inputType, iconType } = showPasswordProps;
|
||||
|
||||
return (
|
||||
<div className="tj-app-input">
|
||||
<input {...props} onFocus={() => setIsFocused(true)} onBlur={() => setIsFocused(false)} />
|
||||
<div className={cx('', { 'tj-app-input-wrapper': type === 'password' || encrypted })}>
|
||||
<input {...props} type={inputType} onFocus={() => setIsFocused(true)} onBlur={() => setIsFocused(false)} />
|
||||
{(type === 'password' || encrypted) && (
|
||||
<div onClick={!disabled && toggleShowPassword}>
|
||||
{' '}
|
||||
<SolidIcon className="eye-icon" name={iconType} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<OrgConstantVariablesPreviewBox
|
||||
workspaceVariables={workspaceVariables}
|
||||
workspaceConstants={workspaceConstants}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ function Layout({ children, switchDarkMode, darkMode }) {
|
|||
<ToolTip message="Marketplace (Beta)" placement="right">
|
||||
<Link
|
||||
to="/integrations"
|
||||
onClick={(event) => checkForUnsavedChanges(getPrivateRoute('integrations'), event)}
|
||||
onClick={(event) => checkForUnsavedChanges('/integrations', event)}
|
||||
className={`tj-leftsidebar-icon-items ${
|
||||
router.pathname === '/integrations' && `current-seleted-route`
|
||||
}`}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import Input from '@/_ui/Input';
|
||||
import Select from '@/_ui/Select';
|
||||
import Headers from '@/_ui/HttpHeaders';
|
||||
import EncryptedFieldWrapper from '@/_components/EncyrptedFieldWrapper';
|
||||
|
||||
const Authentication = ({
|
||||
auth_type,
|
||||
|
|
@ -23,6 +24,9 @@ const Authentication = ({
|
|||
multiple_auth_enabled,
|
||||
optionchanged,
|
||||
workspaceConstants,
|
||||
optionsChanged,
|
||||
selectedDataSource,
|
||||
options,
|
||||
}) => {
|
||||
if (auth_type === 'oauth2') {
|
||||
return (
|
||||
|
|
@ -97,20 +101,22 @@ const Authentication = ({
|
|||
</div>
|
||||
|
||||
<div className="col-md-12">
|
||||
<label className="form-label text-muted mt-3">
|
||||
Client Secret
|
||||
<small className="text-green mx-2">
|
||||
<img className="mx-2 encrypted-icon" src="assets/images/icons/padlock.svg" width="12" height="12" />
|
||||
Encrypted
|
||||
</small>
|
||||
</label>
|
||||
<Input
|
||||
type="password"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('client_secret', e.target.value)}
|
||||
value={client_secret}
|
||||
workspaceConstants={workspaceConstants}
|
||||
/>
|
||||
<EncryptedFieldWrapper
|
||||
options={options}
|
||||
selectedDataSource={selectedDataSource}
|
||||
optionchanged={optionchanged}
|
||||
optionsChanged={optionsChanged}
|
||||
name="client_secret"
|
||||
label="Client Secret"
|
||||
>
|
||||
<Input
|
||||
type="password"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('client_secret', e.target.value)}
|
||||
value={client_secret}
|
||||
workspaceConstants={workspaceConstants}
|
||||
/>
|
||||
</EncryptedFieldWrapper>
|
||||
</div>
|
||||
|
||||
<div className="col-md-12">
|
||||
|
|
@ -199,20 +205,22 @@ const Authentication = ({
|
|||
/>
|
||||
</div>
|
||||
<div className="col-md-12">
|
||||
<label className="form-label text-muted mt-3">
|
||||
Password
|
||||
<small className="text-green mx-2">
|
||||
<img className="mx-2 encrypted-icon" src="assets/images/icons/padlock.svg" width="12" height="12" />
|
||||
Encrypted
|
||||
</small>
|
||||
</label>
|
||||
<Input
|
||||
type="password"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('password', e.target.value)}
|
||||
value={password}
|
||||
workspaceConstants={workspaceConstants}
|
||||
/>
|
||||
<EncryptedFieldWrapper
|
||||
options={options}
|
||||
selectedDataSource={selectedDataSource}
|
||||
optionchanged={optionchanged}
|
||||
optionsChanged={optionsChanged}
|
||||
name="password"
|
||||
label="Password"
|
||||
>
|
||||
<Input
|
||||
type="password"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('password', e.target.value)}
|
||||
value={password}
|
||||
workspaceConstants={workspaceConstants}
|
||||
/>
|
||||
</EncryptedFieldWrapper>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -220,20 +228,22 @@ const Authentication = ({
|
|||
return (
|
||||
<div>
|
||||
<div className="col-md-12">
|
||||
<label className="form-label text-muted mt-3">
|
||||
Token
|
||||
<small className="text-green mx-2">
|
||||
<img className="mx-2 encrypted-icon" src="assets/images/icons/padlock.svg" width="12" height="12" />
|
||||
Encrypted
|
||||
</small>
|
||||
</label>
|
||||
<Input
|
||||
type="password"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('bearer_token', e.target.value)}
|
||||
value={bearer_token}
|
||||
workspaceConstants={workspaceConstants}
|
||||
/>
|
||||
<EncryptedFieldWrapper
|
||||
options={options}
|
||||
selectedDataSource={selectedDataSource}
|
||||
optionchanged={optionchanged}
|
||||
optionsChanged={optionsChanged}
|
||||
name="bearer_token"
|
||||
label="Token"
|
||||
>
|
||||
<Input
|
||||
type="password"
|
||||
className="form-control"
|
||||
onChange={(e) => optionchanged('bearer_token', e.target.value)}
|
||||
value={bearer_token}
|
||||
workspaceConstants={workspaceConstants}
|
||||
/>
|
||||
</EncryptedFieldWrapper>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ const OAuth = ({
|
|||
multiple_auth_enabled,
|
||||
optionchanged,
|
||||
workspaceConstants,
|
||||
options,
|
||||
optionsChanged,
|
||||
selectedDataSource,
|
||||
}) => {
|
||||
const authOptions = (isGrpc = false) => {
|
||||
const options = [
|
||||
|
|
@ -78,6 +81,9 @@ const OAuth = ({
|
|||
bearer_token={bearer_token}
|
||||
auth_url={auth_url}
|
||||
workspaceConstants={workspaceConstants}
|
||||
options={options}
|
||||
optionsChanged={optionsChanged}
|
||||
selectedDataSource={selectedDataSource}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
22421
marketplace/package-lock.json
generated
22421
marketplace/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -30,4 +30,4 @@
|
|||
"lint": "eslint . '**/*.ts'",
|
||||
"format": "eslint . --fix '**/*.ts'"
|
||||
}
|
||||
}
|
||||
}
|
||||
3517
package-lock.json
generated
3517
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -3,8 +3,8 @@
|
|||
"version": "1.18.0",
|
||||
"description": "ToolJet is an open-source low-code framework to build and deploy internal tools.",
|
||||
"engines": {
|
||||
"node": "18.3.0",
|
||||
"npm": "8.11.0"
|
||||
"node": "18.18.2",
|
||||
"npm": "9.8.1"
|
||||
},
|
||||
"lint-staged": {
|
||||
"./frontend/src/**/*.{js,jsx}": [
|
||||
|
|
@ -53,4 +53,4 @@
|
|||
"prepare": "husky install",
|
||||
"update-version": "node update-version.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
34729
plugins/package-lock.json
generated
34729
plugins/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -65,7 +65,8 @@
|
|||
"@tooljet-plugins/zendesk": "file:packages/zendesk"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^4.9.5"
|
||||
"typescript": "^4.9.5",
|
||||
"form-data": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^27.5.2",
|
||||
|
|
@ -78,9 +79,9 @@
|
|||
"eslint-plugin-jest": "^24.7.0",
|
||||
"eslint-plugin-prettier": "^3.4.1",
|
||||
"jest": "^27.5.1",
|
||||
"lerna": "^4.0.0",
|
||||
"lerna": "^5.5.2",
|
||||
"prettier": "^2.8.3",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-jest": "^27.1.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
60
plugins/packages/bigquery/package-lock.json
generated
60
plugins/packages/bigquery/package-lock.json
generated
|
|
@ -8,9 +8,9 @@
|
|||
"name": "@tooljet-plugins/bigquery",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@google-cloud/bigquery": "^5.10.0",
|
||||
"@google-cloud/bigquery": "^5.12.0",
|
||||
"@tooljet-plugins/common": "file:../common",
|
||||
"json5": "^2.2.0",
|
||||
"json5": "^2.2.3",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
},
|
||||
|
|
@ -19,15 +19,19 @@
|
|||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"react": "^17.0.2",
|
||||
"rimraf": "^3.0.2"
|
||||
"rimraf": "^3.0.2",
|
||||
"tough-cookie": "^4.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/tough-cookie": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@google-cloud/bigquery": {
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@google-cloud/bigquery/-/bigquery-5.10.0.tgz",
|
||||
"integrity": "sha512-kHwPT3O5pihjlhZ4wpNElovv/RY2hyz5MdgON1UlwFM9bVA8kXqdUWS09owjVhHKaHqBxliUpG0DAwjrKHqY7Q==",
|
||||
"version": "5.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@google-cloud/bigquery/-/bigquery-5.12.0.tgz",
|
||||
"integrity": "sha512-UaIvvuKpyJhCRBkxEJXnJwvxOxkGoZHvSs9IsS0MNUS4YphcbWYOyzRMufV5gxdsr7XNSd+36Nj/n/7vyZiCqQ==",
|
||||
"dependencies": {
|
||||
"@google-cloud/common": "^3.1.0",
|
||||
"@google-cloud/common": "^3.9.0",
|
||||
"@google-cloud/paginator": "^3.0.0",
|
||||
"@google-cloud/promisify": "^2.0.0",
|
||||
"arrify": "^2.0.1",
|
||||
|
|
@ -36,6 +40,7 @@
|
|||
"extend": "^3.0.2",
|
||||
"is": "^3.3.0",
|
||||
"p-event": "^4.1.0",
|
||||
"readable-stream": "^3.6.0",
|
||||
"stream-events": "^1.0.5",
|
||||
"uuid": "^8.0.0"
|
||||
},
|
||||
|
|
@ -378,12 +383,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/json5": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
|
||||
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.5"
|
||||
},
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
},
|
||||
|
|
@ -432,11 +434,6 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
|
|
@ -660,11 +657,11 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@google-cloud/bigquery": {
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@google-cloud/bigquery/-/bigquery-5.10.0.tgz",
|
||||
"integrity": "sha512-kHwPT3O5pihjlhZ4wpNElovv/RY2hyz5MdgON1UlwFM9bVA8kXqdUWS09owjVhHKaHqBxliUpG0DAwjrKHqY7Q==",
|
||||
"version": "5.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@google-cloud/bigquery/-/bigquery-5.12.0.tgz",
|
||||
"integrity": "sha512-UaIvvuKpyJhCRBkxEJXnJwvxOxkGoZHvSs9IsS0MNUS4YphcbWYOyzRMufV5gxdsr7XNSd+36Nj/n/7vyZiCqQ==",
|
||||
"requires": {
|
||||
"@google-cloud/common": "^3.1.0",
|
||||
"@google-cloud/common": "^3.9.0",
|
||||
"@google-cloud/paginator": "^3.0.0",
|
||||
"@google-cloud/promisify": "^2.0.0",
|
||||
"arrify": "^2.0.1",
|
||||
|
|
@ -673,6 +670,7 @@
|
|||
"extend": "^3.0.2",
|
||||
"is": "^3.3.0",
|
||||
"p-event": "^4.1.0",
|
||||
"readable-stream": "^3.6.0",
|
||||
"stream-events": "^1.0.5",
|
||||
"uuid": "^8.0.0"
|
||||
}
|
||||
|
|
@ -715,8 +713,10 @@
|
|||
"@tooljet-plugins/common": {
|
||||
"version": "file:../common",
|
||||
"requires": {
|
||||
"@types/tough-cookie": "^4.0.2",
|
||||
"react": "^17.0.2",
|
||||
"rimraf": "^3.0.2"
|
||||
"rimraf": "^3.0.2",
|
||||
"tough-cookie": "^4.1.3"
|
||||
}
|
||||
},
|
||||
"@tootallnate/once": {
|
||||
|
|
@ -923,12 +923,9 @@
|
|||
}
|
||||
},
|
||||
"json5": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
|
||||
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
|
||||
},
|
||||
"jwa": {
|
||||
"version": "2.0.0",
|
||||
|
|
@ -965,11 +962,6 @@
|
|||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
|
|
|
|||
|
|
@ -21,5 +21,8 @@
|
|||
"@tooljet-plugins/common": "file:../common",
|
||||
"json5": "^2.2.3",
|
||||
"react": "^17.0.2"
|
||||
},
|
||||
"overrides": {
|
||||
"minimist": "^1.2.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
1822
plugins/packages/firestore/package-lock.json
generated
1822
plugins/packages/firestore/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -16,9 +16,9 @@
|
|||
"clean": "rimraf ./dist && rimraf tsconfig.tsbuildinfo"
|
||||
},
|
||||
"dependencies": {
|
||||
"@google-cloud/firestore": "^5.0.2",
|
||||
"@google-cloud/firestore": "^7.1.0",
|
||||
"@tooljet-plugins/common": "file:../common",
|
||||
"react": "^17.0.2",
|
||||
"rimraf": "^3.0.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
368
plugins/packages/grpc/package-lock.json
generated
368
plugins/packages/grpc/package-lock.json
generated
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@tooljet-plugins/grpc",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
|
|
@ -18,15 +18,19 @@
|
|||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"react": "^17.0.2",
|
||||
"rimraf": "^3.0.2"
|
||||
"rimraf": "^3.0.2",
|
||||
"tough-cookie": "^4.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/tough-cookie": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@grpc/grpc-js": {
|
||||
"version": "1.8.14",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.14.tgz",
|
||||
"integrity": "sha512-w84maJ6CKl5aApCMzFll0hxtFNT6or9WwMslobKaqWUEf1K+zhlL43bSQhFreyYWIWR+Z0xnVFC1KtLm4ZpM/A==",
|
||||
"version": "1.9.12",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.12.tgz",
|
||||
"integrity": "sha512-Um5MBuge32TS3lAKX02PGCnFM4xPT996yLgZNb5H03pn6NyJ4Iwn5YcPq6Jj9yxGRk7WOgaZFtVRH5iTdYBeUg==",
|
||||
"dependencies": {
|
||||
"@grpc/proto-loader": "^0.7.0",
|
||||
"@grpc/proto-loader": "^0.7.8",
|
||||
"@types/node": ">=12.12.47"
|
||||
},
|
||||
"engines": {
|
||||
|
|
@ -34,15 +38,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@grpc/proto-loader": {
|
||||
"version": "0.7.6",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.6.tgz",
|
||||
"integrity": "sha512-QyAXR8Hyh7uMDmveWxDSUcJr9NAWaZ2I6IXgAYvQmfflwouTM+rArE2eEaCtLlRqO81j7pRLCt81IefUei6Zbw==",
|
||||
"version": "0.7.10",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz",
|
||||
"integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==",
|
||||
"dependencies": {
|
||||
"@types/long": "^4.0.1",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"long": "^4.0.0",
|
||||
"protobufjs": "^7.0.0",
|
||||
"yargs": "^16.2.0"
|
||||
"long": "^5.0.0",
|
||||
"protobufjs": "^7.2.4",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
"proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
|
||||
|
|
@ -109,15 +112,13 @@
|
|||
"resolved": "../common",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@types/long": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
|
||||
"integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
|
||||
"integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
|
||||
"version": "20.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.2.tgz",
|
||||
"integrity": "sha512-37MXfxkb0vuIlRKHNxwCkb60PNBpR94u4efQuN4JgIAm66zfCDXGSAFCef9XUWFovX2R1ok6Z7MHhtdVXXkkIw==",
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
|
|
@ -142,13 +143,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
|
|
@ -207,9 +211,9 @@
|
|||
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
|
||||
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
|
||||
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
|
|
@ -231,9 +235,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/protobufjs": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz",
|
||||
"integrity": "sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==",
|
||||
"version": "7.2.5",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz",
|
||||
"integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@protobufjs/aspromise": "^1.1.2",
|
||||
|
|
@ -253,11 +257,6 @@
|
|||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/protobufjs/node_modules/long": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
|
||||
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
|
|
@ -302,6 +301,11 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
|
|
@ -327,299 +331,29 @@
|
|||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dependencies": {
|
||||
"cliui": "^7.0.2",
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.0",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^20.2.2"
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "20.2.9",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
|
||||
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": ">=12"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": {
|
||||
"version": "1.8.14",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.14.tgz",
|
||||
"integrity": "sha512-w84maJ6CKl5aApCMzFll0hxtFNT6or9WwMslobKaqWUEf1K+zhlL43bSQhFreyYWIWR+Z0xnVFC1KtLm4ZpM/A==",
|
||||
"requires": {
|
||||
"@grpc/proto-loader": "^0.7.0",
|
||||
"@types/node": ">=12.12.47"
|
||||
}
|
||||
},
|
||||
"@grpc/proto-loader": {
|
||||
"version": "0.7.6",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.6.tgz",
|
||||
"integrity": "sha512-QyAXR8Hyh7uMDmveWxDSUcJr9NAWaZ2I6IXgAYvQmfflwouTM+rArE2eEaCtLlRqO81j7pRLCt81IefUei6Zbw==",
|
||||
"requires": {
|
||||
"@types/long": "^4.0.1",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"long": "^4.0.0",
|
||||
"protobufjs": "^7.0.0",
|
||||
"yargs": "^16.2.0"
|
||||
}
|
||||
},
|
||||
"@protobufjs/aspromise": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
||||
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
|
||||
},
|
||||
"@protobufjs/base64": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
|
||||
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
|
||||
},
|
||||
"@protobufjs/codegen": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
|
||||
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
|
||||
},
|
||||
"@protobufjs/eventemitter": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
|
||||
"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
|
||||
},
|
||||
"@protobufjs/fetch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
|
||||
"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
|
||||
"requires": {
|
||||
"@protobufjs/aspromise": "^1.1.1",
|
||||
"@protobufjs/inquire": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"@protobufjs/float": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
|
||||
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
|
||||
},
|
||||
"@protobufjs/inquire": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
|
||||
"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
|
||||
},
|
||||
"@protobufjs/path": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
||||
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
|
||||
},
|
||||
"@protobufjs/pool": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
|
||||
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
|
||||
},
|
||||
"@protobufjs/utf8": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
||||
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
|
||||
},
|
||||
"@tooljet-plugins/common": {
|
||||
"version": "file:../common",
|
||||
"requires": {
|
||||
"react": "^17.0.2",
|
||||
"rimraf": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"@types/long": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
|
||||
"integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "18.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
|
||||
"integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"requires": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
|
||||
},
|
||||
"get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"lodash.camelcase": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
|
||||
},
|
||||
"long": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
|
||||
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
|
||||
},
|
||||
"protobufjs": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz",
|
||||
"integrity": "sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==",
|
||||
"requires": {
|
||||
"@protobufjs/aspromise": "^1.1.2",
|
||||
"@protobufjs/base64": "^1.1.2",
|
||||
"@protobufjs/codegen": "^2.0.4",
|
||||
"@protobufjs/eventemitter": "^1.1.0",
|
||||
"@protobufjs/fetch": "^1.1.0",
|
||||
"@protobufjs/float": "^1.0.2",
|
||||
"@protobufjs/inquire": "^1.1.0",
|
||||
"@protobufjs/path": "^1.1.2",
|
||||
"@protobufjs/pool": "^1.1.0",
|
||||
"@protobufjs/utf8": "^1.1.0",
|
||||
"@types/node": ">=13.7.0",
|
||||
"long": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"long": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
|
||||
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"requires": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||
"requires": {
|
||||
"cliui": "^7.0.2",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.0",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^20.2.2"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "20.2.9",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
|
||||
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,5 +21,8 @@
|
|||
"@grpc/proto-loader": "^0.7.6",
|
||||
"@tooljet-plugins/common": "file:../common",
|
||||
"react": "^17.0.2"
|
||||
},
|
||||
"overrides": {
|
||||
"minimist": "^1.2.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,11 +29,11 @@
|
|||
"value": ""
|
||||
},
|
||||
"protocol": {
|
||||
"type": "HTTP"
|
||||
"value": "http"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"api_key": {
|
||||
"api_token": {
|
||||
"label": "API token",
|
||||
"key": "api_token",
|
||||
"type": "password",
|
||||
|
|
@ -79,4 +79,4 @@
|
|||
"host",
|
||||
"protocol"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import { QueryError, QueryResult, QueryService, ConnectionTestResult } from '@to
|
|||
import { SourceOptions, QueryOptions } from './types';
|
||||
const mariadb = require('mariadb');
|
||||
export default class Mariadb implements QueryService {
|
||||
private defaultConnectionLimit = '5';
|
||||
async run(sourceOptions: SourceOptions, queryOptions: QueryOptions): Promise<QueryResult> {
|
||||
let result = {};
|
||||
const mariadbClient = await this.getConnection(sourceOptions);
|
||||
|
|
@ -18,23 +19,31 @@ export default class Mariadb implements QueryService {
|
|||
}
|
||||
|
||||
async testConnection(sourceOptions: SourceOptions): Promise<ConnectionTestResult> {
|
||||
const conn = await this.getConnection(sourceOptions);
|
||||
const rows = await conn.query('SELECT 1 as val');
|
||||
try {
|
||||
const conn = await this.getConnection(sourceOptions);
|
||||
const rows = await conn.query('SELECT 1 as val');
|
||||
|
||||
if (!rows) {
|
||||
throw new Error('Error');
|
||||
if (!rows) {
|
||||
throw new Error('Connection test returned no results');
|
||||
}
|
||||
return {
|
||||
status: 'ok',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new QueryError('Connection test failed', error.message, {});
|
||||
}
|
||||
return {
|
||||
status: 'ok',
|
||||
};
|
||||
}
|
||||
|
||||
async getConnection(sourceOptions: SourceOptions): Promise<any> {
|
||||
const connectionLimit =
|
||||
sourceOptions.connectionLimit && sourceOptions.connectionLimit !== ''
|
||||
? sourceOptions.connectionLimit
|
||||
: this.defaultConnectionLimit;
|
||||
const poolConfig = {
|
||||
host: sourceOptions.host,
|
||||
user: sourceOptions.user,
|
||||
password: sourceOptions.password,
|
||||
connectionLimit: sourceOptions.connectionLimit,
|
||||
connectionLimit: connectionLimit,
|
||||
port: sourceOptions.port,
|
||||
database: sourceOptions.database,
|
||||
};
|
||||
|
|
@ -51,9 +60,17 @@ export default class Mariadb implements QueryService {
|
|||
|
||||
if (sourceOptions.ssl_enabled) poolConfig['ssl'] = sslObject;
|
||||
|
||||
const mariadbPool = mariadb.createPool(poolConfig);
|
||||
try {
|
||||
const mariadbPool = await mariadb.createPool(poolConfig);
|
||||
mariadbPool.on('error', (error) => {
|
||||
console.error(error);
|
||||
});
|
||||
|
||||
return mariadbPool.getConnection();
|
||||
return mariadbPool.getConnection();
|
||||
} catch (error) {
|
||||
console.error('Error while establishing database connection:', error.message);
|
||||
throw new QueryError('Database connection failed', error.message, {});
|
||||
}
|
||||
}
|
||||
|
||||
private toJson(data) {
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ export default class MinioService implements QueryService {
|
|||
async getConnection(sourceOptions: SourceOptions, options?: object): Promise<any> {
|
||||
const credentials: ClientOptions = {
|
||||
endPoint: sourceOptions['host'],
|
||||
port: sourceOptions['port'],
|
||||
useSSL: sourceOptions['ssl_enabled'],
|
||||
port: +sourceOptions['port'],
|
||||
useSSL: !!sourceOptions['ssl_enabled'],
|
||||
accessKey: sourceOptions['access_key'],
|
||||
secretKey: sourceOptions['secret_key'],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -61,5 +61,6 @@ export async function signedUrlForPut(minioClient: MinioClient, queryOptions: ob
|
|||
}
|
||||
|
||||
export async function removeObject(minioClient: MinioClient, queryOptions: object): Promise<object> {
|
||||
return await minioClient.removeObject(queryOptions['bucket'], queryOptions['objectName']);
|
||||
await minioClient.removeObject(queryOptions['bucket'], queryOptions['objectName']);
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
1939
plugins/packages/minio/package-lock.json
generated
1939
plugins/packages/minio/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -17,5 +17,8 @@
|
|||
"@tooljet-plugins/common": "file:../common",
|
||||
"minio": "^7.0.32",
|
||||
"react": "^17.0.2"
|
||||
},
|
||||
"overrides": {
|
||||
"minimist": "^1.2.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -111,6 +111,7 @@
|
|||
"label": "Connection string",
|
||||
"key": "connection_string",
|
||||
"type": "text",
|
||||
"encrypted": true,
|
||||
"description": "mongodb+srv://tooljet:<password>@cluster0.i1vq4.mongodb.net/mydb?retryWrites=true&w=majority"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
"label": "Password",
|
||||
"key": "password",
|
||||
"type": "password",
|
||||
"description": "Enter username"
|
||||
"description": "Enter password"
|
||||
}
|
||||
},
|
||||
"header":{
|
||||
|
|
|
|||
5303
plugins/packages/snowflake/package-lock.json
generated
5303
plugins/packages/snowflake/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -22,4 +22,4 @@
|
|||
"react": "^17.0.2",
|
||||
"snowflake-sdk": "^1.9.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
1124
plugins/packages/twilio/package-lock.json
generated
1124
plugins/packages/twilio/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -20,5 +20,8 @@
|
|||
"react": "^17.0.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"twilio": "^3.84.1"
|
||||
},
|
||||
"overrides": {
|
||||
"url-parse": ">=1.5.9"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,12 @@
|
|||
"data": {},
|
||||
"rawData": {}
|
||||
},
|
||||
"options": {},
|
||||
"options": {
|
||||
"client_secret": {
|
||||
"type": "string",
|
||||
"encrypted": true
|
||||
}
|
||||
},
|
||||
"customTesting": true,
|
||||
"hideSave": true
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
2.26.2
|
||||
2.27.0
|
||||
|
|
|
|||
16120
server/package-lock.json
generated
16120
server/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -44,14 +44,14 @@
|
|||
"@nestjs/platform-ws": "^8.0.10",
|
||||
"@nestjs/schedule": "^2.2.0",
|
||||
"@nestjs/serve-static": "^2.2.2",
|
||||
"@nestjs/typeorm": "^8.0.0",
|
||||
"@nestjs/typeorm": "8.0.0",
|
||||
"@nestjs/websockets": "^8.0.10",
|
||||
"@sentry/node": "6.17.6",
|
||||
"@sentry/tracing": "6.17.6",
|
||||
"@tooljet/plugins": "../plugins",
|
||||
"bcrypt": "^5.0.1",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.13.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"compression": "^1.7.4",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"dotenv": "^10.0.0",
|
||||
|
|
@ -88,7 +88,7 @@
|
|||
"y-websocket": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/cli": "^8.0.0"
|
||||
"@nestjs/cli": "^9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@golevelup/ts-jest": "^0.3.2",
|
||||
|
|
@ -96,12 +96,11 @@
|
|||
"@nestjs/testing": "^8.0.0",
|
||||
"@types/compression": "^1.7.2",
|
||||
"@types/cookie-parser": "^1.4.3",
|
||||
"@types/cron": "^2.0.0",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/express-http-proxy": "^1.6.3",
|
||||
"@types/got": "^9.6.12",
|
||||
"@types/humps": "^2.0.1",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/jest": "^27.0.0",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^16.0.0",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
|
|
@ -110,8 +109,8 @@
|
|||
"@types/sanitize-html": "^2.6.2",
|
||||
"@types/supertest": "^2.0.11",
|
||||
"@types/ws": "^8.2.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.31.1",
|
||||
"@typescript-eslint/parser": "^4.31.1",
|
||||
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
||||
"@typescript-eslint/parser": "^6.13.2",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
|
|
@ -127,7 +126,7 @@
|
|||
"typescript": "^4.3.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18.3.0",
|
||||
"npm": "8.11.0"
|
||||
"node": "18.18.2",
|
||||
"npm": "9.8.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue