diff --git a/.github/workflows/packer-build.yml b/.github/workflows/packer-build.yml index 81fb71f11f..7c1dfbb583 100644 --- a/.github/workflows/packer-build.yml +++ b/.github/workflows/packer-build.yml @@ -69,7 +69,7 @@ jobs: with: command: build #The the below argument is specific for building EE AMI image - arguments: -color=false -on-error=abort -var ami_name=tooljet_${{ env.RELEASE_VERSION }}.ubuntu_focal + arguments: -color=false -on-error=abort -var ami_name=tooljet_${{ env.RELEASE_VERSION }}.ubuntu_jammy target: . working_directory: deploy/ec2/ee env: @@ -78,9 +78,9 @@ jobs: - name: Send Slack Notification run: | if [[ "${{ job.status }}" == "success" ]]; then - message="ToolJet enterprise AWS AMI published:\\n\`tooljet_${{ env.RELEASE_VERSION }}.ubuntu_focal\`" + message="ToolJet enterprise AWS AMI published:\\n\`tooljet_${{ env.RELEASE_VERSION }}.ubuntu-jammy\`" else - message="ToolJet enterprise AWS AMI release failed! \\n\`tooljet_${{ env.RELEASE_VERSION }}.ubuntu_focal\`" + message="ToolJet enterprise AWS AMI release failed! \\n\`tooljet_${{ env.RELEASE_VERSION }}.ubuntu-jammy\`" fi curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$message\"}" ${{ secrets.SLACK_WEBHOOK_URL }} \ No newline at end of file diff --git a/cypress-tests/cypress-marketplace.config.js b/cypress-tests/cypress-marketplace.config.js index b8ffbeaa26..ce955b3c66 100644 --- a/cypress-tests/cypress-marketplace.config.js +++ b/cypress-tests/cypress-marketplace.config.js @@ -77,7 +77,7 @@ module.exports = defineConfig({ baseUrl: "http://localhost:8082", specPattern: [ "cypress/e2e/happyPath/marketplace/commonTestcases/**/*.cy.js", - ], + ] numTestsKeptInMemory: 1, redirectionLimit: 7, experimentalRunAllSpecs: true, diff --git a/cypress-tests/cypress/commands/commands.js b/cypress-tests/cypress/commands/commands.js index 98cbcb31d0..79fea8849f 100644 --- a/cypress-tests/cypress/commands/commands.js +++ b/cypress-tests/cypress/commands/commands.js @@ -239,9 +239,9 @@ Cypress.Commands.add( .invoke("text") .then((text) => { cy.wrap(subject).realType(createBackspaceText(text)), - { - delay: 0, - }; + { + delay: 0, + }; }); } ); @@ -561,7 +561,7 @@ Cypress.Commands.add("installMarketplacePlugin", (pluginName) => { } }); - function installPlugin (pluginName) { + function installPlugin(pluginName) { cy.get('[data-cy="-list-item"]').eq(1).click(); cy.wait(1000); @@ -621,6 +621,7 @@ Cypress.Commands.add("uninstallMarketplacePlugin", (pluginName) => { Cypress.Commands.add( "verifyRequiredFieldValidation", (fieldName, expectedColor) => { + cy.get(commonSelectors.textField(fieldName)).type("some text").clear(); cy.get(commonSelectors.textField(fieldName)).should( "have.css", "border-color", diff --git a/cypress-tests/cypress/e2e/happyPath/marketplace/commonTestcases/data-source/airTableHappyPath.cy.js b/cypress-tests/cypress/e2e/happyPath/marketplace/commonTestcases/data-source/airTableHappyPath.cy.js index 0f3cf9c7a5..9e383b041d 100644 --- a/cypress-tests/cypress/e2e/happyPath/marketplace/commonTestcases/data-source/airTableHappyPath.cy.js +++ b/cypress-tests/cypress/e2e/happyPath/marketplace/commonTestcases/data-source/airTableHappyPath.cy.js @@ -202,10 +202,10 @@ describe("Data source Airtable", () => { ); cy.get(dataSourceSelector.queryPreviewButton).click(); - cy.verifyToastMessage( - commonSelectors.toastMessage, - `Query (${data.dsName}) completed.` - ); + // cy.verifyToastMessage( + // commonSelectors.toastMessage, + // `Query (${data.dsName}) completed.` + // ); // Verfiy Retrieve record operation @@ -225,10 +225,10 @@ describe("Data source Airtable", () => { ); cy.get(dataSourceSelector.queryPreviewButton).click(); - cy.verifyToastMessage( - commonSelectors.toastMessage, - `Query (${data.dsName}) completed.` - ); + // cy.verifyToastMessage( + // commonSelectors.toastMessage, + // `Query (${data.dsName}) completed.` + // ); // Verfiy Create record operation @@ -251,10 +251,10 @@ describe("Data source Airtable", () => { .realType('": {}', { force: true, delay: 0 }); cy.get(dataSourceSelector.queryPreviewButton).click(); - cy.verifyToastMessage( - commonSelectors.toastMessage, - `Query (${data.dsName}) completed.` - ); + // cy.verifyToastMessage( + // commonSelectors.toastMessage, + // `Query (${data.dsName}) completed.` + // ); // Verfiy Update record operation @@ -285,10 +285,10 @@ describe("Data source Airtable", () => { .realType('"Phone Number": "555_98"', { force: true, delay: 0 }); cy.get(dataSourceSelector.queryPreviewButton).click(); - cy.verifyToastMessage( - commonSelectors.toastMessage, - `Query (${data.queryName}) completed.` - ); + // cy.verifyToastMessage( + // commonSelectors.toastMessage, + // `Query (${data.queryName}) completed.` + // ); // Verify Delete record operation @@ -337,10 +337,10 @@ describe("Data source Airtable", () => { ); cy.get(dataSourceSelector.queryPreviewButton).click(); - cy.verifyToastMessage( - commonSelectors.toastMessage, - `Query (${data.queryName}) completed.` - ); + // cy.verifyToastMessage( + // commonSelectors.toastMessage, + // `Query (${data.queryName}) completed.` + // ); cy.apiDeleteApp(`${data.dsName}-airtable-app`); cy.apiDeleteGDS(`cypress-${data.dsName}-airtable`); diff --git a/cypress-tests/cypress/e2e/happyPath/marketplace/commonTestcases/data-source/postgresHappyPath.cy.js b/cypress-tests/cypress/e2e/happyPath/marketplace/commonTestcases/data-source/postgresHappyPath.cy.js index b86ca7cb17..962baeb991 100644 --- a/cypress-tests/cypress/e2e/happyPath/marketplace/commonTestcases/data-source/postgresHappyPath.cy.js +++ b/cypress-tests/cypress/e2e/happyPath/marketplace/commonTestcases/data-source/postgresHappyPath.cy.js @@ -254,7 +254,7 @@ describe("Data sources", () => { .and("be.disabled"); cy.get(dataSourceSelector.connectionAlertText).verifyVisibleElement( "have.text", - "connect ECONNREFUSED 127.0.0.1:5432" + postgreSqlText.serverNotSuppotSsl ); cy.apiDeleteGDS(`cypress-${data.dataSourceName}-postgresql`); diff --git a/deploy/ec2/ee/setup_machine.sh b/deploy/ec2/ee/setup_machine.sh index 0173bd45c6..5dd6c635fd 100644 --- a/deploy/ec2/ee/setup_machine.sh +++ b/deploy/ec2/ee/setup_machine.sh @@ -118,4 +118,5 @@ npm install -g npm@10.9.2 # Building ToolJet app npm install -g @nestjs/cli +export NODE_OPTIONS='--max-old-space-size=8000' TOOLJET_EDTION=ee npm run build diff --git a/deploy/ec2/ee/tooljet_ubuntu_focal.pkr.hcl b/deploy/ec2/ee/tooljet_ubuntu_focal.pkr.hcl index 144803d55c..675c67f4b5 100644 --- a/deploy/ec2/ee/tooljet_ubuntu_focal.pkr.hcl +++ b/deploy/ec2/ee/tooljet_ubuntu_focal.pkr.hcl @@ -16,7 +16,7 @@ source "amazon-ebs" "ubuntu" { source_ami_filter { filters = { - name = "ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*" + name = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*" root-device-type = "ebs" virtualization-type = "hvm" } @@ -30,7 +30,7 @@ source "amazon-ebs" "ubuntu" { launch_block_device_mappings { device_name = "/dev/sda1" - volume_size = 10 + volume_size = 30 delete_on_termination = true } @@ -47,7 +47,7 @@ build { } provisioner "file" { - source = "../../frontend/config/nginx.conf.template" + source = "../../../frontend/config/nginx.conf.template" destination = "/tmp/nginx.conf" } diff --git a/deploy/ec2/ee/variables.pkr.hcl b/deploy/ec2/ee/variables.pkr.hcl index 39dcdfd3cd..f18073b73b 100644 --- a/deploy/ec2/ee/variables.pkr.hcl +++ b/deploy/ec2/ee/variables.pkr.hcl @@ -4,7 +4,7 @@ variable "ami_name" { variable "instance_type" { type = string - default = "t2.medium" + default = "t2.large" } variable "ami_region" { diff --git a/frontend/ee b/frontend/ee index 3297d43038..aed7af0149 160000 --- a/frontend/ee +++ b/frontend/ee @@ -1 +1 @@ -Subproject commit 3297d4303806594bd3f5b614df9057c8ceaa92b3 +Subproject commit aed7af0149525ff745650c21ee40bf9caf2892dc diff --git a/frontend/src/App/App.jsx b/frontend/src/App/App.jsx index d3cda91e3f..e7a5b21f11 100644 --- a/frontend/src/App/App.jsx +++ b/frontend/src/App/App.jsx @@ -38,6 +38,7 @@ import { getDataSourcesRoutes, getAuditLogsRoutes, } from '@/modules'; +import { isWorkflowsFeatureEnabled } from '@/modules/common/helpers/utils'; import { shallow } from 'zustand/shallow'; import useStore from '@/AppBuilder/_stores/store'; import { checkIfToolJetCloud } from '@/_helpers/utils'; @@ -112,6 +113,7 @@ class AppComponent extends React.Component { const featureAccess = await licenseService.getFeatureAccess(); const isBasicPlan = !featureAccess?.licenseStatus?.isLicenseValid || featureAccess?.licenseStatus?.isExpired; this.setState({ showBanner: isBasicPlan }); + this.updateColorScheme(); } // check if its getting routed from editor checkPreviousRoute = (route) => { @@ -121,7 +123,7 @@ class AppComponent extends React.Component { return false; }; - componentDidUpdate(prevProps) { + componentDidUpdate(prevProps, prevState) { // Check if the current location is the dashboard (homepage) if ( this.props.location.pathname === `/${getWorkspaceIdOrSlugFromURL()}` && @@ -134,18 +136,24 @@ class AppComponent extends React.Component { } // Update margin when showBanner changes this.updateMargin(); + // Update color scheme if darkMode changed + if (prevState.darkMode !== this.state.darkMode) { + this.updateColorScheme(); + } } switchDarkMode = (newMode) => { this.setState({ darkMode: newMode }); this.props.updateIsTJDarkMode(newMode); localStorage.setItem('darkMode', newMode); + this.updateColorScheme(newMode); }; isEditorOrViewerFromPath = () => { const pathname = this.props.location.pathname; if (pathname.includes('/apps/')) { return 'editor'; - } else if (pathname.includes('/applications/') || pathname.includes('/embed-apps/')) { + } + if (pathname.includes('/applications/') || pathname.includes('/embed-apps/')) { return 'viewer'; } return ''; @@ -156,6 +164,14 @@ class AppComponent extends React.Component { isExistingPlanUser = (date) => { return new Date(date) < new Date('2025-04-24'); //show banner if user created before 2 april (24 for testing) }; + updateColorScheme = (darkModeValue) => { + const isDark = darkModeValue !== undefined ? darkModeValue : this.state.darkMode; + if (isDark) { + document.documentElement.style.setProperty('color-scheme', 'dark'); + } else { + document.documentElement.style.removeProperty('color-scheme'); + } + }; render() { const { updateAvailable, darkMode, isEditorOrViewer, showBanner } = this.state; const mergedProps = { @@ -278,7 +294,7 @@ class AppComponent extends React.Component { } /> - {window.public_config?.ENABLE_WORKFLOWS_FEATURE === 'true' && ( + {isWorkflowsFeatureEnabled() && ( )} - } - > + } /> } - > - }> + /> + + } + /> - + diff --git a/frontend/src/AppBuilder/QueryManager/Components/DataSourcePicker.jsx b/frontend/src/AppBuilder/QueryManager/Components/DataSourcePicker.jsx index 1c6ebe9ebd..30f2828ae8 100644 --- a/frontend/src/AppBuilder/QueryManager/Components/DataSourcePicker.jsx +++ b/frontend/src/AppBuilder/QueryManager/Components/DataSourcePicker.jsx @@ -14,6 +14,7 @@ import { useQueryPanelActions } from '@/_stores/queryPanelStore'; import { Tooltip } from 'react-tooltip'; import { canCreateDataSource } from '@/_helpers'; import SolidIcon from '@/_ui/Icon/SolidIcons'; +import { isWorkflowsFeatureEnabled } from '@/modules/common/helpers/utils'; import '../queryManager.theme.scss'; import useStore from '@/AppBuilder/_stores/store'; import { staticDataSources } from '../constants'; @@ -80,7 +81,7 @@ function DataSourcePicker({ darkMode }) { navigate(`/${workspaceId}/data-sources`); }; - const workflowsEnabled = window.public_config?.ENABLE_WORKFLOWS_FEATURE == 'true'; + const workflowsEnabled = isWorkflowsFeatureEnabled(); return ( <> diff --git a/frontend/src/AppBuilder/QueryManager/Components/DataSourceSelect.jsx b/frontend/src/AppBuilder/QueryManager/Components/DataSourceSelect.jsx index ed40086216..52a9e8c1ea 100644 --- a/frontend/src/AppBuilder/QueryManager/Components/DataSourceSelect.jsx +++ b/frontend/src/AppBuilder/QueryManager/Components/DataSourceSelect.jsx @@ -15,6 +15,7 @@ import { DataBaseSources, ApiSources, CloudStorageSources } from '@/modules/comm import { canCreateDataSource } from '@/_helpers'; import './../queryManager.theme.scss'; import { DATA_SOURCE_TYPE } from '@/_helpers/constants'; +import { isWorkflowsFeatureEnabled } from '@/modules/common/helpers/utils'; import useStore from '@/AppBuilder/_stores/store'; function DataSourceSelect({ isDisabled, selectRef, closePopup, workflowDataSources, onNewNode, defaultDataSources }) { @@ -39,7 +40,7 @@ function DataSourceSelect({ isDisabled, selectRef, closePopup, workflowDataSourc closePopup(); }; - const workflowsEnabled = window.public_config?.ENABLE_WORKFLOWS_FEATURE == 'true'; + const workflowsEnabled = isWorkflowsFeatureEnabled(); const staticDataSources = workflowsEnabled ? staticDatasources : staticDatasources.filter((ds) => ds?.kind !== 'workflows'); diff --git a/frontend/src/AppBuilder/QueryManager/QueryEditors/Restapi/index.jsx b/frontend/src/AppBuilder/QueryManager/QueryEditors/Restapi/index.jsx index 547aa5452c..e5a9849c35 100644 --- a/frontend/src/AppBuilder/QueryManager/QueryEditors/Restapi/index.jsx +++ b/frontend/src/AppBuilder/QueryManager/QueryEditors/Restapi/index.jsx @@ -9,6 +9,7 @@ import { BaseUrl } from './BaseUrl'; import { queryManagerSelectComponentStyle } from '@/_ui/Select/styles'; import CodeHinter from '@/AppBuilder/CodeEditor'; import { deepClone } from '@/_helpers/utilities/utils.helpers'; +import './styles.css'; class Restapi extends React.Component { constructor(props) { @@ -287,14 +288,15 @@ class Restapi extends React.Component { const { options } = this.state; const dataSourceURL = this.props.selectedDataSource?.options?.url?.value; const queryName = this.props.queryName; + const isWorkflowNode = queryName === 'workflowNode'; const currentValue = { label: options.method?.toUpperCase(), value: options.method }; return ( -
+
{this.props.selectedDataSource?.scope == 'global' &&
}{' '}
-
-
+
+

