- {type === 'query' &&
- param?.schema?.anyOf &&
- param?.schema?.anyOf.map((type, i) =>
- i < param.schema?.anyOf.length - 1
- ? type.type.substring(0, 3).toUpperCase() + '|'
- : type.type.substring(0, 3).toUpperCase()
- )}
- {(type === 'path' || (type === 'query' && !param?.schema?.anyOf)) &&
- param?.schema?.type?.substring(0, 3).toUpperCase()}
- {type === 'request' && parameters[param].type?.substring(0, 3).toUpperCase()}
+
);
};
+ const paramType = (param) => {
+ let paramTypeValue;
+
+ if (type === 'query') {
+ if (param?.schema?.anyOf) {
+ return (
+
+ {param.schema.anyOf.map((typeObj, i) =>
+ i < param.schema.anyOf.length - 1
+ ? (typeObj.type || '').toString().substring(0, 3).toUpperCase() + '|'
+ : (typeObj.type || '').toString().substring(0, 3).toUpperCase()
+ )}
+
+ );
+ }
+ paramTypeValue = param?.schema?.type;
+ } else if (type === 'path') {
+ paramTypeValue = param?.schema?.type;
+ } else if (type === 'request') {
+ paramTypeValue = parameters[param]?.type;
+ }
+
+ const displayType = Array.isArray(paramTypeValue) ? paramTypeValue[0] : paramTypeValue;
+
+ return
- {(type === 'request' && parameters[param].description) || param?.description
- ? paramLabelWithDescription(param)
- : paramLabelWithoutDescription(param)}
- {param.required &&
*}
+
+
+ {(type === 'request' && parameters[param].description) || param?.description
+ ? paramLabelWithDescription(param)
+ : paramLabelWithoutDescription(param)}
+ {param.required && *}
+
{paramType(param)}
);
@@ -359,3 +366,34 @@ RenderParameterFields.propTypes = {
removeParam: PropTypes.func,
darkMode: PropTypes.bool,
};
+
+const AutoWidthText = ({ value, className }) => {
+ const spanRef = useRef(null);
+ const [width, setWidth] = useState(0);
+
+ useLayoutEffect(() => {
+ if (spanRef.current) {
+ setWidth(spanRef.current.offsetWidth);
+ }
+ }, [value]);
+
+ return (
+
+
+ {value}
+
+ {value}
+
+ );
+};
diff --git a/frontend/src/_components/DynamicForm.jsx b/frontend/src/_components/DynamicForm.jsx
index a71974afc4..bdc7f71054 100644
--- a/frontend/src/_components/DynamicForm.jsx
+++ b/frontend/src/_components/DynamicForm.jsx
@@ -245,7 +245,7 @@ const DynamicForm = ({
encrypted,
placeholders = {},
editorType = 'basic',
- specUrl = '',
+ spec_url = '',
disabled = false,
buttonText,
text,
@@ -486,7 +486,7 @@ const DynamicForm = ({
};
case 'react-component-api-endpoint':
return {
- specUrl: specUrl,
+ specUrl: spec_url,
optionsChanged,
options,
darkMode,
diff --git a/frontend/src/_components/Slack.jsx b/frontend/src/_components/Slack.jsx
index d986bccd5f..1301572357 100644
--- a/frontend/src/_components/Slack.jsx
+++ b/frontend/src/_components/Slack.jsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useEffect } from 'react';
import { datasourceService } from '@/_services';
import { useTranslation } from 'react-i18next';
import { toast } from 'react-hot-toast';
@@ -15,8 +15,16 @@ const Slack = ({
isDisabled,
}) => {
const [authStatus, setAuthStatus] = useState(null);
- const whiteLabelText = retrieveWhiteLabelText();
+ const [whiteLabelText, setWhiteLabelText] = useState('');
+ const plugin_id = selectedDataSource?.plugin?.id;
const { t } = useTranslation();
+ useEffect(() => {
+ async function fetchLabel() {
+ const text = await retrieveWhiteLabelText();
+ setWhiteLabelText(text);
+ }
+ fetchLabel();
+ }, []);
function authGoogle() {
const provider = 'slack';
@@ -29,7 +37,7 @@ const Slack = ({
}
datasourceService
- .fetchOauth2BaseUrl(provider)
+ .fetchOauth2BaseUrl(provider, plugin_id, {})
.then((data) => {
const authUrl = `${data.url}&scope=${scope}&access_type=offline&prompt=select_account`;
diff --git a/frontend/src/_components/Zendesk.jsx b/frontend/src/_components/Zendesk.jsx
index 7d03035152..c61927c52e 100644
--- a/frontend/src/_components/Zendesk.jsx
+++ b/frontend/src/_components/Zendesk.jsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useEffect } from 'react';
import { toast } from 'react-hot-toast';
import { useTranslation } from 'react-i18next';
import Input from '@/_ui/Input';
@@ -18,17 +18,26 @@ const Zendesk = ({
isDisabled,
optionsChanged,
}) => {
+ const [whiteLabelText, setWhiteLabelText] = useState('');
const [authStatus, setAuthStatus] = useState(null);
- const whiteLabelText = retrieveWhiteLabelText();
+ useEffect(() => {
+ async function fetchLabel() {
+ const text = await retrieveWhiteLabelText();
+ setWhiteLabelText(text);
+ }
+ fetchLabel();
+ }, []);
function authZendesk() {
const provider = 'zendesk';
setAuthStatus('waiting_for_url');
const scope = options?.access_type?.value === 'read' ? 'read' : 'read%20write';
+ const subDomain = options?.subdomain?.value;
+ const client_id = options?.client_id?.value;
try {
- const authUrl = `https://${options?.subdomain?.value}.zendesk.com/oauth/authorizations/new?response_type=code&client_id=${options?.client_id?.value}&redirect_uri=${window.location.origin}/oauth2/authorize&scope=${scope}`;
+ const authUrl = `https://${subDomain}.zendesk.com/oauth/authorizations/new?response_type=code&client_id=${client_id}&redirect_uri=${window.location.origin}/oauth2/authorize&scope=${scope}`;
localStorage.setItem('sourceWaitingForOAuth', 'newSource');
localStorage.setItem('currentAppEnvironmentIdForOauth', currentAppEnvironmentId);
optionchanged('provider', provider).then(() => {
diff --git a/frontend/src/_services/datasource.service.js b/frontend/src/_services/datasource.service.js
index 9ea24e99d0..49a6ade912 100644
--- a/frontend/src/_services/datasource.service.js
+++ b/frontend/src/_services/datasource.service.js
@@ -98,7 +98,7 @@ function setOauth2Token(dataSourceId, body, current_organization_id) {
function fetchOauth2BaseUrl(provider, plugin_id = null, source_options = {}) {
const payload = { provider, ...(plugin_id && { plugin_id }), ...(source_options && { source_options }) };
const requestOptions = {
- method: 'GET',
+ method: 'POST',
headers: authHeader(),
credentials: 'include',
body: JSON.stringify(payload),
diff --git a/frontend/src/_services/globalDatasource.service.js b/frontend/src/_services/globalDatasource.service.js
index aebdcca0f1..14963c19f5 100644
--- a/frontend/src/_services/globalDatasource.service.js
+++ b/frontend/src/_services/globalDatasource.service.js
@@ -9,6 +9,8 @@ export const globalDatasourceService = {
convertToGlobal,
getDataSourceByEnvironmentId,
getForApp,
+ getQueriesLinkedToDatasource,
+ getQueriesLinkedToMarketplacePlugin,
};
function getForApp(organizationId, appVersionId, environmentId) {
@@ -68,3 +70,15 @@ function getDataSourceByEnvironmentId(dataSourceId, environmentId) {
handleResponse
);
}
+
+function getQueriesLinkedToMarketplacePlugin(pluginId) {
+ const requestOptions = { method: 'GET', headers: authHeader(), credentials: 'include' };
+ return fetch(`${config.apiUrl}/data-sources/dependent-queries/marketplace-plugin/${pluginId}`, requestOptions).then(
+ handleResponse
+ );
+}
+
+function getQueriesLinkedToDatasource(dataSourceId) {
+ const requestOptions = { method: 'GET', headers: authHeader(), credentials: 'include' };
+ return fetch(`${config.apiUrl}/data-sources/dependent-queries/${dataSourceId}`, requestOptions).then(handleResponse);
+}
diff --git a/frontend/src/_services/user.service.js b/frontend/src/_services/user.service.js
index 0046ca7c11..a2017ceb22 100644
--- a/frontend/src/_services/user.service.js
+++ b/frontend/src/_services/user.service.js
@@ -12,6 +12,7 @@ export const userService = {
getAvatar,
updateAvatar,
updateUserType,
+ updateUserTypeInstance,
getUserLimits,
changeUserPassword,
generateUserPassword,
@@ -80,6 +81,16 @@ function updateUserType(userUpdateBody) {
return fetch(`${config.apiUrl}/users/user-type`, requestOptions).then(handleResponse);
}
+function updateUserTypeInstance(userUpdateBody) {
+ const requestOptions = {
+ method: 'PATCH',
+ headers: authHeader(),
+ body: JSON.stringify(userUpdateBody),
+ credentials: 'include',
+ };
+ return fetch(`${config.apiUrl}/users/user-type/instance`, requestOptions).then(handleResponse);
+}
+
function changePassword(currentPassword, newPassword) {
const body = { currentPassword, newPassword };
const requestOptions = { method: 'PATCH', headers: authHeader(), credentials: 'include', body: JSON.stringify(body) };
diff --git a/frontend/src/modules/dataSources/components/DataSourceManager/DataSourceManager.jsx b/frontend/src/modules/dataSources/components/DataSourceManager/DataSourceManager.jsx
index ea556429dd..9f601bb412 100644
--- a/frontend/src/modules/dataSources/components/DataSourceManager/DataSourceManager.jsx
+++ b/frontend/src/modules/dataSources/components/DataSourceManager/DataSourceManager.jsx
@@ -21,7 +21,7 @@ import config from 'config';
import { capitalize, isEmpty } from 'lodash';
import { Card } from '@/_ui/Card';
import { withTranslation, useTranslation } from 'react-i18next';
-import { camelizeKeys, decamelizeKeys } from 'humps';
+import { camelizeKeys, decamelizeKeys, decamelize } from 'humps';
import { ButtonSolid } from '@/_ui/AppButton/AppButton';
import SolidIcon from '@/_ui/Icon/SolidIcons';
import { useAppVersionStore } from '@/_stores/appVersionStore';
@@ -249,14 +249,26 @@ class DataSourceManagerComponent extends React.Component {
const scope = this.state?.scope || selectedDataSource?.scope;
const parsedOptions = Object?.keys(options)?.map((key) => {
- const keyMeta = dataSourceMeta.options[key];
+ let keyMeta = dataSourceMeta.options[key];
+ let isEncrypted = false;
+ if (keyMeta) {
+ isEncrypted = keyMeta.encrypted;
+ }
+
+ // to resolve any casing mis-match
+ if (decamelize(key) !== key) {
+ const newKey = decamelize(key);
+ isEncrypted = dataSourceMeta.options[newKey]?.encrypted;
+ }
+
return {
key: key,
value: options[key].value,
- encrypted: keyMeta ? keyMeta.encrypted : false,
+ encrypted: isEncrypted,
...(!options[key]?.value && { credential_id: options[key]?.credential_id }),
};
});
+
if (OAuthDs.includes(kind)) {
const value = localStorage.getItem('OAuthCode');
parsedOptions.push({ key: 'code', value, encrypted: false });
diff --git a/frontend/src/modules/dataSources/components/List/index.jsx b/frontend/src/modules/dataSources/components/List/index.jsx
index f3c691ad66..3ceb1864dc 100644
--- a/frontend/src/modules/dataSources/components/List/index.jsx
+++ b/frontend/src/modules/dataSources/components/List/index.jsx
@@ -9,6 +9,7 @@ import SolidIcon from '@/_ui/Icon/SolidIcons';
import { SearchBox } from '@/_components/SearchBox';
import { DATA_SOURCE_TYPE } from '@/_helpers/constants';
import FolderSkeleton from '@/_ui/FolderSkeleton/FolderSkeleton';
+import Modal from '@/HomePage/Modal';
export const List = ({ updateSelectedDatasource }) => {
const {
@@ -28,6 +29,7 @@ export const List = ({ updateSelectedDatasource }) => {
const [isDeleteModalVisible, setDeleteModalVisibility] = React.useState(false);
const [filteredData, setFilteredData] = useState(dataSources);
const [showInput, setShowInput] = useState(false);
+ const [showDependentQueriesInfo, setShowDependentQueriesInfo] = useState(false);
const darkMode = localStorage.getItem('darkMode') === 'true';
@@ -50,7 +52,7 @@ export const List = ({ updateSelectedDatasource }) => {
setCurrentEnvironment(environments[0]);
toggleDataSourceManagerModal(true);
updateSelectedDatasource(selectedSource?.name);
- setDeleteModalVisibility(true);
+ getQueriesLinkedToDatasource(selectedSource);
};
const executeDataSourceDeletion = () => {
@@ -74,6 +76,21 @@ export const List = ({ updateSelectedDatasource }) => {
});
};
+ const getQueriesLinkedToDatasource = (selectedSource) => {
+ globalDatasourceService
+ .getQueriesLinkedToDatasource(selectedSource.id)
+ .then((data) => {
+ if (data?.dependent_queries) {
+ setShowDependentQueriesInfo(true);
+ } else {
+ setDeleteModalVisibility(true);
+ }
+ })
+ .catch(({ error }) => {
+ toast.error(error);
+ });
+ };
+
const cancelDeleteDataSource = () => {
setDeleteModalVisibility(false);
};
@@ -171,6 +188,16 @@ export const List = ({ updateSelectedDatasource }) => {
)}