Merge pull request #11370 from ToolJet/release/lts-3.0.3

Release LTS v3.0.3 - Platform
This commit is contained in:
Midhun G S 2024-11-22 12:41:00 +05:30 committed by GitHub
commit 167d1eb2db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 171 additions and 14 deletions

View file

@ -1 +1 @@
3.0.3-ce-lts
3.0.4-ce-lts

View file

@ -1 +1 @@
3.0.3-ce-lts
3.0.4-ce-lts

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="18" viewBox="0 0 17 18" fill="none">
<circle opacity="0.4" cx="8.5118" cy="9.25781" r="8.33333" fill="#BF4F03"/>
<path d="M9.34513 5.09115C9.34513 5.55138 8.97204 5.92448 8.5118 5.92448C8.05156 5.92448 7.67847 5.55138 7.67847 5.09115C7.67847 4.63091 8.05156 4.25781 8.5118 4.25781C8.97204 4.25781 9.34513 4.63091 9.34513 5.09115Z" fill="#BF4F03"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.05347 7.59115C7.05347 7.24597 7.33329 6.96615 7.67847 6.96615H8.5118C8.85698 6.96615 9.1368 7.24597 9.1368 7.59115V13.4245C9.1368 13.7697 8.85698 14.0495 8.5118 14.0495C8.16662 14.0495 7.8868 13.7697 7.8868 13.4245V8.21615H7.67847C7.33329 8.21615 7.05347 7.93633 7.05347 7.59115Z" fill="#BF4F03"/>
</svg>

After

Width:  |  Height:  |  Size: 769 B

View file