-
-
+
+
- - -
- )} +   + {appType !== 'workflow' + ? t('blankPage.importApplication', 'Import an app') + : t('blankPage.importWorkflow', 'Import a workflow')} + + + +
diff --git a/frontend/src/HomePage/Folders.jsx b/frontend/src/HomePage/Folders.jsx index 3a94991f4e..4e4a735687 100644 --- a/frontend/src/HomePage/Folders.jsx +++ b/frontend/src/HomePage/Folders.jsx @@ -14,6 +14,8 @@ import _ from 'lodash'; import { validateName, handleHttpErrorMessages, getWorkspaceId } from '@/_helpers/utils'; import { useNavigate, useLocation } from 'react-router-dom'; import FolderSkeleton from '@/_ui/FolderSkeleton/FolderSkeleton'; +import { Button } from '@/components/ui/Button/Button'; + export const Folders = function Folders({ folders, foldersLoading, @@ -246,24 +248,36 @@ export const Folders = function Folders({
{canCreateFolder && ( <> -
{ setNewFolderName(''); setShowForm(true); }} data-cy="create-new-folder-button" > - -
-
+ +
+ + )}
@@ -287,8 +301,7 @@ export const Folders = function Folders({ className={cx( `list-group-item border-0 list-group-item-action d-flex align-items-center all-apps-link tj-text-xsm`, { - 'bg-light-indigo': _.isEmpty(activeFolder) && !darkMode, - 'bg-dark-indigo': _.isEmpty(activeFolder) && darkMode, + 'tw-bg-interactive-default': _.isEmpty(activeFolder), } )} style={{ height: '32px' }} @@ -314,8 +327,7 @@ export const Folders = function Folders({ className={cx( `folder-list-group-item rounded-2 list-group-item h-4 mb-1 list-group-item-action no-border d-flex align-items-center`, { - 'bg-light-indigo': activeFolder.id === folder.id && !darkMode, - 'bg-dark-indigo': activeFolder.id === folder.id && darkMode, + 'tw-bg-interactive-default': activeFolder.id === folder.id, } )} onClick={() => { diff --git a/frontend/src/HomePage/Header.jsx b/frontend/src/HomePage/Header.jsx index aa6580cb29..d37e19bbbc 100644 --- a/frontend/src/HomePage/Header.jsx +++ b/frontend/src/HomePage/Header.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { SearchBox } from '@/_components/SearchBox'; +import { SearchBox } from '@/_components/PageSearchBox'; import { useTranslation } from 'react-i18next'; export default function HomeHeader({ onSearchSubmit, darkMode, appType }) { @@ -14,17 +14,15 @@ export default function HomeHeader({ onSearchSubmit, darkMode, appType }) { : t('globals.workflowsSearchItem', 'Search workflows in this workspace'); return ( -
-
- -
+
+
); } diff --git a/frontend/src/HomePage/HomePage.jsx b/frontend/src/HomePage/HomePage.jsx index 8f387a1650..31aa2dfee0 100644 --- a/frontend/src/HomePage/HomePage.jsx +++ b/frontend/src/HomePage/HomePage.jsx @@ -12,7 +12,7 @@ import { } from '@/_services'; import { ConfirmDialog, AppModal, ToolTip } from '@/_components'; import Select from '@/_ui/Select'; -import _, { sample, isEmpty, capitalize } from 'lodash'; +import _, { sample, isEmpty, capitalize, has } from 'lodash'; import { Folders } from './Folders'; import { BlankPage } from './BlankPage'; import { toast } from 'react-hot-toast'; @@ -48,6 +48,7 @@ import { } from '@/modules/dashboard/components'; import CreateAppWithPrompt from '@/modules/AiBuilder/components/CreateAppWithPrompt'; import SolidIcon from '@/_ui/Icon/SolidIcons'; +import { isWorkflowsFeatureEnabled } from '@/modules/common/helpers/utils'; import EmptyModuleSvg from '../../assets/images/icons/empty-modules.svg'; const { iconList, defaultIcon } = configs; @@ -256,7 +257,11 @@ class HomePageComponent extends React.Component { }; getAppType = () => { - return this.props.appType === 'module' ? 'Module' : this.props.appType === 'workflow' ? 'Workflow' : 'App'; + const { appType } = this.props; + if (appType === 'front-end') return 'App'; + if (appType === 'workflow') return 'Workflow'; + if (appType === 'module') return 'Module'; + return 'app'; }; createApp = async (appName, type, prompt) => { @@ -339,6 +344,66 @@ class HomePageComponent extends React.Component { this.setState({ isExportingApp: true, app: app }); }; + exportAppDirectly = async (app) => { + try { + const fetchVersions = await appsService.getVersions(app.id); + const { versions } = fetchVersions; + + const currentEditingVersion = versions?.filter((version) => version?.isCurrentEditingVersion)[0]; + if (!currentEditingVersion) { + toast.error('Could not find current editing version.', { + position: 'top-center', + }); + return; + } + + // Export all TJDB tables used by default + const fetchTables = await appsService.getTables(app.id); + const { tables: allTables } = fetchTables; + + const versionId = currentEditingVersion.id; + const exportTjDb = true; + const exportTables = allTables; + + const appOpts = { + app: [ + { + id: app.id, + search_params: { version_id: versionId }, + }, + ], + }; + + const requestBody = { + ...appOpts, + ...(exportTjDb && { tooljet_database: exportTables }), + organization_id: app.organization_id, + }; + + const data = await appsService.exportResource(requestBody); + + const appName = app.name.replace(/\s+/g, '-').toLowerCase(); + const fileName = `${appName}-export-${new Date().getTime()}`; + const json = JSON.stringify(data, null, 2); + const blob = new Blob([json], { type: 'application/json' }); + const href = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = href; + link.download = fileName + '.json'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + + toast.success('Workflow exported successfully!', { + position: 'top-center', + }); + } catch (error) { + toast.error(`Could not export workflow: ${error?.data?.message || error.message}`, { + position: 'top-center', + }); + } + }; + readAndImport = (event) => { try { const file = event.target.files[0]; @@ -413,7 +478,7 @@ class HomePageComponent extends React.Component { let installedPluginsInfo = []; try { if (this.state.dependentPlugins.length) { - ({ installedPluginsInfo = [] } = await pluginsService.installDependentPlugins( + ({ installedPluginsInfo =[] } = await pluginsService.installDependentPlugins( this.state.dependentPlugins, true )); @@ -421,8 +486,7 @@ class HomePageComponent extends React.Component { if (importJSON.app[0].definition.appV2.type !== this.props.appType) { toast.error( - `${this.props.appType === 'module' ? 'App' : 'Module'} could not be imported in ${ - this.props.appType === 'module' ? 'modules' : 'apps' + `${this.props.appType === 'module' ? 'App' : 'Module'} could not be imported in ${this.props.appType === 'module' ? 'modules' : 'apps' } section. Switch to ${this.props.appType === 'module' ? 'apps' : 'modules'} section and try again.`, { style: { maxWidth: '425px' } } ); @@ -453,7 +517,7 @@ class HomePageComponent extends React.Component { this.setState({ isImportingApp: false }); if (error.statusCode === 409) return false; - toast.error(error?.error || error?.message || 'App import failed'); + toast.error(error?.error || error?.message || `${capitalize(this.getAppType())} import failed`); } }; @@ -485,7 +549,7 @@ class HomePageComponent extends React.Component { }; canViewWorkflow = () => { - return this.canUserPerform(this.state.currentUser, 'view'); + return this.canUserPerform(this.state.currentUser, 'view') && isWorkflowsFeatureEnabled(); }; canUserPerform(user, action, app) { @@ -953,6 +1017,53 @@ class HomePageComponent extends React.Component { importingGitAppOperations: validationMessage, }); }; + + // Helper functions for workflow limit checks + hasWorkflowLimitReached = () => { + const { workflowInstanceLevelLimit, workflowWorkspaceLevelLimit } = this.state; + + const instanceLimitReached = + workflowInstanceLevelLimit.total === 0 || workflowInstanceLevelLimit.current >= workflowInstanceLevelLimit.total; + const workspaceLimitReached = + workflowWorkspaceLevelLimit.total === 0 || + workflowWorkspaceLevelLimit.current >= workflowWorkspaceLevelLimit.total; + + return instanceLimitReached || workspaceLimitReached; + }; + + hasWorkflowLimitWarning = () => { + const { workflowInstanceLevelLimit, workflowWorkspaceLevelLimit } = this.state; + return this.hasInstanceLimitWarning() || this.hasWorkspaceLimitWarning(); + }; + + hasInstanceLimitWarning = () => { + const { workflowInstanceLevelLimit } = this.state; + const percentage = workflowInstanceLevelLimit.percentage; + + return ( + workflowInstanceLevelLimit.current >= workflowInstanceLevelLimit.total || + (percentage >= 90 && percentage < 100) || + workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1 + ); + }; + + hasWorkspaceLimitWarning = () => { + const { workflowWorkspaceLevelLimit } = this.state; + const percentage = workflowWorkspaceLevelLimit.percentage; + + return ( + workflowWorkspaceLevelLimit.current >= workflowWorkspaceLevelLimit.total || + (percentage >= 90 && percentage < 100) || + workflowWorkspaceLevelLimit.current === workflowWorkspaceLevelLimit.total - 1 + ); + }; + + getWorkflowLimit = () => { + return this.hasInstanceLimitWarning() + ? this.state.workflowInstanceLevelLimit + : this.state.workflowWorkspaceLevelLimit; + }; + render() { const { apps, @@ -1012,7 +1123,7 @@ class HomePageComponent extends React.Component { } else if (this.props.appType === 'front-end') { return appsLimit?.percentage >= 100; } else { - return workflowInstanceLevelLimit.percentage >= 100 || workflowWorkspaceLevelLimit.percentage >= 100; + return this.hasWorkflowLimitReached(); } }; const modalConfigs = { @@ -1113,9 +1224,8 @@ class HomePageComponent extends React.Component {
User groups @@ -1191,8 +1301,8 @@ class HomePageComponent extends React.Component { this.props.appType === 'workflow' ? 'homePage.deleteWorkflowAndData' : this.props.appType === 'front-end' - ? 'homePage.deleteAppAndData' - : deleteModuleText, + ? 'homePage.deleteAppAndData' + : deleteModuleText, { appName: appToBeDeleted?.name, } @@ -1457,22 +1567,18 @@ class HomePageComponent extends React.Component { {this.props.appType === 'module' ? 'Create new module' : this.props.t( - `${ - this.props.appType === 'workflow' ? 'workflowsDashboard' : 'homePage' - }.header.createNewApplication`, - 'Create new app' - )} + `${this.props.appType === 'workflow' ? 'workflowsDashboard' : 'homePage' + }.header.createNewApplication`, + 'Create new app' + )} - - {this.props.appType !== 'workflow' && ( - - )} + = workflowInstanceLevelLimit.total || - 100 > workflowInstanceLevelLimit.percentage >= 90 || - workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1 + 100 > workflowInstanceLevelLimit.percentage >= 90 || + workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1 ? workflowInstanceLevelLimit : workflowWorkspaceLevelLimit } @@ -1545,12 +1651,7 @@ class HomePageComponent extends React.Component {
-
+
{featuresLoaded && !isLoading ? ( <> @@ -1577,15 +1678,12 @@ class HomePageComponent extends React.Component { {(meta?.total_count > 0 || appSearchKey) && ( <> {!(isLoading && !appSearchKey) && ( - <> - -
- + )}
{currentFolder?.count ?? meta?.total_count} APPS @@ -1633,8 +1731,8 @@ class HomePageComponent extends React.Component { appType={this.props.appType} workflowsLimit={ workflowInstanceLevelLimit.current >= workflowInstanceLevelLimit.total || - 100 > workflowInstanceLevelLimit.percentage >= 90 || - workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1 + 100 > workflowInstanceLevelLimit.percentage >= 90 || + workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1 ? workflowInstanceLevelLimit : workflowWorkspaceLevelLimit } @@ -1679,7 +1777,7 @@ class HomePageComponent extends React.Component { canUpdateApp={this.canUpdateApp} deleteApp={this.deleteApp} cloneApp={this.cloneApp} - exportApp={this.exportApp} + exportApp={this.props.appType === 'workflow' ? this.exportAppDirectly : this.exportApp} meta={meta} currentFolder={currentFolder} isLoading={isLoading || !featuresLoaded} diff --git a/frontend/src/HomePage/styles/homepage.scss b/frontend/src/HomePage/styles/homepage.scss new file mode 100644 index 0000000000..5f94c9668f --- /dev/null +++ b/frontend/src/HomePage/styles/homepage.scss @@ -0,0 +1,295 @@ +.home-page-sidebar { + height: calc(100vh - 48px) !important; //64 is navbar height + + .folder-list-user { + height: calc(100vh - 116px) !important; //64 is navbar height + 52 px footer + } +} + +.app-list { + margin: 24px 0; +} + +.home-search-holder { + height: 48px; + width: 100%; + margin-top: 32px; +} +.homepage-app-card-list-item-wrap { + column-gap: 24px; + row-gap: 24px; + flex-wrap: wrap; + display: flex; +} + +.homepage-app-card-list-item { + max-width: 272px; + flex-basis: 33%; + padding: 0 !important; +} + +.homepage-dropdown-style { + min-width: 11rem; + display: block; + align-items: center; + margin: 0; + line-height: 1.4285714; + width: 100%; + padding: 0.5rem 0.75rem !important; + font-weight: 400; + white-space: nowrap; + border: 0; + cursor: pointer; + font-size: 12px; +} + +.homepage-dropdown-style:hover { + background: rgba(101, 109, 119, 0.06); +} + +.menu-icon--trigger { + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 10px; + background-color: var(--background-surface-layer-01); + box-shadow: none; + transition: all 0.15s ease-in-out; + will-change: background-color, box-shadow; + + &:hover { + background-color: var(--background-surface-layer-02); + box-shadow: var(--elevation-000-box-shadow); + } +} + +.home-app-card-header { + margin-bottom: 32px; +} + +.homepage-app-card { + height: 160px; + padding: 16px; + + .app-icon-main { + background: var(--indigo3) !important; + border-radius: 6px !important; + display: flex; + justify-content: center; + align-items: center; + width: 48px; + height: 48px; + will-change: height, width; + transition: all 0.15s ease-in-out; + } + + .appcard-buttons-wrap { + visibility: hidden; + opacity: 0; + height: 0; + } + + .home-app-card-header { + .menu-ico { + visibility: hidden !important; + } + } + + &:hover { + .home-app-card-header { + margin-bottom: 12px; + + .menu-ico { + visibility: visible !important; + } + } + + .app-creation-time-container { + margin-bottom: 0px; + } + + .app-card-name { + margin-bottom: 0px; + } + + .app-creation-time { + // display: none; + } + + .appcard-buttons-wrap { + display: flex; + visibility: visible; + opacity: 1; + padding: 0px; + gap: 12px; + width: 240px; + height: 28px; + flex-direction: row; + transition: all 0.15s ease-in-out; + will-change: opacity, visibility; + + div { + a { + text-decoration: none; + } + } + } + + .app-icon-main { + width: 36px; + height: 36px; + } + } +} + +.home-page-content-container { + max-width: 880px; + + @media only screen and (max-width: 768px) { + margin-bottom: 0rem !important; + + .liner { + width: unset !important; + } + + .app-list { + overflow-y: auto; + height: calc(100vh - 26rem); + + .skeleton-container { + display: flex; + flex-direction: column; + + .col { + display: flex; + justify-content: center; + margin-bottom: 1rem; + } + + .card-skeleton-container { + width: 304px; + } + } + } + + .menu-ico { + display: none !important; + } + } +} + + +.home-page-footer { + height: 52px; + background-color: var(--page-weak) !important; + border-top: 1px solid var(--border-weak) !important; + width: calc(100% - 336px) !important; + + @media only screen and (max-width: 768px) { + position: unset; + width: 100%; + + .col-4, + .col-5 { + display: none; + } + + .pagination-container { + display: flex !important; + align-items: center; + justify-content: center; + } + } +} + +@media only screen and (min-width: 1728px) { + .homepage-app-card-list-item { + // max-width: 304px; + max-width: calc(33.3% - 16px); + + .edit-button, + .launch-button { + width: 129px !important; + } + } + + .home-page-content-container { + max-width: 976px; + } + + .liner { + width: 976px; + } +} + +@media only screen and (min-width: 1584px) and (max-width: 1727px) { + .homepage-app-card-list-item { + max-width: calc(33.3% - 16px); + } + + .edit-button, + .launch-button { + width: 113px !important; + } +} + +@media only screen and (min-width: 1312px) and (max-width: 1583px) { + .homepage-app-card-list-item { + // max-width: 264px; + max-width: calc(33.3% - 16px); + + .edit-button, + .launch-button { + width: 109px !important; + } + } +} + +@media only screen and (min-width: 993px) and (max-width: 1311px) { + .home-page-content-container { + max-width: 568px; + } + + .homepage-app-card-list-item-wrap { + row-gap: 20px; + } + + .homepage-app-card-list-item { + // max-width: 269px; + max-width: calc(50% - 12px); + flex-basis: 50%; + flex-grow: 1; + flex-shrink: 0; + + .edit-button, + .launch-button { + width: 111.5px !important; + } + } + + .liner { + width: 568px; + } +} + +@media only screen and (max-width: 992px) { + .homepage-app-card-list-item-wrap { + display: flex; + justify-content: center; + width: 100%; + gap: 24px; + } + + .homepage-app-card-list-item { + // max-width: 304px !important; + max-width: calc(50% - 12px); + flex-basis: 100%; + + .edit-button, + .launch-button { + width: 129px !important; + } + } +} diff --git a/frontend/src/MarketplacePage/MarketplaceCard.jsx b/frontend/src/MarketplacePage/MarketplaceCard.jsx index 1a2c07cf61..daf6e470f6 100644 --- a/frontend/src/MarketplacePage/MarketplaceCard.jsx +++ b/frontend/src/MarketplacePage/MarketplaceCard.jsx @@ -52,7 +52,7 @@ export const MarketplaceCard = ({ id, name, repo, description, version, isInstal return (
-
+
diff --git a/frontend/src/SettingsPage/SettingsPage.jsx b/frontend/src/SettingsPage/SettingsPage.jsx index 53dfcad2d8..e7768dcf5f 100644 --- a/frontend/src/SettingsPage/SettingsPage.jsx +++ b/frontend/src/SettingsPage/SettingsPage.jsx @@ -169,7 +169,7 @@ function SettingsPage(props) {
-
+

{t('header.profileSettingPage.profile', 'Profile')} @@ -244,8 +244,7 @@ function SettingsPage(props) {

-
-
+

{t('header.profileSettingPage.changePassword', 'Change password')} diff --git a/frontend/src/TooljetDatabase/Forms/TableSchema.jsx b/frontend/src/TooljetDatabase/Forms/TableSchema.jsx index 9bee86278a..e6a2359739 100644 --- a/frontend/src/TooljetDatabase/Forms/TableSchema.jsx +++ b/frontend/src/TooljetDatabase/Forms/TableSchema.jsx @@ -368,6 +368,12 @@ function TableSchema({ isDisabled={ isEditMode && columnDetails[index]?.constraints_type?.is_primary_key === true ? true : false } + classNames={{ + control: (state) => cx({ + '!tw-border-border-default': true, + }), + + }} />

diff --git a/frontend/src/TooljetDatabase/Forms/styles.scss b/frontend/src/TooljetDatabase/Forms/styles.scss index 7bc6fe366c..233850ee4e 100644 --- a/frontend/src/TooljetDatabase/Forms/styles.scss +++ b/frontend/src/TooljetDatabase/Forms/styles.scss @@ -548,7 +548,7 @@ } .empty-foreignkey-container { - border: 1px dashed #d7dbdf; + border: 1px dashed var(--border-default); height: 40px; width: 270px !important; border-radius: 100px !important; diff --git a/frontend/src/TooljetDatabase/Table/Header.jsx b/frontend/src/TooljetDatabase/Table/Header.jsx index 9774822a6f..53e43309fe 100644 --- a/frontend/src/TooljetDatabase/Table/Header.jsx +++ b/frontend/src/TooljetDatabase/Table/Header.jsx @@ -148,8 +148,8 @@ const Header = ({ return ( <>
-
-
+
+
<> diff --git a/frontend/src/TooljetDatabase/Table/styles.scss b/frontend/src/TooljetDatabase/Table/styles.scss index 5f32c6e68d..120148b5d8 100644 --- a/frontend/src/TooljetDatabase/Table/styles.scss +++ b/frontend/src/TooljetDatabase/Table/styles.scss @@ -97,8 +97,8 @@ z-index: 1; position: sticky; left: 66px; - border-right: 2px solid var(--light-slate-08, #C1C8CD); - background-color: white; + border-right: 2px solid var(--border-weak); + background-color: var(--surfaces-surface-01); } th { @@ -145,14 +145,14 @@ th:nth-child(2) { z-index: 2; left: 66px; - border-right: 2px solid var(--light-slate-08, #C1C8CD); + border-right: 2px solid var(--border-weak); } .dark-background { td:nth-child(1), td:nth-child(2) { - background-color: #2B394A; + background-color: var(--surfaces-surface-01); } } @@ -283,26 +283,6 @@ background-color: #2B2F30 !important; } -.empty-table-description { - font-size: 14px !important; - line-height: 20px !important; - margin-top: 5px !important; -} - -.empty-table-container { - display: flex; - align-items: center; - justify-content: center; - height: calc(100% - 95px); -} - -.tjdb-create-new-table { - width: 180px !important; - margin: 0px auto !important; - display: flex !important; - align-items: center !important; - justify-content: center !important; -} .keyPress-actions { diff --git a/frontend/src/TooljetDatabase/TableList/index.jsx b/frontend/src/TooljetDatabase/TableList/index.jsx index 61afc607c3..6686ffb989 100644 --- a/frontend/src/TooljetDatabase/TableList/index.jsx +++ b/frontend/src/TooljetDatabase/TableList/index.jsx @@ -8,6 +8,7 @@ import { ListItem } from '../TableListItem'; import { BreadCrumbContext } from '../../App/App'; import Search from '../Search'; import SolidIcon from '@/_ui/Icon/SolidIcons'; +import { Button } from '@/components/ui/Button/Button'; const List = () => { const { @@ -83,15 +84,23 @@ const List = () => { <> All tables ({filteredTables.length}) -
{ setShowInput(true); }} data-cy="create-new-folder-button" > - -
+ + ) : ( + + diff --git a/frontend/src/WorkflowEditor/LogsPanel/icons/triangle-right.svg b/frontend/src/WorkflowEditor/LogsPanel/icons/triangle-right.svg new file mode 100644 index 0000000000..9f8648e692 --- /dev/null +++ b/frontend/src/WorkflowEditor/LogsPanel/icons/triangle-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/_components/DynamicForm.jsx b/frontend/src/_components/DynamicForm.jsx index bdc7f71054..dcb0078909 100644 --- a/frontend/src/_components/DynamicForm.jsx +++ b/frontend/src/_components/DynamicForm.jsx @@ -253,6 +253,8 @@ const DynamicForm = ({ }) => { const source = schema?.source?.kind; const darkMode = localStorage.getItem('darkMode') === 'true'; + const workspaceConstant = options?.[key]?.workspace_constant; + const isWorkspaceConstant = !!workspaceConstant; if (!options) return; @@ -264,7 +266,7 @@ const DynamicForm = ({ (options?.[key]?.encrypted !== undefined ? options?.[key].encrypted : encrypted) || type === 'password'; return { type, - placeholder: useEncrypted ? '**************' : description, + placeholder: workspaceConstant ? workspaceConstant : useEncrypted ? '**************' : description, className: `form-control${handleToggle(controller)} ${useEncrypted && 'dynamic-form-encrypted-field'}`, style: { marginBottom: '0px !important' }, value: options?.[key]?.value || '', @@ -276,6 +278,7 @@ const DynamicForm = ({ workspaceVariables, workspaceConstants: currentOrgEnvironmentConstants, encrypted: useEncrypted, + isWorkspaceConstant: isWorkspaceConstant, }; } case 'toggle': @@ -509,10 +512,16 @@ const DynamicForm = ({ return; } const isEditing = computedProps[field]['disabled']; + const workspaceConstant = options?.[field]?.workspace_constant; + const isWorkspaceConstant = !!workspaceConstant; + if (isEditing) { - optionchanged(field, ''); + if (isWorkspaceConstant) { + optionchanged(field, workspaceConstant); + } else { + optionchanged(field, ''); + } } else { - //Send old field value if editing mode disabled for encrypted fields const newOptions = { ...options }; const oldFieldValue = selectedDataSource?.['options']?.[field]; if (oldFieldValue) { diff --git a/frontend/src/_components/DynamicFormV2.jsx b/frontend/src/_components/DynamicFormV2.jsx index 6554f43da2..3ea431b67e 100644 --- a/frontend/src/_components/DynamicFormV2.jsx +++ b/frontend/src/_components/DynamicFormV2.jsx @@ -8,7 +8,6 @@ import Headers from '@/_ui/HttpHeaders'; import Toggle from '@/_ui/Toggle'; import InputV3 from '@/_ui/Input-V3'; import { filter, find, isEmpty } from 'lodash'; -import { ButtonSolid } from './AppButton'; import { useGlobalDataSourcesStatus } from '@/_stores/dataSourcesStore'; import { canDeleteDataSource, canUpdateDataSource } from '@/_helpers'; import { OverlayTrigger, Tooltip } from 'react-bootstrap'; @@ -206,39 +205,63 @@ const DynamicFormV2 = ({ } const processFields = (fieldsObject) => { - Object.keys(fieldsObject).forEach((key) => { - const field = fieldsObject[key]; - const { widget, encrypted, key: propertyKey } = field; + const processNestedField = (field, propertyKey) => { + const { widget, encrypted } = field; - if (!canUpdateDataSource(selectedDataSource?.id) && !canDeleteDataSource()) { - encryptedFieldsProps[propertyKey] = { - disabled: !!selectedDataSource?.id, - }; - } else if (!isDataSourceEditing) { - if (widget === 'password' || encrypted) { - encryptedFieldsProps[propertyKey] = { - disabled: true, - }; - } - } else { - if ((widget === 'password' || encrypted) && !(propertyKey in computedProps)) { + const isEncryptedField = + widget === 'password-v3' || + widget === 'password-v3-textarea' || + widget === 'password' || + encrypted || + encryptedProperties.includes(propertyKey); + + if (isEncryptedField) { + if (computedProps[propertyKey] !== undefined && computedProps[propertyKey].disabled === false) { + encryptedFieldsProps[propertyKey] = { disabled: false }; + } else if (!isDataSourceEditing) { + encryptedFieldsProps[propertyKey] = { disabled: true }; + } else if (!(propertyKey in computedProps)) { encryptedFieldsProps[propertyKey] = { disabled: !!selectedDataSource?.id, }; } } + }; - // To check for nested dropdown-component-flip - if (widget === 'dropdown-component-flip') { - const selectedOption = options?.[field.key]?.value; + Object.keys(fieldsObject).forEach((key) => { + const field = fieldsObject[key]; - if (field.commonFields) { - processFields(field.commonFields); + if (field.key) { + processNestedField(field, field.key); + } + + // Check for nested structures and recursively process them + if (typeof field === 'object') { + if (field.widget === 'dropdown-component-flip') { + const selectedOption = options?.[field.key]?.value; + + if (field.commonFields) { + Object.keys(field.commonFields).forEach((commonKey) => { + const commonField = field.commonFields[commonKey]; + processNestedField(commonField, commonField.key); + }); + } + + if (selectedOption && fieldsObject[selectedOption]) { + processFields(fieldsObject[selectedOption]); + } } - if (selectedOption && fieldsObject[selectedOption]) { - processFields(fieldsObject[selectedOption]); - } + // For other nested objects, recursively process them + Object.keys(field).forEach((subKey) => { + if (typeof field[subKey] === 'object' && field[subKey] !== null) { + if (field[subKey].widget || field[subKey].key) { + processNestedField(field[subKey], field[subKey].key); + } else { + processFields({ [subKey]: field[subKey] }); + } + } + }); } }); }; @@ -264,6 +287,11 @@ const DynamicFormV2 = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedDataSource?.id, options, isDataSourceEditing]); + React.useEffect(() => { + const requiredFields = processAllOfConditions(schema, options); + setConditionallyRequiredProperties(requiredFields); + }, [options, processAllOfConditions, schema, selectedDataSource.id]); + const getElement = (type) => { switch (type) { case 'password': @@ -295,6 +323,8 @@ const DynamicFormV2 = ({ const currentValue = options?.[key]?.value; const skipValidation = (!hasUserInteracted && !showValidationErrors) || (!interactedFields.has(key) && !showValidationErrors); + const workspaceConstant = options?.[key]?.workspace_constant; + const isEditing = computedProps[key] && computedProps[key].disabled === false; const handleOptionChange = (key, value, flag = true) => { if (!hasUserInteracted) { @@ -309,10 +339,10 @@ const DynamicFormV2 = ({ case 'text': case 'textarea': { return { - key, + propertyKey: key, widget, label, - placeholder: isEncrypted ? '**************' : description, + placeholder: workspaceConstant ? workspaceConstant : isEncrypted ? '**************' : description, className: cx('form-control', { 'dynamic-form-encrypted-field': isEncrypted, }), @@ -321,20 +351,20 @@ const DynamicFormV2 = ({ value: currentValue || '', onChange: (e) => optionchanged(key, e.target.value, true), isGDS: true, - workspaceVariables: [], - workspaceConstants: [], encrypted: isEncrypted, onBlur, + workspaceVariables, + workspaceConstants: currentOrgEnvironmentConstants, }; } case 'password-v3': case 'password-v3-textarea': case 'text-v3': { return { - key, + propertyKey: key, widget, label, - placeholder: isEncrypted ? '**************' : description, + placeholder: workspaceConstant ? workspaceConstant : isEncrypted ? '**************' : description, className: cx('form-control', { 'dynamic-form-encrypted-field': isEncrypted, }), @@ -343,8 +373,6 @@ const DynamicFormV2 = ({ value: currentValue || '', onChange: (e) => handleOptionChange(key, e.target.value, true), isGDS: true, - workspaceVariables: [], - workspaceConstants: [], encrypted: isEncrypted, onBlur, isRequired: isRequired, @@ -356,6 +384,10 @@ const DynamicFormV2 = ({ ? { valid: true, message: '' } : { valid: null, message: '' }, // handle optional && encrypted fields isDisabled: !canUpdateDataSource(selectedDataSource?.id) && !canDeleteDataSource(), + workspaceVariables, + workspaceConstants: currentOrgEnvironmentConstants, + isEditing: isEditing, + labelDisabled: false, }; } case 'react-component-headers': { @@ -411,11 +443,18 @@ const DynamicFormV2 = ({ if (!canUpdateDataSource(selectedDataSource?.id) && !canDeleteDataSource()) { return; } + const isEditing = computedProps[field]['disabled']; + const workspaceConstant = options?.[field]?.workspace_constant; + const isWorkspaceConstant = !!workspaceConstant; + if (isEditing) { - optionchanged(field, ''); + if (isWorkspaceConstant) { + optionchanged(field, workspaceConstant); + } else { + optionchanged(field, ''); + } } else { - //Send old field value if editing mode disabled for encrypted fields const newOptions = { ...options }; const oldFieldValue = selectedDataSource?.['options']?.[field]; if (oldFieldValue) { @@ -425,6 +464,7 @@ const DynamicFormV2 = ({ optionsChanged({ ...newOptions }); } } + setComputedProps({ ...computedProps, [field]: { @@ -511,6 +551,7 @@ const DynamicFormV2 = ({ dataCy={uiProperties[key].key.replace(/_/g, '-')} //to be removed after whole ui is same isHorizontalLayout={isHorizontalLayout} + handleEncryptedFieldsToggle={handleEncryptedFieldsToggle} />
diff --git a/frontend/src/_components/NotificationCenter/index.jsx b/frontend/src/_components/NotificationCenter/index.jsx index 4f031857f5..f1fc1cbf8f 100644 --- a/frontend/src/_components/NotificationCenter/index.jsx +++ b/frontend/src/_components/NotificationCenter/index.jsx @@ -38,7 +38,7 @@ export const NotificationCenter = ({ darkMode }) => { const overlay = (
{ + const [searchText, setSearchText] = useState(''); + const debouncedSearchTerm = useDebounce(searchText, debounceDelay); + const [isFocused, setFocussed] = useState(false); + + const handleChange = (e) => { + setSearchText(e.target.value); + callBack?.(e); + }; + + const clearSearchText = () => { + setSearchText(''); + onClearCallback?.(); + }; + + const handleClickOutside = (event) => { + if (ref?.current && !ref.current.contains(event.target) && clearTextOnBlur) { + clearSearchText(); + // Your function to be triggered + } + }; + + const mounted = useMounted(); + + useEffect(() => { + document.addEventListener('mousedown', handleClickOutside); + if (mounted) { + onSubmit?.(debouncedSearchTerm); + } + return () => { + // Cleanup event listener on component unmount + document.removeEventListener('mousedown', handleClickOutside); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [debouncedSearchTerm, onSubmit]); + + useEffect(() => { + initialValue !== undefined && setSearchText(initialValue); + }, [initialValue]); + + return ( +
+
+ {!isFocused && ( + + + + )} + setFocussed(true)} + onBlur={() => setFocussed(false)} + data-cy={`${dataCy}-search-bar`} + autoFocus={autoFocus} + ref={ref} + /> + {searchText.length >= 0 ? ( + +
+ +
+
+ ) : ( + '' + )} +
+
+ ); + } +); + +SearchBox.propTypes = { + onSubmit: PropTypes.func.isRequired, + debounceDelay: PropTypes.number, + width: PropTypes.string, +}; diff --git a/frontend/src/_components/SearchBox.jsx b/frontend/src/_components/SearchBox.jsx index f0c09054dc..58afc173de 100644 --- a/frontend/src/_components/SearchBox.jsx +++ b/frontend/src/_components/SearchBox.jsx @@ -4,6 +4,7 @@ import cx from 'classnames'; import useDebounce from '@/_hooks/useDebounce'; import { useMounted } from '@/_hooks/use-mount'; import SolidIcon from '@/_ui/Icon/SolidIcons'; +import './_styles/search-box.scss'; export const SearchBox = forwardRef( ( diff --git a/frontend/src/_components/_styles/page-search-box.scss b/frontend/src/_components/_styles/page-search-box.scss new file mode 100644 index 0000000000..f1be3e2be4 --- /dev/null +++ b/frontend/src/_components/_styles/page-search-box.scss @@ -0,0 +1,85 @@ +.ghost-search-box-wrapper { + .form-control.ghost-search { + background: none !important; + color: var(--slate12); + height: 48px; + border: none !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--border-weak) !important; + transition: border-bottom 0.2s ease-in-out; + + &:hover { + background: none !important; + border-bottom: 1px solid var(--border-accent-weak) !important; + color: var(--slate12); + } + + &:focus { + background: none !important; + border: none !important; + border-bottom: 1px solid var(--border-accent-strong) !important; + } + + } + .input-icon { + .input-icon-addon { + padding-right: 6px; + display: flex; + } + } +} + + +/** + * Search Box + */ + .ghost-search-box-wrapper { + input { + width: 200px; + border-radius: 5px !important; + color: var(--slate12); + background-color: var(--base); + } + + .input-icon .form-control:not(:first-child), + .input-icon .form-select:not(:last-child) { + padding-left: 28px !important; + } + + input:focus { + width: 200px; + background-color: var(--base); + } + + .input-icon .input-icon-addon { + display: flex; + } + + .input-icon .input-icon-addon.end { + pointer-events: auto; + + .tj-common-search-input-clear-icon { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 4px; + width: 20px; + height: 20px; + background: var(--indigo3) !important; + border-radius: 4px; + } + + div { + border-radius: 12px; + color: #ffffff; + padding: 1px; + cursor: pointer; + + svg { + height: 14px; + width: 14px; + } + } + } +} diff --git a/frontend/src/_components/_styles/search-box.scss b/frontend/src/_components/_styles/search-box.scss new file mode 100644 index 0000000000..202f98b688 --- /dev/null +++ b/frontend/src/_components/_styles/search-box.scss @@ -0,0 +1,65 @@ +.search-box-wrapper { + input { + width: 200px; + border-radius: 5px !important; + color: var(--text-primary); + background-color: var(--surfaces-surface-01) !important; + border: 1px solid var(--border-weak) !important; + } + + .input-icon .form-control:not(:first-child), + .input-icon .form-select:not(:last-child) { + padding-left: 28px !important; + } + + input:focus { + width: 200px; + background-color: var(--surfaces-surface-02); + } + + .input-icon .input-icon-addon { + display: flex; + } + + .input-icon .input-icon-addon.end { + pointer-events: auto; + + .tj-common-search-input-clear-icon { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 4px; + width: 20px; + height: 20px; + background: var(--indigo3) !important; + border-radius: 4px; + } + + div { + border-radius: 12px; + color: #ffffff; + padding: 1px; + cursor: pointer; + + svg { + height: 14px; + width: 14px; + } + } + } +} + +.searchbox-wrapper { + margin-top: 0 !important; + + .search-icon { + margin: 0.30rem + } + + input { + border-radius: 8px !important; + padding-left: 1.75rem !important; + border-radius: 8px !important; + } +} \ No newline at end of file diff --git a/frontend/src/_services/ai.service.js b/frontend/src/_services/ai.service.js index 94f273d27d..98f7f10698 100644 --- a/frontend/src/_services/ai.service.js +++ b/frontend/src/_services/ai.service.js @@ -4,7 +4,6 @@ import { fetchEventSource } from '@microsoft/fetch-event-source'; export const aiService = { generateApp, - createComponent, createQuery, updateComponent, createEvent, @@ -60,14 +59,6 @@ function generateApp(prompt) { return fetch(`${config.apiUrl}/ai/generateApp`, requestOptions).then(handleResponse); } -function createComponent(prompt) { - const body = { - prompt, - }; - const requestOptions = { method: 'POST', headers: authHeader(), credentials: 'include', body: JSON.stringify(body) }; - return fetch(`${config.apiUrl}/agents/create-components`, requestOptions).then(handleResponse); -} - function createQuery(prompt) { const body = { prompt, diff --git a/frontend/src/_services/dataquery.service.js b/frontend/src/_services/dataquery.service.js index 3dc5e26593..c69b125237 100644 --- a/frontend/src/_services/dataquery.service.js +++ b/frontend/src/_services/dataquery.service.js @@ -11,6 +11,7 @@ export const dataqueryService = { changeQueryDataSource, updateStatus, bulkUpdateQueryOptions, + createWorkflowQuery, }; function getAll(appVersionId, mode) { @@ -36,6 +37,21 @@ function create(app_id, app_version_id, name, kind, options, data_source_id, plu ).then(handleResponse); } +function createWorkflowQuery(app_id, app_version_id, name, kind, options, data_source_id, plugin_id) { + const body = { + app_id, + app_version_id, + name, + kind, + options, + data_source_id, + plugin_id, + }; + + const requestOptions = { method: 'POST', headers: authHeader(), credentials: 'include', body: JSON.stringify(body) }; + return fetch(`${config.apiUrl}/data-queries/workflow-node`, requestOptions).then(handleResponse); +} + function update(id, versionId, name, options, dataSourceId) { const body = { options, diff --git a/frontend/src/_services/workflow_executions.service.js b/frontend/src/_services/workflow_executions.service.js index 8eac985252..8abcdfe569 100644 --- a/frontend/src/_services/workflow_executions.service.js +++ b/frontend/src/_services/workflow_executions.service.js @@ -10,11 +10,15 @@ export const workflowExecutionsService = { all, enableWebhook, previewQueryNode, + getPaginatedExecutions, + getPaginatedNodes, + trigger, + streamSSE, }; -function previewQueryNode(queryId, appVersionId, nodeId) { +function previewQueryNode(queryId, appVersionId, nodeId, state = {}) { const currentSession = authenticationService.currentSessionValue; - const body = { appVersionId, userId: currentSession.current_user?.id, queryId, nodeId }; + const body = { appVersionId, userId: currentSession.current_user?.id, queryId, nodeId, state }; const requestOptions = { method: 'POST', headers: authHeader(), body: JSON.stringify(body), credentials: 'include' }; return fetch(`${config.apiUrl}/workflow_executions/previewQueryNode`, requestOptions).then(handleResponse); } @@ -70,3 +74,40 @@ function enableWebhook(appId, value) { const requestOptions = { method: 'PATCH', headers: authHeader(), body: JSON.stringify(body), credentials: 'include' }; return fetch(`${config.apiUrl}/v2/webhooks/workflows/${appId}`, requestOptions).then(handleResponse); } + +function getPaginatedExecutions(appVersionId, page = 1, perPage = 10) { + const requestOptions = { method: 'GET', headers: authHeader(), credentials: 'include' }; + return fetch( + `${config.apiUrl}/workflow_executions?appVersionId=${appVersionId}&page=${page}&per_page=${perPage}`, + requestOptions + ).then(handleResponse); +} + +function getPaginatedNodes(executionId, page = 1, perPage = 20) { + const requestOptions = { method: 'GET', headers: authHeader(), credentials: 'include' }; + return fetch( + `${config.apiUrl}/workflow_executions/${executionId}/nodes?page=${page}&per_page=${perPage}`, + requestOptions + ).then(handleResponse); +} + +function trigger(workflowAppId, params, environmentId) { + const currentSession = authenticationService.currentSessionValue; + const body = { + appId: workflowAppId, + userId: currentSession.current_user?.id, + executeUsing: 'app', + params: Array.isArray(params) + ? Object.fromEntries(params.filter((param) => param.key !== '').map((param) => [param.key, param.value])) + : params || {}, + environmentId, + }; + const requestOptions = { method: 'POST', headers: authHeader(), body: JSON.stringify(body), credentials: 'include' }; + return fetch(`${config.apiUrl}/workflow_executions/${workflowAppId}/trigger`, requestOptions).then(handleResponse); +} + +function streamSSE(workflowExecutionId) { + return new EventSource(`${config.apiUrl}/workflow_executions/${workflowExecutionId}/stream`, { + withCredentials: true, + }); +} diff --git a/frontend/src/_stores/workflowStore.js b/frontend/src/_stores/workflowStore.js new file mode 100644 index 0000000000..89ba9d0c8a --- /dev/null +++ b/frontend/src/_stores/workflowStore.js @@ -0,0 +1,8 @@ +import create from 'zustand'; + +const useWorkflowStore = create((set) => ({ + workflowId: null, + setWorkflowId: (id) => set({ workflowId: id }), +})); + +export default useWorkflowStore; diff --git a/frontend/src/_styles/componentdesign.scss b/frontend/src/_styles/componentdesign.scss index b5879cd2f9..9175677b51 100644 --- a/frontend/src/_styles/componentdesign.scss +++ b/frontend/src/_styles/componentdesign.scss @@ -109,6 +109,17 @@ //upgrade --upgrade-default: #FFAF41; --upgrade-weak: #FFAF4140; + + // Shadows + --elevation-000-box-shadow: 0px 1px 0px 0px rgba(0, 0, 0, 0.10); + --elevation-200-box-shadow: 0px 2px 4px 0px rgba(48, 50, 51, 0.10), 0px 0px 1px 0px rgba(48, 50, 51, 0.05); + --elevation-300-box-shadow: 0px 4px 8px 0px rgba(48, 50, 51, 0.10), 0px 0px 1px 0px rgba(48, 50, 51, 0.05); + --elevation-400-box-shadow: 0px 8px 16px 0px rgba(48, 50, 51, 0.10), 0px 0px 1px 0px rgba(48, 50, 51, 0.05); + --elevation-500-box-shadow: 0px 16px 24px 0px rgba(48, 50, 51, 0.09), 0px 0px 1px 0px rgba(48, 50, 51, 0.05); + --elevation-600-box-shadow: 0px 24px 40px 0px rgba(48, 50, 51, 0.08), 0px 0px 1px 0px rgba(48, 50, 51, 0.05); + --elevation-700-box-shadow: 0px 32px 50px 0px rgba(48, 50, 51, 0.08), 0px 0px 1px 0px rgba(48, 50, 51, 0.05); + --elevation-100-box-shadow: 0px 1px 1px 0px rgba(48, 50, 51, 0.10), 0px 0px 1px 0px rgba(48, 50, 51, 0.05); + } .dark-theme { @@ -222,4 +233,15 @@ //upgrade --upgrade-default: #FFAF41; --upgrade-weak: #FFAF4140; + + //box-shadow + --elevation-000-box-shadow: 0px 1px 0px 0px rgba(0, 0, 0, 0.40); + --elevation-100-box-shadow: 0px 1px 1px 0px #000, 0px 0px 1px 0px rgba(0, 0, 0, 0.90); + --elevation-200-box-shadow: 0px 2px 4px 0px #000, 0px 0px 1px 0px rgba(0, 0, 0, 0.90); + --elevation-300-box-shadow: 0px 4px 8px 0px #000, 0px 0px 1px 0px rgba(0, 0, 0, 0.90); + --elevation-400-box-shadow: 0px 8px 16px 0px #000, 0px 0px 1px 0px rgba(0, 0, 0, 0.90); + --elevation-500-box-shadow: 0px 16px 24px 0px rgba(0, 0, 0, 0.99), 0px 0px 1px 0px rgba(0, 0, 0, 0.90); + --elevation-600-box-shadow: 0px 24px 40px 0px rgba(0, 0, 0, 0.98), 0px 0px 1px 0px rgba(0, 0, 0, 0.90); + --elevation-700-box-shadow: 0px 32px 50px 0px rgba(0, 0, 0, 0.98), 0px 0px 1px 0px rgba(0, 0, 0, 0.90); + } \ No newline at end of file diff --git a/frontend/src/_styles/designtheme.scss b/frontend/src/_styles/designtheme.scss index bfdb6cee41..091fe42737 100644 --- a/frontend/src/_styles/designtheme.scss +++ b/frontend/src/_styles/designtheme.scss @@ -120,7 +120,7 @@ --interactive-overlays-column-resize: #1B1F244D; //interactive - --interactive-default: #CCD1D54D; + --interactive-default: #88909914; --interactive-hover: #ACB2B959; @@ -211,7 +211,7 @@ --interactive-overlays-column-resize: #FFFFFF80; //interactive - --interactive-default: #A1A7AE1F; + --interactive-default: #858C940D; --interactive-hover: #A1A7AE29; diff --git a/frontend/src/_styles/drawer.scss b/frontend/src/_styles/drawer.scss index 4b2f9b89d5..e9945e3572 100644 --- a/frontend/src/_styles/drawer.scss +++ b/frontend/src/_styles/drawer.scss @@ -3,15 +3,14 @@ } .drawer { - background: var(--base); + background: var(--surfaces-surface-01); width: 540px; height: 100%; position: fixed; - border: 1px solid var(--slate5); - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); + border: 1px solid var(--border-weak); + box-shadow: var(--elevation-400-box-shadow); transition: transform var(--transition-speed) ease; z-index: 1000; - background: var(--base); overflow-y: auto; &.left { diff --git a/frontend/src/_styles/dropdown-custom.scss b/frontend/src/_styles/dropdown-custom.scss index 7ca2a022c0..5c3f7136c8 100644 --- a/frontend/src/_styles/dropdown-custom.scss +++ b/frontend/src/_styles/dropdown-custom.scss @@ -1,80 +1,94 @@ // for selects and dropdowns across app dashboard .react-select__control { - background-color: var(--base) !important; - border: 1px solid var(--slate7) !important; + background-color: var(--surfaces-surface-01) !important; + border: 1px solid var(--border-weak) !important; - &:active { - border: 1px solid var(--indigo9); - } + &:active { + border: 1px solid var(--indigo9); + } } .react-select__menu-portal { - z-index: 100 !important; + z-index: 100 !important; - .react-select__option { - color: var(--slate12); - z-index: 100; - - } + .react-select__option { + color: var(--text-default); + height: 32px; + z-index: 100; + padding: 4px 8px; + } } .react-select__single-value { - color: var(--slate12) ; + color: var(--text-default); } .react-select__menu { - background-color: var(--base) !important; - border: 1px solid var(--slate3) !important; - box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03) !important; - margin: 0px !important; - z-index: 100; + background-color: var(--surfaces-surface-01) !important; + border: 1px solid var(--border-weak) !important; + box-shadow: var(--elevation-00-box-shadow) !important; + margin: 0px !important; + z-index: 100; - .react-select__menu-list { - background-color: var(--base) !important; - overflow-y: auto; + .react-select__menu-list { + background-color: var(--surfaces-surface-01) !important; + padding: 4px; + overflow-y: auto; - .react-select__option { - background-color: var(--base) !important; + .react-select__option { + background-color: var(--surfaces-surface-01) !important; + border-radius: 6px; - &:hover { - background-color: var(--slate3) !important; - } + + > div { + color: var(--text-default) !important; + background-color: transparent !important; + } + + &:hover { + background-color: var(--interactive-hover) !important; + > div { + background-color: transparent !important; } + } } + } } .org-select-container { - height: 52px; - display: flex; - align-items: center; - justify-content: center; - border-top: 1px solid var(--slate5); - margin-bottom: var(--dynamic-margin, 0px); //please Remove after Basicplan banner is removed.. + height: 52px; + display: flex; + align-items: center; + justify-content: center; + border-top: 1px solid var(--border-weak); + margin-bottom: var( + --dynamic-margin, + 0px + ); //please Remove after Basicplan banner is removed.. } .tj-org-select { - .react-select__control { - width: 262px; - height: 32px; - border: none !important; - background-color: var(--page-default) !important; + .react-select__control { + width: 262px; + height: 32px; + border: none !important; + background-color: var(--surfaces-surface-01) !important; - &:hover { - background: var(--slate2) !important; - } - - &:active { - background: var(--slate3) !important; - } + &:hover { + background: var(--slate2) !important; } - .tj-text-xsm { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - width: 200px; + &:active { + background: var(--slate3) !important; } + } + .tj-text-xsm { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + width: 200px; + } } .users-filter-dropdown, @@ -85,59 +99,58 @@ .select-order-field, .select-column-field, .records-dropdown-field { - .react-select__control { - border: 1px solid var(--slate7) !important; - } + .react-select__control { + border: 1px solid var(--border-default) !important; + } } .css-1ms6gku-MenuPortal, .css-169zxdi-MenuList { - .react-select__option { - border-radius: 6px; - } + .react-select__option { + border-radius: 6px; + } } .css-nw08ma-menu { - box-shadow: none !important; + box-shadow: none !important; } .react-select__menu-portal { - z-index: 9999 !important; + z-index: 9999 !important; } // following is the styles for table select column type menu list and options styles. If its same for all the select elements in the editor, then we can make it common and not specific for table select -.table-select-custom-menu-list{ - .react-select__menu-list{ - padding: 2px; - // this is needed otherwise :active state doesn't look nice, gap is required - display: flex; - flex-direction: column; - gap: 4px !important; - background-color: var(--base) !important; - overflow-y: auto; +.table-select-custom-menu-list { + .react-select__menu-list { + padding: 2px; + // this is needed otherwise :active state doesn't look nice, gap is required + display: flex; + flex-direction: column; + gap: 4px !important; + background-color: var(--surfaces-surface-01) !important; + overflow-y: auto; + } + .react-select__option { + display: flex; + justify-content: space-between; + padding: 8px 12px; + align-self: stretch; + align-items: center; + color: var(--slate12) !important; + border-radius: 6px; + /* Paragraph/Extrasmall/Regular */ + font-family: "IBM Plex Sans"; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 166.667% */ + &.react-select__option--is-selected { + color: var(--indigo9) !important; } - .react-select__option{ - display: flex; - justify-content: space-between; - padding: 8px 12px; - align-self: stretch; - align-items: center; - color: var(--slate12) !important; - border-radius: 6px; - /* Paragraph/Extrasmall/Regular */ - font-family: 'IBM Plex Sans'; - font-size: 12px; - font-style: normal; - font-weight: 400; - line-height: 20px; /* 166.667% */ - &.react-select__option--is-selected{ - color: var(--indigo9) !important; - } - &:active{ - background: var(--base) !important; - box-shadow: 0px 0px 0px 4px var(--slate6); - color : var(--slate12) !important; - } + &:active { + background: var(--surfaces-surface-01) !important; + box-shadow: 0px 0px 0px 4px var(--slate6); + color: var(--slate12) !important; } + } } - diff --git a/frontend/src/_styles/editor/react-select-search.scss b/frontend/src/_styles/editor/react-select-search.scss index 707c59e8a4..3660056f68 100644 --- a/frontend/src/_styles/editor/react-select-search.scss +++ b/frontend/src/_styles/editor/react-select-search.scss @@ -20,10 +20,10 @@ } .select-search-container { - --select-search-background: var(--base); - --select-search-border: var(--slate7); + --select-search-background: var(--surfaces-surface-01); + --select-search-border: var(--border-weak); --select-search-selected: #dadcde; - --select-search-text: var(--slate12); + --select-search-text: var(--text-default); --select-search-subtle-text: #6c6f85; --select-search-inverted-text: var(--select-search-background); --select-search-highlight: var(--indigo3); diff --git a/frontend/src/_styles/global-datasources.scss b/frontend/src/_styles/global-datasources.scss index d365b1ac0c..97d9108c44 100644 --- a/frontend/src/_styles/global-datasources.scss +++ b/frontend/src/_styles/global-datasources.scss @@ -2,12 +2,13 @@ @import "./designtheme.scss"; .global-datasources-sidebar { - height: calc(100vh - 64px); + height: calc(100vh - 48px); max-width: 288px; - background: var(--page-default); + background: var(--page-weak); display: grid; grid-template-rows: auto 1fr auto; - border-right: 1px solid var(--slate5); + border-right: 1px solid var(--border-weak); + gap: 30px; .add-datasource-btn { height: 40px; @@ -28,7 +29,7 @@ padding: 6px 15px; width: 248px; height: 32px; - margin-bottom: 10px; + margin-bottom: 8px; &:focus-visible { box-shadow: 0px 0px 0px 4px #dfe3e6; @@ -69,7 +70,8 @@ } .datasources-list-item { - background-color: var(--indigo3); + background-color: var(--interactive-default); + color: var(--text-default); } } @@ -109,7 +111,7 @@ .datasource-modal-container { position: relative; - background: var(--page-default); + background: var(--page-weak); .modal-header { background-color: var(--slate3) !important; @@ -118,12 +120,12 @@ .modal { position: absolute; z-index: 1050; - background: var(--slate2); + background: var(--page-weak); } .modal-content { - border: 1px solid var(--slate5); - background-color: var(--base) !important; + border: 1px solid var(--border-weak); + background-color: var(--page-weak) !important; .input-icon { &:hover { @@ -165,6 +167,12 @@ display: flex; justify-content: center; align-items: center; + + svg { + top: 1px; + left: 1px; + position: relative; + } } } @@ -184,26 +192,24 @@ .datasource-list-container { overflow-y: auto; padding-left: 20px; - max-height: calc(100vh - 64px); - border-left: 1px solid var(--slate5); + max-height: calc(100vh - 48px); + + .datasource-list { width: 976px; margin: 0 auto; - max-height: calc(100vh - 70px); + padding-bottom: 48px; .datasource-search-holder { width: 100%; - margin-top: 22px; + margin-top: 24px; + margin-bottom: 24px; + } - .liner { - margin-top: 5px; - width: 100% !important; - } - - input { - background: none !important; - border: none !important; - } + .ghost-search-box-wrapper .form-control.ghost-search { + padding-top: 16px; + padding-bottom: 16px; + height: 64px; } } diff --git a/frontend/src/_styles/instancelogout.scss b/frontend/src/_styles/instancelogout.scss index 5205472426..2e83aa64de 100644 --- a/frontend/src/_styles/instancelogout.scss +++ b/frontend/src/_styles/instancelogout.scss @@ -1,16 +1,14 @@ .instance-logout-wrapper{ - background: var(--base); + background: var(--page-weak); .instance-logout-header{ padding: 24px 24px; gap: 12px; height: 72px; border-top-left-radius: 6px; border-top-right-radius: 6px; - border-bottom: 1px solid rgb(230, 232, 235); /* Light gray border */ + border-bottom: 1px solid var(--border-weak); padding-bottom: 1rem; - &.dark-mode { - border-bottom: 1px solid rgb(43, 47, 49) !important; - } + .instance-logout-title{ font-size: 18px; line-height: 28px; diff --git a/frontend/src/_styles/left-sidebar.scss b/frontend/src/_styles/left-sidebar.scss index 2f5dde474b..3149e86a48 100644 --- a/frontend/src/_styles/left-sidebar.scss +++ b/frontend/src/_styles/left-sidebar.scss @@ -1,7 +1,7 @@ @import "./colors.scss"; @import "./designtheme.scss"; .left-sidebar { - background: var(--page-default) !important; + background: var(--page-weak) !important; display: flex; gap: 16px; @@ -785,7 +785,7 @@ align-items: center; padding-top: 0px; width: 48px; - border-right: 1px solid var(--slate5); + border-right: 1px solid var(--border-weak); } .tj-leftsidebar-icon-wrap { diff --git a/frontend/src/_styles/license.scss b/frontend/src/_styles/license.scss index e058dab5e7..62e4011730 100644 --- a/frontend/src/_styles/license.scss +++ b/frontend/src/_styles/license.scss @@ -6,16 +6,17 @@ width: 880px; margin: auto; border-radius: 6px; + border: 1px solid var(--border-weak); .body-wrapper { - border: 1px solid var(--slate5); + height: 100%; min-height: 620px; } .license-page-sidebar { max-width: 220px; - background-color: var(--base); - border-right: 1px solid var(--slate5) !important; + background-color: var(--surfaces-surface-01); + border-right: 1px solid var(--border-weak) !important; display: grid !important; grid-template-rows: auto 1fr auto !important; @@ -29,7 +30,7 @@ } .license-content-wrapper { - background-color: var(--base); + background-color: var(--surfaces-surface-01); .groups-sub-header-wrap { width: 100%; @@ -253,11 +254,10 @@ .license-header-wrap { display: flex; justify-content: space-between; - padding-right: 40px; - padding-left: 20px; + padding: 24px 40px 16px; align-items: center; height: unset !important; - background-color: var(--base); + background-color: var(--surfaces-surface-01); .status-container { border-radius: 20px; @@ -599,9 +599,9 @@ align-items: center; align-self: stretch; border-radius: 8px; - background-color: #FFFFFF; - border: 1px solid var(--upgrade-weak, #FFAF4140); - box-shadow: 0px 0px 1px 0px var(--dropshadow-100700-layer-1, rgba(48, 50, 51, 0.05)), 0px 1px 1px 0px var(--dropshadow-100400-layer-2, rgba(48, 50, 51, 0.10)); + background-color: var(--surfaces-surface-01); + border: 1px solid var(--border-weak, #FFAF4140); + box-shadow: var(--elevation-000-box-shadow); .license-loader { justify-content: center; @@ -796,7 +796,7 @@ } .license-error-modal { - background-color: var(--base); + background-color: var(--surfaces-surface-01); .modal-header { background-color: var(--slate3) !important; @@ -859,7 +859,7 @@ width: 100%; height: 88px; border-top: 1px solid var(--slate5) !important; - background: var(--base); + background: var(--surfaces-surface-01); margin-top: 0px !important; } diff --git a/frontend/src/_styles/modules.scss b/frontend/src/_styles/modules.scss index 239cc3201c..b86e7043dd 100644 --- a/frontend/src/_styles/modules.scss +++ b/frontend/src/_styles/modules.scss @@ -1,6 +1,7 @@ -.apps-modules-tabs { - .nav-link { - background-color: var(--page-default); +.apps-modules-tabs.nav-tabs { + .nav-link, + ul > li.nav-link.active { + background-color: var(--page-weak); } .nav-link.active { diff --git a/frontend/src/_styles/rocket/card.scss b/frontend/src/_styles/rocket/card.scss new file mode 100644 index 0000000000..6dc527eb5d --- /dev/null +++ b/frontend/src/_styles/rocket/card.scss @@ -0,0 +1,13 @@ +// Card +.card { + border: 0 !important; + outline: 1px solid var(--border-weak); + box-shadow: var(--elevation-100-box-shadow); + border-radius: 8px; + background-color: var(--background-surface-layer-01) !important; + + + &.card--clickable:hover { + box-shadow: var(--elevation-200-box-shadow); + } +} \ No newline at end of file diff --git a/frontend/src/_styles/tabler.scss b/frontend/src/_styles/tabler.scss index ad724a1833..f21427d807 100644 --- a/frontend/src/_styles/tabler.scss +++ b/frontend/src/_styles/tabler.scss @@ -18972,7 +18972,7 @@ img { @media not print { .theme-dark { color: #f4f6fa; - background-color: #1f2936 + background-color: #1E2226; } .theme-dark .card, diff --git a/frontend/src/_styles/theme.scss b/frontend/src/_styles/theme.scss index d3b556bba8..3f614e476c 100644 --- a/frontend/src/_styles/theme.scss +++ b/frontend/src/_styles/theme.scss @@ -20,6 +20,8 @@ @import "./componentdesign.scss"; @import './pages-sidebar.scss'; @import './modules.scss'; +@import "./rocket/card.scss"; +@import "../HomePage/styles/homepage.scss"; /* ibm-plex-sans-100 - latin */ @font-face { @@ -214,6 +216,7 @@ &::-webkit-scrollbar-thumb { background: transparent; } + &::-webkit-scrollbar-track { background: transparent; } @@ -225,6 +228,7 @@ &::-webkit-scrollbar-thumb { background: var(--slate8); } + &::-webkit-scrollbar-track { background: transparent; } @@ -943,70 +947,6 @@ button { } } -.home-search-holder { - height: 20px; - width: 100%; - margin-top: 32px; - - .search-box-wrapper { - .input-icon { - .input-icon-addon { - padding-right: 6px; - } - } - } - - .homepage-search { - background: none !important; - color: var(--slate12); - height: 20px; - border: none !important; - - &:focus { - background: none !important; - border: none !important; - } - - &:hover { - background: none !important; - border: none !important; - color: var(--slate12); - } - } -} - -.homepage-app-card-list-item-wrap { - row-gap: 16px; - column-gap: 32px; - display: flex; - margin-top: 22px; -} - -.homepage-app-card-list-item { - max-width: 272px; - flex-basis: 33%; - padding: 0 !important; -} - -.homepage-dropdown-style { - min-width: 11rem; - display: block; - align-items: center; - margin: 0; - line-height: 1.4285714; - width: 100%; - padding: 0.5rem 0.75rem !important; - font-weight: 400; - white-space: nowrap; - border: 0; - cursor: pointer; - font-size: 12px; -} - -.homepage-dropdown-style:hover { - background: rgba(101, 109, 119, 0.06); -} - .card-skeleton-container { border: 0.5px solid #b4bbc6; padding: 1rem; @@ -1250,7 +1190,7 @@ button { font-weight: 500; .modal-header { - background-color: var(--base) !important; + background-color: var(--surfaces-surface-01) !important; border-bottom: 1px solid var(--slate5); } @@ -1267,7 +1207,7 @@ button { .modal-body { height: 80%; padding: 0 10px; - background-color: var(--base) !important; + background-color: var(--surfaces-surface-01) !important; .container-fluid { @@ -1401,7 +1341,7 @@ button { .modal-body { height: 80%; padding: 0 10px; - background-color: var(--base) !important; + background-color: var(--surfaces-surface-01) !important; .container-fluid { height: 100%; @@ -1417,7 +1357,7 @@ button { .modal-header, .modal-content { color: white; - background-color: #2b394a; + background-color: var(--surfaces-surface-01); } .template-categories { @@ -2316,10 +2256,10 @@ tr:focus { #popover-app-menu { border-radius: 4px; width: 150px; - box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03); - background: var(--base); - color: var(--slate12); - border: 1px solid var(--slate3); + box-shadow: var(--elevation-200-box-shadow); + background: var(--surfaces-surface-01); + color: var(--text-default); + border: 1px solid var(--border-default); .popover-arrow { display: none; @@ -3422,7 +3362,7 @@ input:focus-visible { .modal-content, .modal-header { - background-color: #1f2936; + background-color: var(--surfaces-surface-01); .text-muted { color: var(--slate9) !important; @@ -3756,7 +3696,7 @@ input:focus-visible { position: relative; min-height: 100%; min-width: 100%; - background-color: #2b394b; + background-color: var(--page-weak); } .jet-table { @@ -3794,6 +3734,7 @@ input:focus-visible { .nav-tabs { font-weight: 300; + border-bottom: 1px solid var(--border-weak); } .nav-tabs .nav-link.active { @@ -3814,7 +3755,9 @@ input:focus-visible { } input[type="text"] { - outline-color: #dadcde !important; + outline-color: var(--border-default) !important; + border-color: var(--border-default) !important; + } .widget-header { @@ -4752,74 +4695,6 @@ input[type="text"] { } } -/** - * Search Box - */ -.search-box-wrapper { - input { - width: 200px; - border-radius: 5px !important; - color: var(--slate12); - background-color: var(--base); - } - - .input-icon .form-control:not(:first-child), - .input-icon .form-select:not(:last-child) { - padding-left: 28px !important; - } - - input:focus { - width: 200px; - background-color: var(--base); - } - - .input-icon .input-icon-addon { - display: flex; - } - - .input-icon .input-icon-addon.end { - pointer-events: auto; - - .tj-common-search-input-clear-icon { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - padding: 4px; - width: 20px; - height: 20px; - background: var(--indigo3) !important; - border-radius: 4px; - } - - div { - border-radius: 12px; - color: #ffffff; - padding: 1px; - cursor: pointer; - - svg { - height: 14px; - width: 14px; - } - } - } -} - -.searchbox-wrapper { - margin-top: 0 !important; - - .search-icon { - margin: 0.30rem - } - - input { - border-radius: $border-radius !important; - padding-left: 1.75rem !important; - border-radius: $border-radius !important; - } -} - .fixedHeader { table thead { position: -webkit-sticky; // this is for all Safari (Desktop & iOS), not for Chrome @@ -4834,7 +4709,7 @@ input[type="text"] { * Folder List */ .folder-list { - overflow-y: scroll; + overflow-y: auto; scrollbar-width: thin; scrollbar-color: #888 transparent; @@ -4932,7 +4807,7 @@ input[type="text"] { .modal-content.home-modal-component { border-radius: 8px; overflow: hidden; - background-color: var(--base); + background-color: var(--surfaces-surface-01); color: var(--slate12); box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03); @@ -4943,7 +4818,7 @@ input[type="text"] { .modal-header, .modal-body { padding: 16px 28px; - background: var(--base); + background: var(--surfaces-surface-01); } .modal-title { @@ -4953,7 +4828,7 @@ input[type="text"] { input:not([type=checkbox]) { border-radius: 5px !important; - background: var(--base); + background: var(--surfaces-surface-01); color: var(--slate12); } @@ -4973,13 +4848,13 @@ input[type="text"] { .modal-header, .modal-body { - background-color: #232e3c; + background-color: var(--surfaces-surface-01); color: #fff; } .form-control { color: #fff; - background-color: #232e3c !important; + background-color: var(--surfaces-surface-01) !important; } .btn-close { @@ -5024,7 +4899,7 @@ input[type="text"] { } .modal-header { - background-color: $bg-dark-light !important; + background-color: var(--surfaces-surface-01) !important; color: $white !important; border-bottom: 2px solid #3A3F42 !important; } @@ -5039,7 +4914,7 @@ input[type="text"] { } input { - background-color: $bg-dark-light !important; + background-color: var(--surfaces-surface-01) !important; } .form-select { @@ -5700,7 +5575,7 @@ div#driver-page-overlay { } .sso-card-wrapper { - background: var(--base); + background: var(--surfaces-surface-01); min-height: 100%; // height: calc(100vh - 156px) !important; @@ -5732,18 +5607,18 @@ div#driver-page-overlay { background: var(--base); margin-top: 0px !important; } +} +.form-footer.sso-card-footer { + border-top: 0 !important; } .workspace-settings-page { width: 880px; margin: 0 auto; - background: var(--base); + background: var(--surfaces-surface-01); .card { - background: var(--base); - border: 1px solid var(--slate7) !important; - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05) !important; width: 880px; .card-header { @@ -5775,13 +5650,18 @@ div#driver-page-overlay { align-items: center; padding: 24px 32px; gap: 8px; - border-top: 1px solid var(--slate5) !important; - background: var(--base); + border-top: 1px solid var(--border-weak) !important; + background: var(--surfaces-surface-01); margin-top: 0px !important; align-Self: 'stretch'; height: 88px; } + .card-footer { + border-top: 1px solid var(--border-weak) !important; + background: var(--surfaces-surface-01); + } + .card-body { height: 467px; padding: 24px; @@ -6309,7 +6189,7 @@ div#driver-page-overlay { .org-constant-page { .card-footer { - background: var(--base); + background: var(--page-weak); color: var(--slate12); } } @@ -6682,13 +6562,13 @@ a.step-item-disabled { .card { min-width: 400px; - background: var(--base); - color: var(--slate12); - box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03); + background: var(--surfaces-surface-01); + color: var(--text-default); + box-shadow: var(--elevation-400-box-shadow); } .card-footer { - background: var(--base); + background: var(--surfaces-surface-01); color: var(--slate12); } @@ -7671,11 +7551,11 @@ tbody { height: 36px; &:not(.table-row-selected):hover { - background: var(--Slate-02, #F8F9FA); + background: var(--slate2); td:nth-child(1), td:nth-child(2) { - background: var(--Slate-02, #F8F9FA); + background: var(--slate2); } .tjdb-checkbox-cell { @@ -7959,16 +7839,6 @@ tbody { color: var(--tblr-breadcrumb-item-active-color); } -.app-icon-main { - background: var(--indigo3) !important; - border-radius: 6px !important; - display: flex; - justify-content: center; - align-items: center; - width: 48px; - height: 48px; -} - .settings-nav-item, .audit-log-nav-item, .notification-center-nav-item { @@ -7994,15 +7864,8 @@ tbody { padding-left: 20px; } -.workspace-content-wrapper, -.database-page-content-wrap { - background-color: var(--page-default); - height: calc(100vh - 64px) !important; -} - -.instance-settings-wrapper {} - -.database-page-content-wrap { +.workspace-content-wrapper { + background-color: var(--page-weak); height: calc(100vh - 64px) !important; } @@ -8020,12 +7883,12 @@ tbody { } .organization-page-sidebar { - height: calc(100vh - 64px); + height: calc(100vh - 48px); max-width: 288px; - background-color: var(--page-default); - border-right: 1px solid var(--slate5) !important; - display: grid !important; - grid-template-rows: auto 1fr auto !important; + background-color: var(--page-weak); + border-right: 1px solid var(--border-weak) !important; + display: flex !important; + flex-direction: column !important; position: relative; .trial-banner { @@ -8041,10 +7904,10 @@ tbody { } .marketplace-page-sidebar { - height: calc(100vh - 64px); + height: calc(100vh - 48px); max-width: 272px; - background-color: var(--page-default); - border-right: 1px solid var(--slate5) !important; + background-color: var(--page-weak); + border-right: 1px solid var(--border-weak) !important; display: grid !important; grid-template-rows: auto 1fr auto !important; position: fixed; @@ -8052,8 +7915,8 @@ tbody { .home-page-sidebar { max-width: 288px; - background-color: var(--page-default); - border-right: 1px solid var(--slate5); + background-color: var(--page-weak); + border-right: 1px solid var(--border-weak); display: grid; grid-template-rows: auto 1fr auto; @@ -8066,38 +7929,6 @@ tbody { margin-top: 14px; } -.create-new-table-btn { - width: 248px; - - button { - height: 40px !important; - - } -} - -.tooljet-database-sidebar { - max-width: 288px; - background: var(--page-default); - border-right: 1px solid var(--slate5); - height: calc(100vh - 64px) !important; - - - .sidebar-container { - height: 40px !important; - padding-top: 4px !important; - margin: 0 auto; - display: flex; - justify-content: center; - } - - .sidebar-container-with-banner { - height: 40px !important; - padding-top: 1px !important; - margin: 0 auto; - display: flex; - justify-content: center; - } -} .create-new-app-dropdown { width: 248px !important; @@ -8492,11 +8323,11 @@ tbody { right: 0; left: 48px; z-index: 1; - background: var(--base); - height: 64px; + background: var(--page-weak); + height: 48px; @media only screen and (max-width: 767px) { - border-bottom: 1px solid var(--slate5); + border-bottom: 1px solid var(--border-weak); .row { display: flex; @@ -8765,24 +8596,33 @@ tbody { .tj-dashboard-section-header { - background-color: var(--page-default); + background-color: var(--page-weak); max-width: 288px; + height: 48px; max-height: 64px; - padding-top: 20px; + padding-top: 8px; padding-left: 20px; - padding-bottom: 24px; - border-right: 1px solid var(--slate5); + padding-bottom: 8px; + border-right: 1px solid var(--border-weak); + display: flex; + align-items: center; + // justify-content: center; &[data-name="Audit logs"], &[data-name="Workspace constants"], &[data-name="Profile settings"] { border-right: none; - border-bottom: 1px solid var(--slate5); + border-bottom: 1px solid var(--border-weak); .paid-feature-banner { margin-left: 15px; } } + + &[data-name="Audit logs"] { + flex: 1 0 0%; + max-width: unset; + } } .layout-sidebar-icon { @@ -8902,28 +8742,6 @@ tbody { bottom: 0px; } -.home-page-footer { - height: 52px; - background-color: var(--page-default) !important; - border-top: 1px solid var(--slate5) !important; - width: calc(100% - 336px) !important; - - @media only screen and (max-width: 768px) { - position: unset; - width: 100%; - - .col-4, - .col-5 { - display: none; - } - - .pagination-container { - display: flex !important; - align-items: center; - justify-content: center; - } - } -} .pagination-container { display: flex; @@ -9095,17 +8913,9 @@ tbody { padding-top: 4px; } -.home-page-sidebar { - height: calc(100vh - 64px) !important; //64 is navbar height - - .folder-list-user { - height: calc(100vh - 116px) !important; //64 is navbar height + 52 px footer - } -} - .home-page-content { - background-color: var(--page-default); - height: calc(100vh - 64px) !important; + background-color: var(--page-weak); + height: calc(100vh - 48px) !important; overflow-y: auto; position: relative; @@ -9155,100 +8965,6 @@ tbody { // DASHBOARD STYLES END -// TABLE -.table-left-sidebar { - height: calc(100vh - 104px) !important; // 62px [navbar] + 40px [ add table and search ] + extra 2 px(border) - overflow-y: auto; -} - -.toojet-db-table-footer { - height: 52px; - background: var(--page-default) !important; - width: calc(100vw - 336px); -} - -.toojet-db-table-footer-collapse { - height: 52px; - background: var(--page-default) !important; - width: calc(100vw - 48px); -} - -.toojet-db-table-footer-collapse { - height: 52px; - background: var(--page-default) !important; - width: calc(100vw - 48px); -} - -.home-app-card-header { - margin-bottom: 32px; -} - -.homepage-app-card { - height: 166px; - outline: 1px solid var(--slate3); - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); - border-radius: 6px; - padding: 16px; - background-color: var(--base) !important; - - .appcard-buttons-wrap { - display: none; - } - - .home-app-card-header { - .menu-ico { - visibility: hidden !important; - } - } - - &:hover { - box-shadow: 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03); - - .home-app-card-header { - margin-bottom: 12px; - - .menu-ico { - visibility: visible !important; - } - } - - .app-creation-time-container { - margin-bottom: 0px; - } - - .app-card-name { - margin-bottom: 0px; - } - - .app-creation-time { - display: none; - } - - - .appcard-buttons-wrap { - display: flex; - padding: 0px; - gap: 12px; - width: 240px; - height: 28px; - flex-direction: row; - - div { - a { - text-decoration: none; - } - } - - } - - .app-icon-main { - width: 36px; - height: 36px; - - } - } -} - .app-creation-time-container { height: 16px; } @@ -9739,7 +9455,7 @@ tbody { color: var(--slate11); .with-border { - border-bottom: 1px solid var(--slate5) !important; + border-bottom: 1px solid var(--border-weak) !important; } a { @@ -9789,19 +9505,6 @@ tbody { color: var(—-slate12) !important; } -.tj-dashboard-header-wrap { - background-color: var(--page-default); - padding-top: 22px; - padding-bottom: 22px; - padding-left: 40px; - height: 64px; - border-bottom: 1px solid var(--slate5); - - @media only screen and (max-width: 768px) { - border-bottom: none; - } -} - .dashboard-breadcrumb-header-name:hover { text-decoration: none !important; } @@ -9858,7 +9561,6 @@ tbody { .users-table { background: var(--base); padding: 16px; - width: 848px; margin: 0 auto; padding: 16px; @@ -9880,7 +9582,7 @@ tbody { } &[data-name="name-header"] { - max-width: 220px !important; + max-width: 210px !important; } &[data-name="meta-header"] { @@ -9904,16 +9606,15 @@ tbody { thead { tr { - padding: 6px 0px 0px 6px; + padding: 6px 24px 0px 24px; gap: 8px; - width: 848px; height: 40px; display: flex; align-items: center; } tr>th { - background: var(--base) !important; + background: var(--page-weak) !important; border-bottom: none !important; padding: 0 !important; width: 230px; @@ -9937,10 +9638,10 @@ tbody { } tr { - background: var(--base); + background: var(--page-weak); height: 66px; - padding: 13px 6px; - border-bottom: 1px solid var(--slate7); + padding: 13px 24px; + border-bottom: 1px solid var(--border-weak); display: flex; justify-content: space-between; gap: 8px; @@ -10011,10 +9712,6 @@ tbody { max-width: 880px; margin: 0 auto; - .tj-user-table-wrapper { - padding-right: 4px; - } - &:hover { .tj-user-table-wrapper { padding-right: 0px; @@ -10043,7 +9740,7 @@ tbody { border: 1px solid var(--slate5); border-radius: 6px; margin: 10px auto; - background-color: #FFFFFF; + background-color: var(--page-weak); display: flex; flex-direction: column; @@ -10078,7 +9775,7 @@ tbody { .worskspace-sub-header-wrap-nav-ws { width: 100%; height: 64px; - border-bottom: 1px solid var(--slate5); + border-bottom: 1px solid var(--surfaces-surface-01); display: flex; .nav-link.active { @@ -10175,30 +9872,29 @@ tbody { } .manage-workspace-table-wrap.dark-mode { - border: 1px solid var(--slate7) !important; + border: 1px solid var(--border-weak) !important; border-radius: 6px !important; - ; .worskspace-sub-header-wrap-nav-ws { - background-color: var(--slate3) !important; - border-bottom: 1px solid var(--slate7) !important; + background-color: var(--surfaces-surface-01) !important; + border-bottom: 1px solid var(--border-weak) !important; } .tab-content-ws { - background-color: var(--base) !important; + background-color: var(--surfaces-surface-01) !important; } .pagination-container-box { - background-color: var(--base) !important; + background-color: var(--surfaces-surface-01) !important; } .workspace-table-row { - border-bottom: 1px solid var(--slate7); + border-bottom: 1px solid var(--border-weak); } .worspace-list-table-body-header { - border-bottom: 1px solid var(--slate7); + border-bottom: 1px solid var(--border-weak); } } @@ -10213,8 +9909,7 @@ tbody { .workspace-setting-table-wrapper { box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); - outline: 1px solid var(--slate7); - background: var(--base); + outline: 1px solid var(--border-weak); width: 880px; margin: 0 auto; border-radius: 6px; @@ -10260,11 +9955,11 @@ tbody { column-gap: 8px; .limit { - width: 100px !important; + width: 140px !important; display: flex; flex-direction: column; align-items: center; - padding: 5px !important; + padding: 5px 10px 10px !important; background-color: var(--base); border-radius: 5px; border: 1px solid var(--slate5); @@ -10279,6 +9974,7 @@ tbody { div { width: unset !important; font-size: 11px; + margin-bottom: 2px !important; } } } @@ -10486,146 +10182,8 @@ tbody { } } -.tj-db-operations-header { - height: 48px; - padding: 0 !important; - display: flex; - align-items: center; - background-color: var(--base); - - .row { - margin-left: 0px; - width: 98%; - } - - .col-8 { - padding-left: 0px; - display: flex; - gap: 12px; - align-items: center; - } -} - -.add-new-column-btn { - margin-left: 16px; - height: 28px; - border-radius: 6px; - padding: 0 !important; - display: flex; - align-items: center; - justify-content: center; - background: transparent; - color: var(--slate12); - border: none; -} - -.tj-db-filter-btn { - width: 100%; - height: 28px; - display: flex; - border-radius: 6px; - background: transparent; - color: var(--slate12); - border: none; - display: flex; - align-items: center; - justify-content: center; -} - -.tj-db-filter-btn-applied, -.tj-db-sort-btn-applied { - display: flex !important; - flex-direction: row !important; - justify-content: center !important; - align-items: center !important; - width: 100% !important; - height: 28px !important; - background: var(--grass2) !important; - border-radius: 6px !important; -} - -.tj-db-filter-btn-applied, -.tj-db-filter-clear-icon { - background-color: var(--indigo4) !important; - color: var(--indigo9) !important; - - &:hover { - background-color: var(--button-secondary-pressed) !important; - } -} - -.tj-db-filter-clear-icon { - border-radius: 0px 6px 6px 0px; -} - -.tj-db-filter-btn-active, -.tj-db-sort-btn-active { - display: flex !important; - flex-direction: row !important; - justify-content: center !important; - align-items: center !important; - width: 100% !important; - height: 28px !important; - border-radius: 6px !important; - background: var(--indigo4) !important; - color: var(--indigo9) !important; -} - -.tj-db-filter-btn-active { - background: var(--button-outline-pressed) !important; - color: var(--text-default) !important; -} - -.tj-db-filter-btn-active-filter { - display: flex !important; - flex-direction: row !important; - justify-content: center !important; - align-items: center !important; - width: 100% !important; - height: 28px !important; - border-radius: 6px !important; - background: var(--button-secondary-pressed) !important; - color: var(--text-brand) !important; -} - -.tj-db-header-add-new-row-btn { - height: 28px; - background: transparent; - border-radius: 6px !important; - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - gap: 6px; - border: none; - - padding: span {} -} - -.tj-db-sort-btn { - width: 100%; - height: 28px; - background: transparent; - color: var(--slate12); - border: none; - display: flex; - align-items: center; - justify-content: center; - margin: 0 -} - -.edit-row-btn { - background: transparent; - color: var(--slate12); - border: none; - display: flex; - align-items: center; - justify-content: center; -} - .workspace-variable-header { width: 880px; - ; margin: 0 auto; display: flex; padding: 0; @@ -10789,10 +10347,9 @@ tbody { .org-settings-wrapper-card { display: flex; flex-direction: row; - background: var(--base); + background: var(--surfaces-surface-01); width: 880px; - outline: 1px solid var(--slate5); - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); + outline: 1px solid var(--border-weak); border-radius: 6px; max-height: calc(100vh - 156px); } @@ -10809,7 +10366,7 @@ tbody { padding: 0px 24px; width: 660px; height: 72px; - border-bottom: 1px solid var(--slate5); + border-bottom: 1px solid var(--border-weak); } @@ -10828,7 +10385,7 @@ tbody { gap: 40px; width: 188px; height: 32px; - background: var(--base); + background: var(--surfaces-surface-01); border-radius: 6px; cursor: pointer; } @@ -11916,15 +11473,12 @@ tbody { } .workspace-settings-filter-wrap { - background: var(--slate3); + background: var(--page-weak); padding: 15px 16px; gap: 12px; width: 880px; height: 62px; - border-right: 1px solid var(--slate7); - border-top: 1px solid var(--slate7); - border-left: 1px solid var(--slate7); - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); + border: 1px solid var(--border-weak); border-top-left-radius: 6px; border-top-right-radius: 6px; } @@ -11951,7 +11505,7 @@ tbody { } .new-app-dropdown { - background: var(--base) !important; + background: var(--surfaces-surface-01) !important; color: var(--slate12); } @@ -11962,11 +11516,11 @@ tbody { .card, thead { - background: var(--base) !important; + background: var(--page-weak) !important; tr>th, tbody>tr>td { - background: var(--base) !important; + background: var(--page-weak) !important; } } @@ -11993,8 +11547,8 @@ tbody { align-items: center; padding: 7px 8px; gap: 10px; - width: 34px; - height: 34px; + width: 24px; + height: 24px; background: var(--slate4) !important; color: var(--slate9); border-radius: 6px; @@ -12008,8 +11562,8 @@ tbody { align-items: center; padding: 7px 8px; gap: 10px; - width: 34px; - height: 34px; + width: 24px; + height: 24px; border-radius: 6px; } @@ -12103,7 +11657,7 @@ tbody { } .confirm-dialogue-body { - background: var(--base); + background: var(--surfaces-surface-01); color: var(--slate12); } @@ -12188,7 +11742,7 @@ tbody { .sidebar-list-wrap { margin-top: 24px; padding: 0px 20px 20px 20px; - height: calc(100vh - 180px); + flex-grow: 1; overflow: auto; span { @@ -12240,13 +11794,13 @@ tbody { padding: 16px 24px; gap: 8px; height: 72px; - border-top: 1px solid var(--slate5); - background: var(--base); + border-top: 1px solid var(--border-weak); + background: var(--surfaces-surface-01); } .drawer-card-title { padding: 16px 20px; - border-bottom: 1px solid var(--slate5); + border-bottom: 1px solid var(--border-weak); height: 64px; h3 { @@ -12309,7 +11863,7 @@ tbody { .tj-user-table-wrapper { height: calc(100vh - 392px); //52+64+40+32+20+62 overflow-y: auto; - background: var(--base); + background: var(--page-weak); border-right: 1px solid var(--slate7); border-bottom: 1px solid var(--slate7); border-left: 1px solid var(--slate7); @@ -12697,8 +12251,10 @@ tbody { } .workspace-nav-list-wrap { - padding: 20px 20px 20px 20px; - height: calc(100vh - 116px) !important; + flex-grow: 1; + padding: 12px 24px; + width: 100%; + box-sizing: border-box; } .upload-user-form span.file-upload-error { @@ -12967,12 +12523,12 @@ tbody { } .profile-page-content-wrap { - background-color: var(--page-default); + background-color: var(--page-weak); padding-top: 40px; } .profile-page-card { - background-color: var(--base); + background-color: var(--surfaces-surface-01); border-radius: 6px; } @@ -13003,7 +12559,6 @@ tbody { .workspace-constant-card-body { min-height: calc(100vh - 408px); - background: var(--base); } .constant-table-wrapper { @@ -13014,13 +12569,9 @@ tbody { .constant-table-card { min-height: 420px; - padding: 16px; - padding-top: 0px; - padding-bottom: 0px; .p-3-constants { padding: 1rem !important; - padding-left: 0px !important; } } @@ -13045,125 +12596,6 @@ tbody { } } -.home-page-content-container { - max-width: 880px; - - @media only screen and (max-width: 768px) { - margin-bottom: 0rem !important; - - .liner { - width: unset !important; - } - - .app-list { - overflow-y: auto; - height: calc(100vh - 26rem); - - .skeleton-container { - display: flex; - flex-direction: column; - - .col { - display: flex; - justify-content: center; - margin-bottom: 1rem; - } - - .card-skeleton-container { - width: 304px; - } - } - } - - .menu-ico { - display: none !important; - } - } -} - -@media only screen and (min-width: 1584px) and (max-width: 1727px) { - - .edit-button, - .launch-button { - width: 113px !important; - } -} - -@media only screen and (max-width: 1583px) and (min-width: 1312px) { - .homepage-app-card-list-item { - max-width: 264px; - - .edit-button, - .launch-button { - width: 109px !important; - } - } -} - -@media only screen and (min-width: 1728px) { - .homepage-app-card-list-item { - max-width: 304px; - - .edit-button, - .launch-button { - width: 129px !important; - } - } - - .home-page-content-container { - max-width: 976px; - } - - .liner { - width: 976px; - } -} - -@media only screen and (max-width: 992px) { - .homepage-app-card-list-item-wrap { - display: flex; - justify-content: center; - margin-left: auto; - margin-right: auto; - width: 100%; - margin-top: 22px; - } - - .homepage-app-card-list-item { - max-width: 304px !important; - flex-basis: 100%; - - .edit-button, - .launch-button { - width: 129px !important; - } - } -} - -@media only screen and (min-width: 993px) and (max-width: 1311px) { - .home-page-content-container { - max-width: 568px; - } - - .homepage-app-card-list-item-wrap { - row-gap: 20px; - } - - .homepage-app-card-list-item { - max-width: 269px; - flex-basis: 100%; - - .edit-button, - .launch-button { - width: 111.5px !important; - } - } - - .liner { - width: 568px; - } -} - .tj-docs-link { color: var(--indigo9) !important; text-decoration: none; @@ -13189,9 +12621,9 @@ tbody { .modal-body-content, .modal-sidebar, .card { - background-color: var(--base) !important; + background-color: var(--page-weak) !important; color: var(--slate12) !important; - border-color: var(--slate5) !important; + border-color: var(--border-weak) !important; } .datasource-modal-sidebar-footer { @@ -13240,14 +12672,10 @@ tbody { .marketplace-body { height: calc(100vh - 64px) !important; overflow-y: auto; - background-color: var(--page-default); + background-color: var(--page-weak); } .plugins-card { - background-color: var(--base); - border: 1px solid var(--slate3); - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); - border-radius: 6px; .card-body-alignment { min-height: 145px; @@ -13529,16 +12957,14 @@ tbody { .instance-settings-page { width: 880px; margin: 0 auto; - background: var(--base); + background: var(--surfaces-surface-01); .page-wrapper { margin-bottom: 50px !important; } .card { - background: var(--base); - border: 1px solid var(--slate7) !important; - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05) !important; + background: var(--surfaces-surface-01); width: 880px; .card-header { @@ -13570,8 +12996,8 @@ tbody { align-items: center; padding: 24px 32px; gap: 8px; - border-top: 1px solid var(--slate5) !important; - background: var(--base); + border-top: 1px solid var(--border-weak) !important; + background: var(--surfaces-surface-01); margin-top: 0px !important; align-Self: 'stretch'; height: 88px; @@ -13695,7 +13121,7 @@ tbody { } .audit-log { - background-color: var(--slate2); + background-color: var(--page-weak); width: unset; .tj-ms { @@ -14782,7 +14208,7 @@ tbody { } .modal-content { - background: var(--base); + background: var(--surfaces-surface-01); color: var(--slate12); } @@ -15142,7 +14568,7 @@ tbody { } .modal-content { - background: var(--base); + background: var(--surfaces-surface-01); color: var(--slate12); } @@ -15218,7 +14644,7 @@ tbody { } .popover-body { - background-color: var(--base); + background-color: var(--surfaces-surface-01); color: var(--slate12); border-radius: 6px; } @@ -16793,6 +16219,11 @@ fieldset:disabled { header { display: flex; gap: 12px; + padding: 16px 24px; + border-radius: 8px; + background: var(--bg-surface-layer-01); + box-shadow: var(--elevation-000-box-shadow); + border: 1px solid var(--border-weak); .left { border-radius: 24px; @@ -16887,12 +16318,49 @@ fieldset:disabled { font-weight: 400; line-height: 18px; } + + .right { + display: flex; + gap: 8px; + flex-wrap: wrap; + + button { + border: none; + outline: none; + display: flex; + gap: 6px; + align-items: center; + padding: 5px 10px; + background: transparent; + border-radius: 6px; + border: 1px solid var(--border-weak, #E4E7EB); + background: var(--button-secondary, #FFF); + box-shadow: 0px 0px 1px 0px var(--dropshadow-100700-layer-1, rgba(48, 50, 51, 0.05)), 0px 1px 1px 0px var(--dropshadow-100400-layer-2, rgba(48, 50, 51, 0.10)); + + span { + color: var(--text-default, #1B1F24); + + /* base/medium */ + font-family: "IBM Plex Sans"; + font-size: 12px; + font-style: normal; + font-weight: 500; + line-height: 18px; + /* 150% */ + } + + &:hover { + border: 1px solid var(--border-default, #CCD1D5); + background: linear-gradient(0deg, var(--button-outline-hover, rgba(136, 144, 153, 0.12)) 0%, var(--button-outline-hover, rgba(136, 144, 153, 0.12)) 100%), var(--button-outline, #FFF); + } + } + } } } section.ai-message-prompt-input-wrapper { border-radius: 6px; - // border: 1px solid var(--border-accent-strong, #4368E3); + border: 1px solid var(--border-weak, #E4E7EB); background: var(--background-surface-layer-01, #FFFFFF); margin-top: 12px; padding: 12px; diff --git a/frontend/src/_ui/Card/Card.jsx b/frontend/src/_ui/Card/Card.jsx index e070cb0f14..967fbed113 100644 --- a/frontend/src/_ui/Card/Card.jsx +++ b/frontend/src/_ui/Card/Card.jsx @@ -11,6 +11,7 @@ const Card = ({ width = 50, usePluginIcon = false, className, + cardClassName, titleClassName, actionButton, darkMode, @@ -37,7 +38,7 @@ const Card = ({ return (
{ e.preventDefault(); diff --git a/frontend/src/_ui/FolderList/FolderList.scss b/frontend/src/_ui/FolderList/FolderList.scss index 921243f1b3..89ae9937fc 100644 --- a/frontend/src/_ui/FolderList/FolderList.scss +++ b/frontend/src/_ui/FolderList/FolderList.scss @@ -5,7 +5,7 @@ line-height: 20px; display: flex; align-items: center; - color: var(--slate12); + color: var(--text-default); min-height: 32px; cursor: pointer; padding: 6px 8px; @@ -71,5 +71,5 @@ } .tj-list-item-selected { - background-color: var(--slate5);; + background-color: var(--interactive-default); } \ No newline at end of file diff --git a/frontend/src/_ui/Header/index.jsx b/frontend/src/_ui/Header/index.jsx index dc46793984..66425c4619 100644 --- a/frontend/src/_ui/Header/index.jsx +++ b/frontend/src/_ui/Header/index.jsx @@ -71,9 +71,9 @@ function Header({
{!collapseSidebar && (
-
+
-

+

{pathname}

{routesWithTags(pathname) && ( @@ -117,7 +117,7 @@ function Header({
)}
-
+
{enableCollapsibleSidebar && collapseSidebar && (
diff --git a/frontend/src/_ui/Icon/solidIcons/AppLimitSvg.jsx b/frontend/src/_ui/Icon/solidIcons/AppLimitSvg.jsx index e9490c038c..91759919a0 100644 --- a/frontend/src/_ui/Icon/solidIcons/AppLimitSvg.jsx +++ b/frontend/src/_ui/Icon/solidIcons/AppLimitSvg.jsx @@ -1,22 +1,22 @@ import React from 'react'; -const AppLimitSvg = () => ( - +const AppLimitSvg = ({ fill }) => ( + ); diff --git a/frontend/src/_ui/Icon/solidIcons/Plus.jsx b/frontend/src/_ui/Icon/solidIcons/Plus.jsx index 1af087cdeb..7f7b601dad 100644 --- a/frontend/src/_ui/Icon/solidIcons/Plus.jsx +++ b/frontend/src/_ui/Icon/solidIcons/Plus.jsx @@ -5,7 +5,7 @@ const Plus = ({ fill = '#C1C8CD', width = '25', className = '', viewBox = '0 0 2 width={width} height={width} viewBox={viewBox} - fill="none" + fill={fill} xmlns="http://www.w3.org/2000/svg" className={className} data-cy={dataCy} diff --git a/frontend/src/_ui/Icon/solidIcons/Search.jsx b/frontend/src/_ui/Icon/solidIcons/Search.jsx index 9fae3533ee..c7045732cb 100644 --- a/frontend/src/_ui/Icon/solidIcons/Search.jsx +++ b/frontend/src/_ui/Icon/solidIcons/Search.jsx @@ -5,7 +5,7 @@ const Search = ({ fill = '#C1C8CD', width = '24', className = '', viewBox = '0 0 width={width} height={width} viewBox={viewBox} - fill="none" + fill={fill} xmlns="http://www.w3.org/2000/svg" className={className} style={style} diff --git a/frontend/src/_ui/Input-V3/index.js b/frontend/src/_ui/Input-V3/index.js index 71b2b3cf2a..d80606981d 100644 --- a/frontend/src/_ui/Input-V3/index.js +++ b/frontend/src/_ui/Input-V3/index.js @@ -6,7 +6,7 @@ import { toast } from 'react-hot-toast'; import InputComponent from '@/components/ui/Input/Index'; const InputV3 = ({ helpText, ...props }) => { - const { workspaceVariables, workspaceConstants, value, widget, disabled, encrypted } = props; + const { workspaceVariables, workspaceConstants, value, widget, encrypted, onBlur } = props; const [isFocused, setIsFocused] = useState(false); const [isCopied, setIsCopied] = useState(false); @@ -37,6 +37,11 @@ const InputV3 = ({ helpText, ...props }) => { setIsFocused(true)} + onBlur={(event) => { + setIsFocused(false); + onBlur(event); + }} styles="tw-bg-transparent" label={props.label} placeholder={props.placeholder} @@ -49,6 +54,11 @@ const InputV3 = ({ helpText, ...props }) => { {...props} type="password" value={value} + onFocus={() => setIsFocused(true)} + onBlur={(event) => { + setIsFocused(false); + onBlur(event); + }} styles="tw-bg-transparent" label={props.label} placeholder={props.placeholder} diff --git a/frontend/src/_ui/Input/index.js b/frontend/src/_ui/Input/index.js index 7b876d4e45..2e632c74e7 100644 --- a/frontend/src/_ui/Input/index.js +++ b/frontend/src/_ui/Input/index.js @@ -5,20 +5,21 @@ import SolidIcon from '../Icon/SolidIcons'; import { toast } from 'react-hot-toast'; const Input = ({ helpText, onBlur, ...props }) => { - const { workspaceVariables, workspaceConstants, value, type, disabled, encrypted } = props; + const { workspaceVariables, workspaceConstants, value, type, disabled, encrypted, isWorkspaceConstant } = props; const [isFocused, setIsFocused] = useState(false); const [isCopied, setIsCopied] = useState(false); - const [showPasswordProps, setShowPasswordProps] = useState({ - inputType: type, - iconType: 'eyedisable', - }); + const [showPassword, setShowPassword] = useState(false); + const inputType = type === 'password' || encrypted ? (showPassword ? 'text' : 'password') : type; + const iconType = showPassword ? 'eye' : 'eyedisable'; + + useEffect(() => { + if (isWorkspaceConstant) { + setShowPassword(true); + } + }, [isWorkspaceConstant]); const toggleShowPassword = () => { - if (inputType !== 'text') { - setShowPasswordProps({ inputType: 'text', iconType: 'eye' }); - } else { - setShowPasswordProps({ inputType: 'password', iconType: 'eyedisable' }); - } + setShowPassword(!showPassword); }; const handleCopyToClipboard = async () => { @@ -36,12 +37,6 @@ const Input = ({ helpText, onBlur, ...props }) => { } }; - useEffect(() => { - if (disabled && encrypted) setShowPasswordProps({ inputType: 'password', iconType: 'eyedisable' }); - }, [disabled]); - - const { inputType, iconType } = showPasswordProps; - return (
{ }} /> {(type === 'password' || encrypted) && ( -
- {' '} +
)} @@ -66,12 +63,10 @@ const Input = ({ helpText, onBlur, ...props }) => { value && (!isCopied ? (
- {' '}
) : (
- {' '} Copied!
))} diff --git a/frontend/src/_ui/Layout/index.jsx b/frontend/src/_ui/Layout/index.jsx index aa784e04cf..1f7095dd04 100644 --- a/frontend/src/_ui/Layout/index.jsx +++ b/frontend/src/_ui/Layout/index.jsx @@ -148,7 +148,7 @@ function Layout({ collapseSidebar={collapseSidebar} toggleCollapsibleSidebar={toggleCollapsibleSidebar} /> -
{children}
+
{children}
.form-check-input:not(:checked) { - background-color: #ffffff; + background-color: var(--slider-track); } .text-wrappers{ display: flex; diff --git a/frontend/src/components/ui/Card/Index.jsx b/frontend/src/components/ui/Card/Index.jsx new file mode 100644 index 0000000000..3005fcdea5 --- /dev/null +++ b/frontend/src/components/ui/Card/Index.jsx @@ -0,0 +1,35 @@ +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +const Card = React.forwardRef(({ className, ...props }, ref) => ( +
+)); +Card.displayName = 'Card'; + +const CardHeader = React.forwardRef(({ className, ...props }, ref) => ( +
+)); +CardHeader.displayName = 'CardHeader'; + +const CardTitle = React.forwardRef(({ className, ...props }, ref) => ( +
+)); +CardTitle.displayName = 'CardTitle'; + +const CardDescription = React.forwardRef(({ className, ...props }, ref) => ( +
+)); +CardDescription.displayName = 'CardDescription'; + +const CardContent = React.forwardRef(({ className, ...props }, ref) => ( +
+)); +CardContent.displayName = 'CardContent'; + +const CardFooter = React.forwardRef(({ className, ...props }, ref) => ( +
+)); +CardFooter.displayName = 'CardFooter'; + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }; diff --git a/frontend/src/components/ui/Input/CommonInput/Index.jsx b/frontend/src/components/ui/Input/CommonInput/Index.jsx index 2b968a0940..c992db5aaa 100644 --- a/frontend/src/components/ui/Input/CommonInput/Index.jsx +++ b/frontend/src/components/ui/Input/CommonInput/Index.jsx @@ -6,14 +6,26 @@ import { ButtonSolid } from '../../../../_components/AppButton'; import { generateCypressDataCy } from '../../../../modules/common/helpers/cypressHelpers.js'; const CommonInput = ({ label, helperText, disabled, required, onChange: change, ...restProps }) => { - const { type, encrypted, validation, isValidatedMessages, isDisabled } = restProps; + const { + propertyKey, + type, + encrypted, + validation, + isValidatedMessages, + isDisabled, + isEditing, + handleEncryptedFieldsToggle, + labelDisabled, + } = restProps; const InputComponentType = type === 'number' ? NumberInput : TextInput; const [isValid, setIsValid] = useState(null); const [message, setMessage] = useState(''); - const [isEditing, setIsEditing] = useState(false); const isEncrypted = type === 'password' || encrypted; + const isWorkspaceConstant = + restProps.placeholder && + (restProps.placeholder.includes('{{constants') || restProps.placeholder.includes('{{secrets')); const handleChange = (e) => { if (validation) { @@ -39,20 +51,12 @@ const CommonInput = ({ label, helperText, disabled, required, onChange: change, } }, [isValid, isValidatedMessages]); - const toggleEditing = () => { - if (isDisabled) return; - - const willBeInEditMode = !isEditing; - setIsEditing(willBeInEditMode); - change({ target: { value: '' } }); - }; - return (
{label && (
- +
)} {type === 'password' && ( @@ -65,7 +69,7 @@ const CommonInput = ({ label, helperText, disabled, required, onChange: change, target="_blank" rel="noreferrer" disabled={isDisabled} - onClick={toggleEditing} + onClick={(e) => handleEncryptedFieldsToggle(e, propertyKey)} data-cy={`button-${generateCypressDataCy(isEditing ? 'Cancel' : 'Edit')}`} > {isEditing ? 'Cancel' : 'Edit'} @@ -86,6 +90,7 @@ const CommonInput = ({ label, helperText, disabled, required, onChange: change, required={required} response={isValid} onChange={handleChange} + isWorkspaceConstant={isWorkspaceConstant} {...restProps} /> {helperText && ( diff --git a/frontend/src/components/ui/Input/Input.jsx b/frontend/src/components/ui/Input/Input.jsx index 0f227023e1..24090abc2f 100644 --- a/frontend/src/components/ui/Input/Input.jsx +++ b/frontend/src/components/ui/Input/Input.jsx @@ -2,56 +2,65 @@ import * as React from 'react'; import { cn } from '@/lib/utils'; import { inputVariants } from './InputUtils/Variants'; import SolidIcon from '../../../_ui/Icon/SolidIcons'; +import { useEffect } from 'react'; -const Input = React.forwardRef(({ className, size, type, multiline, response, rows = 3, ...props }, ref) => { - const [isPasswordVisible, setIsPasswordVisible] = React.useState(false); - const isPasswordField = type === 'password'; +const Input = React.forwardRef( + ({ className, size, type, multiline, response, isWorkspaceConstant, rows = 3, ...props }, ref) => { + const [isPasswordVisible, setIsPasswordVisible] = React.useState(false); + const isPasswordField = type === 'password'; - const togglePasswordVisibility = () => { - if (!props.disabled) { - setIsPasswordVisible((prev) => !prev); - } - }; + const togglePasswordVisibility = () => { + if (!props.disabled) { + setIsPasswordVisible((prev) => !prev); + } + }; - const validationClass = response === true ? 'valid-textarea' : response === false ? 'invalid-textarea' : ''; + useEffect(() => { + if (isWorkspaceConstant) { + setIsPasswordVisible(true); + } + }, [isWorkspaceConstant]); - return ( -
- {multiline ? ( -