@ -19,6 +19,7 @@ import { DATA_SOURCE_TYPE } from '@/_helpers/constants';
import { canDeleteDataSource, canReadDataSource, canUpdateDataSource } from '@/_helpers';
import useStore from '@/AppBuilder/_stores/store';
import { EventManager } from '@/AppBuilder/RightSideBar/Inspector/EventManager';
import NotificationBanner from '@/_components/NotificationBanner';
export const QueryManagerBody = ({ darkMode, options, setOptions, activeTab }) => {
const { t } = useTranslation();
@ -30,6 +31,7 @@ export const QueryManagerBody = ({ darkMode, options, setOptions, activeTab }) =
const selectedDataSource = useStore((state) => state.queryPanel.selectedDataSource);
const changeDataQuery = useStore((state) => state.dataQuery.changeDataQuery);
const updateDataQuery = useStore((state) => state.dataQuery.updateDataQuery);
const [showLocalDataSourceDeprecationBanner, setshowLocalDataSourceDeprecationBanner] = useState(false);
const [dataSourceMeta, setDataSourceMeta] = useState(null);
/* - Added the below line to cause re-rendering when the query is switched
@ -280,7 +282,7 @@ export const QueryManagerBody = ({ darkMode, options, setOptions, activeTab }) =
return (
<>
<div className="" ref={paramListContainerRef}>
{selectedQuery && (
{selectedQuery && !showLocalDataSourceDeprecationBanner && (
<ParameterList
parameters={options.parameters}
handleAddParameter={handleAddParameter}
@ -310,6 +312,21 @@ export const QueryManagerBody = ({ darkMode, options, setOptions, activeTab }) =
</>
);
};
useEffect(() => {
const staticDataSources = ['runjs', 'runpy', 'tooljetdb'];
// added specific check for rest api - as it is a part of both : default and global data sources
const showDeprecationBanner =
selectedDataSource == null &&
selectedQuery &&
!staticDataSources.includes(selectedDataSource?.kind) &&
(selectedDataSource?.kind !== 'restapi' || selectedDataSource?.type !== 'default');
if (showDeprecationBanner) {
setshowLocalDataSourceDeprecationBanner(true);
} else {
setshowLocalDataSourceDeprecationBanner(false);
}
}, [selectedDataSource, selectedQuery]);
// if (selectedQueryId !== selectedQuery?.id) return;
const hasPermissions =
@ -318,7 +335,6 @@ export const QueryManagerBody = ({ darkMode, options, setOptions, activeTab }) =
canReadDataSource(selectedQuery?.data_source_id) ||
canDeleteDataSource()
: true;
return (
<div
className={`query-details ${selectedDataSource?.kind === 'tooljetdb' ? 'tooljetdb-query-details' : ''} ${
@ -331,7 +347,14 @@ export const QueryManagerBody = ({ darkMode, options, setOptions, activeTab }) =
}} // 40px for preview header height
>
{selectedDataSource === null || !selectedQuery ? (
renderDataSourcesList()
showLocalDataSourceDeprecationBanner ? (
<>
<NotificationBanner enhanceDisabledVisibility={!hasPermissions || isFreezed} darkMode={darkMode} />
{renderChangeDataSource()}
</>
) : (
renderDataSourcesList()
)
) : (
<>
{selectedQuery?.data_source_id && activeTab === 1 && renderChangeDataSource()}

View file

@ -51,7 +51,7 @@
border: 1px solid #e9ece;
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
overflow: hidden;
width: 920px;
// width: 920px; //Add it for EE
height: 620px;
padding: 20px;
border-radius: 4px;

View file

@ -90,7 +90,7 @@ const ConstantTable = ({
<tbody>
{constants.map((constant) => (
<tr key={constant.id}>
<td className="p-3">
<td className="p-3-constants">
<span
data-cy={`${constant.name.toLowerCase().replace(/\s+/g, '-')}-workspace-constant-name`}
data-tooltip-id="tooltip-for-org-constant-cell"
@ -101,7 +101,7 @@ const ConstantTable = ({
: constant.name}
</span>
</td>
<td className="text-muted p-3" style={{ width: '350px' }}>
<td className="text-muted p-3-constants" style={{ width: '350px' }}>
<a
className="text-reset user-email"
data-cy={`${constant.name.toLowerCase().replace(/\s+/g, '-')}-workspace-constant-value`}
@ -111,7 +111,7 @@ const ConstantTable = ({
</td>
{canUpdateDeleteConstant && (
<td className="p-3">
<td className="p-3-constants">
<div
style={{ display: 'flex', justifyContent: 'space-between', gap: 5 }}
data-cy={`${constant.name.toLowerCase().replace(/\s+/g, '-')}-workspace-constant-update`}

View file

@ -445,7 +445,7 @@ const ManageOrgConstantsComponent = ({ darkMode }) => {
<OrganizationList />
</div>
<div className="page-wrapper mt-4">
<div className="page-wrapper mt-4" style={{ marginLeft: '50px' }}>
<div className="container-xl" style={{ width: '880px' }}>
<div className="align-items-center d-flex justify-content-between">
<div className="tj-text-sm font-weight-500" data-cy="env-name">

View file

@ -0,0 +1,49 @@
import React from 'react';
import { Alert } from '@/_ui/Alert/Alert';
import './resources/styles.scss';
const DEFAULT_CONFIG = {
docsLink: ' https://docs.tooljet.com/docs/data-sources/local-data-sources-migration',
};
const DEFAULT_MESSAGES = {
prefix: 'This query is connected to a local data source which has been',
highlightedText: 'discontinued',
middle: 'Please create a global data source connection to reconnect your query.',
suffix: 'to know more.',
linkText: 'Read documentation',
};
const NotificationBanner = ({
docsLink,
customMessage,
darkMode = false,
highlightedText = DEFAULT_MESSAGES.highlightedText,
highlightedClassName = 'highlighted-text',
enhanceDisabledVisibility = false,
}) => {
const currentDocsLink = docsLink || DEFAULT_CONFIG.docsLink;
const bannerMessage = customMessage || (
<>
{DEFAULT_MESSAGES.prefix} <span className={highlightedClassName}>{highlightedText}</span>.{' '}
{DEFAULT_MESSAGES.middle}{' '}
<a href={currentDocsLink} className="documentation-link" target="_blank" rel="noopener noreferrer">
{DEFAULT_MESSAGES.linkText}
</a>{' '}
{DEFAULT_MESSAGES.suffix}
</>
);
return (
<div className="notification-banner-component">
<Alert svg="info-icon" cls="notification-banner" useDarkMode={darkMode}>
<div className={`notification-content ${enhanceDisabledVisibility ? 'disabled' : ''}`}>{bannerMessage}</div>
</Alert>
</div>
);
};
export default NotificationBanner;
// To Do later: Expand this component properly to make it generic notification component

View file

@ -0,0 +1 @@
export { default } from './NotificationBanner';

View file

@ -0,0 +1,55 @@
.notification-banner {
display: flex;
padding: var(--3, 6px) var(--6, 12px);
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 32px;
flex: 1 0 0;
border-radius: var(--3, 6px);
background: var(--background-warning-weak, #FAEFE7);
border: none !important;
outline: none !important;
opacity: 1;
img {
margin-top: -5px !important;
}
}
@media screen and (min-width: 1200px) {
.notification-banner {
justify-content: center !important;
align-items: center !important;
}
&>div {
justify-content: center !important;
}
}
.notification-content {
color: var(--text-default, #1B1F24);
font-family: "IBM Plex Sans";
font-size: 11px;
font-style: normal;
font-weight: 400;
line-height: 16px;
&.disabled {
font-weight: 700 !important;
opacity: 1 !important;
}
}
.highlighted-text {
font-weight: 600 !important;
font-style: bold;
}
.documentation-link {
font-weight: 400 !important;
color: var(--primary, #3E63DD) !important;
text-decoration-line: underline !important;
}

View file

@ -148,9 +148,9 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => {
setSlug({ value: defaultValue, error: '' });
const checkWorkspaceUniqueness = async () => {
sluginput.current.value = defaultValue;
try {
await organizationService.checkWorkspaceUniqueness(null, defaultValue);
sluginput.current.value = defaultValue;
} catch (errResponse) {
let error = {
status: false,

View file

@ -7864,7 +7864,7 @@ tbody {
.marketplace-page-sidebar {
height: calc(100vh - 64px);
max-width: 288px;
max-width: 272px;
background-color: var(--page-default);
border-right: 1px solid var(--slate5) !important;
display: grid !important;
@ -12830,6 +12830,11 @@ color: var(--text-default);
padding: 16px;
padding-top: 0px;
padding-bottom: 0px;
.p-3-constants{
padding: 1rem !important;
padding-left: 0px !important;
}
}
.card-footer {

View file

@ -1 +1 @@
3.0.3-ce-lts
3.0.4-ce-lts

View file

@ -424,3 +424,13 @@ export function mergeDeep(target, source, seen = new WeakMap()) {
return target;
}
export const getSubpath = () => {
const subpath = process.env.SUB_PATH || '';
// Ensure subpath starts and ends with slashes
if (subpath) {
if (!subpath.startsWith('/') || !subpath.endsWith('/')) {
throw new Error('SUB_PATH must start and end with a slash');
}
}
return subpath;
};

View file

@ -13,6 +13,7 @@ import { bootstrap as globalAgentBootstrap } from 'global-agent';
import { join } from 'path';
import * as helmet from 'helmet';
import * as express from 'express';
import { getSubpath } from '@helpers/utils.helper';
const fs = require('fs');
@ -100,7 +101,15 @@ function setSecurityHeaders(app, configService) {
app.use((req, res, next) => {
res.setHeader('Permissions-Policy', 'geolocation=(self), camera=(), microphone=()');
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
const subpath = getSubpath();
const path = req.path.replace(subpath, subpath ? '/' : '');
if (path.startsWith('/api/')) {
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
} else {
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
}
return next();
});
}