From 5024eff92e07f9ab9f23e99222d8606e92fb56f9 Mon Sep 17 00:00:00 2001 From: Rudhra Deep Biswas <98055396+rudeUltra@users.noreply.github.com> Date: Tue, 13 Aug 2024 13:03:58 +0530 Subject: [PATCH 1/7] current user global inspector fix (#10468) --- frontend/src/_stores/currentStateStore.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/frontend/src/_stores/currentStateStore.js b/frontend/src/_stores/currentStateStore.js index 96b24dec83..e1cc4d54f0 100644 --- a/frontend/src/_stores/currentStateStore.js +++ b/frontend/src/_stores/currentStateStore.js @@ -7,13 +7,15 @@ import { useEditorStore } from '@/_stores/editorStore'; import { useQueryPanelStore } from '@/_stores/queryPanelStore'; import update from 'immutability-helper'; const { diff } = require('deep-object-diff'); - +import { useAppDataStore } from './appDataStore'; +import { authenticationService } from '@/_services'; const initialState = { queries: {}, components: {}, globals: { theme: { name: 'light' }, urlparams: null, + currentUser: {}, }, errors: {}, variables: {}, @@ -53,9 +55,22 @@ export const useCurrentStateStore = create( }, setEditorReady: (isEditorReady) => set({ isEditorReady }), initializeCurrentStateOnVersionSwitch: () => { + //fetch user for current app + const currentUser = useAppDataStore.getState().currentUser; + const userVars = { + email: currentUser?.email, + firstName: currentUser?.first_name, + lastName: currentUser?.last_name, + groups: authenticationService.currentSessionValue.group_permissions?.map((group) => group.group), + ssoUserInfo: currentUser?.sso_user_info, + }; const newInitialState = { ...initialState, constants: get().constants, + globals: { + ...get().globals, + currentUser: userVars, + }, }; set({ ...newInitialState }, false, { type: 'INITIALIZE_CURRENT_STATE_ON_VERSION_SWITCH', From 30dd554bb0ddef6ddd022e11e21d0aa8f2ccc4c4 Mon Sep 17 00:00:00 2001 From: Rudhra Deep Biswas <98055396+rudeUltra@users.noreply.github.com> Date: Tue, 13 Aug 2024 13:08:13 +0530 Subject: [PATCH 2/7] Updated nav links for workspace settings (#10556) * updated nav links for workspace settings * review changes * changes * fix --------- Co-authored-by: gsmithun4 --- .../src/OrganizationSettingsPage/constant.js | 6 + .../src/OrganizationSettingsPage/index.jsx | 109 +++++++++--------- 2 files changed, 59 insertions(+), 56 deletions(-) create mode 100644 frontend/src/OrganizationSettingsPage/constant.js diff --git a/frontend/src/OrganizationSettingsPage/constant.js b/frontend/src/OrganizationSettingsPage/constant.js new file mode 100644 index 0000000000..4a5153a41a --- /dev/null +++ b/frontend/src/OrganizationSettingsPage/constant.js @@ -0,0 +1,6 @@ +export const workspaceSettingsLinks = [ + { id: 'users', name: 'Users', route: 'users', conditions: ['admin'] }, + { id: 'groups', name: 'Groups', route: 'groups', conditions: ['admin'] }, + { id: 'workspacelogin', name: 'Workspace login', route: 'workspace-login', conditions: ['admin'] }, + { id: 'workspacevariables', name: 'Workspace variables', route: 'workspace-variables', conditions: ['admin'] }, +]; diff --git a/frontend/src/OrganizationSettingsPage/index.jsx b/frontend/src/OrganizationSettingsPage/index.jsx index 32094dbee4..b79cdad83d 100644 --- a/frontend/src/OrganizationSettingsPage/index.jsx +++ b/frontend/src/OrganizationSettingsPage/index.jsx @@ -1,57 +1,59 @@ import React, { useEffect, useState, useContext } from 'react'; import cx from 'classnames'; -import { useParams, Outlet, Link, useNavigate, useLocation } from 'react-router-dom'; +import { Outlet, Link, useNavigate, useLocation } from 'react-router-dom'; import Layout from '@/_ui/Layout'; import { authenticationService } from '@/_services'; import { BreadCrumbContext } from '../App/App'; import FolderList from '@/_ui/FolderList/FolderList'; import { OrganizationList } from '../_components/OrganizationManager/List'; -import { getWorkspaceId } from '@/_helpers/utils'; -import { getSubpath } from '@/_helpers/routes'; +import { workspaceSettingsLinks } from './constant'; export function OrganizationSettings(props) { - const [admin, setAdmin] = useState(authenticationService.currentSessionValue?.admin); - const [selectedTab, setSelectedTab] = useState(admin ? 'Users & permissions' : 'manageEnvVars'); + const admin = authenticationService.currentSessionValue?.admin; + const [selectedTab, setSelectedTab] = useState(admin ? workspaceSettingsLinks[0].id : 'workspacevariables'); const navigate = useNavigate(); const location = useLocation(); const { updateSidebarNAV } = useContext(BreadCrumbContext); - const { workspaceId } = useParams(); + const [conditionObj, setConditionObj] = useState({ admin: authenticationService.currentSessionValue?.admin }); - const sideBarNavs = ['Users', 'Groups', 'Workspace login', 'Workspace variables']; - const defaultOrgName = (groupName) => { - switch (groupName) { - case 'users': - return 'Users'; - case 'groups': - return 'Groups'; - case 'workspace-login': - return 'Workspace login'; - case 'workspace-variables': - return 'Workspace variables'; - default: - return groupName; + const checkConditions = (conditions, conditionsObj) => { + if (!conditions || conditions.length === 0) { + return true; } + return conditions.every((condition) => conditionsObj?.[condition] === true); + }; + + //Filtered Links from the workspace settings links array + const filteredLinks = () => + workspaceSettingsLinks.filter((item) => { + return checkConditions(item.conditions, conditionObj); + }); + + const getMenuFromRoute = (route) => { + return workspaceSettingsLinks?.find((e) => e.route === route) || {}; }; useEffect(() => { const subscription = authenticationService.currentSession.subscribe((newOrd) => { - setAdmin(newOrd?.admin); + setConditionObj({ admin: newOrd?.admin }); }); - admin ? updateSidebarNAV('Users') : updateSidebarNAV('Workspace variables'); - - () => subscription.unsubsciption(); const selectedTabFromRoute = location.pathname.split('/').pop(); if (selectedTabFromRoute === 'workspace-settings') { - setSelectedTab(admin ? 'Users' : 'Workspace variables'); - const subPath = getSubpath(); - const path = subPath ? `${subPath}/${workspaceId}/workspace-settings` : `/${workspaceId}/workspace-settings`; - window.location.href = admin ? `${path}/users` : `${path}/workspace-variables`; + // No Sub routes added loading first one + setSelectedTab(admin ? workspaceSettingsLinks[0].id : 'workspacevariables'); } else { - setSelectedTab(defaultOrgName(selectedTabFromRoute)); + setSelectedTab(getMenuFromRoute(selectedTabFromRoute)?.id); } - updateSidebarNAV(defaultOrgName(selectedTabFromRoute)); - }, [navigate, workspaceId, authenticationService.currentSessionValue?.admin]); + + return () => subscription.unsubscribe(); + }, [authenticationService.currentSessionValue?.admin]); + + useEffect(() => { + const menu = workspaceSettingsLinks?.find((m) => m.id === selectedTab); + updateSidebarNAV(menu?.name || ''); + navigate(menu?.route || ''); + }, [selectedTab]); return ( @@ -59,12 +61,11 @@ export function OrganizationSettings(props) {
- {sideBarNavs.map((item, index) => { + {filteredLinks().map((item, index) => { const Wrapper = ({ children }) => <>{children}; return ( - {admin && ( - { - setSelectedTab(defaultOrgName(item)); - if (item == 'Users') updateSidebarNAV('Users'); - else updateSidebarNAV(item); - }} - selectedItem={selectedTab == defaultOrgName(item)} - renderBadgeForItems={['Workspace constants']} - renderBadge={() => ( - - new - - )} - dataCy={item.toLowerCase().replace(/\s+/g, '-')} - > - {item} - - )} + { + setSelectedTab(item.id); + }} + selectedItem={selectedTab == item.id} + renderBadgeForItems={[]} + renderBadge={() => ( + + new + + )} + dataCy={item.name.toLowerCase().replace(/\s+/g, '-')} + > + {item.name} + ); From 5dfcc56047eeea14910488b753a36211200c3948 Mon Sep 17 00:00:00 2001 From: rohanlahori Date: Wed, 31 Jul 2024 16:25:09 +0530 Subject: [PATCH 3/7] pop-up-message-change --- frontend/src/_helpers/error_constants.js | 2 +- server/src/helpers/error_type.constant.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/_helpers/error_constants.js b/frontend/src/_helpers/error_constants.js index f6a15588d3..4b968f002e 100644 --- a/frontend/src/_helpers/error_constants.js +++ b/frontend/src/_helpers/error_constants.js @@ -1,5 +1,5 @@ export const APP_ERROR_TYPE = { IMPORT_EXPORT_SERVICE: { - UNSUPPORTED_VERSION_ERROR: "Can't import higher version application to lower version", + UNSUPPORTED_VERSION_ERROR: 'Apps built on later versions of ToolJet cannot be imported', }, }; diff --git a/server/src/helpers/error_type.constant.ts b/server/src/helpers/error_type.constant.ts index f6a15588d3..4b968f002e 100644 --- a/server/src/helpers/error_type.constant.ts +++ b/server/src/helpers/error_type.constant.ts @@ -1,5 +1,5 @@ export const APP_ERROR_TYPE = { IMPORT_EXPORT_SERVICE: { - UNSUPPORTED_VERSION_ERROR: "Can't import higher version application to lower version", + UNSUPPORTED_VERSION_ERROR: 'Apps built on later versions of ToolJet cannot be imported', }, }; From 523c80f6950a387e5193eca7389703786b5e7a0d Mon Sep 17 00:00:00 2001 From: Rudhra Deep Biswas <98055396+rudeUltra@users.noreply.github.com> Date: Tue, 13 Aug 2024 13:15:18 +0530 Subject: [PATCH 4/7] New add plugins UI (#10538) * New add plugins UI * hover and height --- .../GlobalDataSourcesPage/index.jsx | 59 ++++++++++--------- frontend/src/_styles/global-datasources.scss | 33 +++++++++++ 2 files changed, 63 insertions(+), 29 deletions(-) diff --git a/frontend/src/GlobalDatasources/GlobalDataSourcesPage/index.jsx b/frontend/src/GlobalDatasources/GlobalDataSourcesPage/index.jsx index 0512eadf28..1fddbb5b96 100644 --- a/frontend/src/GlobalDatasources/GlobalDataSourcesPage/index.jsx +++ b/frontend/src/GlobalDatasources/GlobalDataSourcesPage/index.jsx @@ -31,7 +31,6 @@ export const GlobalDataSourcesPage = ({ darkMode = false, updateSelectedDatasour const [addingDataSource, setAddingDataSource] = useState(false); const [suggestingDataSource, setSuggestingDataSource] = useState(false); const { t } = useTranslation(); - const navigate = useNavigate(); const { admin } = authenticationService.currentSessionValue; const marketplaceEnabled = admin && window.public_config?.ENABLE_MARKETPLACE_FEATURE == 'true'; const [modalProps, setModalProps] = useState({ @@ -296,34 +295,6 @@ export const GlobalDataSourcesPage = ({ darkMode = false, updateSelectedDatasour }; const renderCardGroup = (source, type) => { - if (type === 'Plugins' && source.length === 0) { - return ( -
-
- -
-
No plugins added
- {admin && ( - <> -
- Browse through plugins in marketplace to add them as a Data Source.{' '} -
- { - marketplaceEnabled - ? navigate('/integrations') - : toast.error('Please enable marketplace to add plugins'); - }} - style={{ margin: 'auto' }} - variant="secondary" - > - Add plugins - - - )} -
- ); - } const addDataSourceBtn = (item) => ( ))} + {type === 'Plugins' && ( +
+
{ + if (marketplaceEnabled) { + window.open('/integrations', '_blank'); + } else { + toast.error('Please enable marketplace to add plugins'); + } + }} + data-cy={`data-source-add-plugin`} + > +
+
+ +

+ Add plugin +
+
+
+
+ )}
); diff --git a/frontend/src/_styles/global-datasources.scss b/frontend/src/_styles/global-datasources.scss index 6ff16d7f77..1cbaed557b 100644 --- a/frontend/src/_styles/global-datasources.scss +++ b/frontend/src/_styles/global-datasources.scss @@ -300,4 +300,37 @@ border-radius: 6px; margin: auto; } +} + + +.add-plugin-card{ + border: 1px dashed var(--border-default, #CCD1D5); + background-color: var(--interactive-weak); + + &:hover{ + border: 1px dashed var(--border-strong, #CCD1D5); + background-color: var(--interactive-default); + } +} + + + +.add-plugin-card-title{ + font-weight: 500; + font-size: 14px; + line-height: 20px; + color: var(--text-default); +} + + +.dark-theme{ + .add-plugin-card{ + border: 1px dashed var(--border-default, #CCD1D5); + background-color: var(--interactive-weak); + + &:hover{ + border: 1px dashed var(--border-strong, #CCD1D5); + background-color: var(--interactive-default); + } + } } \ No newline at end of file From b49dbf9b1c99d230606870dec7bdd0d731bc2161 Mon Sep 17 00:00:00 2001 From: Rohan Lahori <64496391+rohanlahori@users.noreply.github.com> Date: Tue, 13 Aug 2024 13:30:58 +0530 Subject: [PATCH 5/7] Feature/autofill workspaceslug using workspace name (#10432) * fixed workspace slug autofilling * changes for auto update slug url based on name * changes to enable workspace button only when required * made change for removing empty spaces * added - support in the slug * fixed all the bugs in workspace creation card * removed all the console used for debugging * added check for setting the prop to true * add slug set dependency in the useEffect prop --- .../CreateOrganization.jsx | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/frontend/src/_components/OrganizationManager/CreateOrganization.jsx b/frontend/src/_components/OrganizationManager/CreateOrganization.jsx index 0b777db87e..204487773a 100644 --- a/frontend/src/_components/OrganizationManager/CreateOrganization.jsx +++ b/frontend/src/_components/OrganizationManager/CreateOrganization.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useRef, useEffect } from 'react'; import { organizationService } from '@/_services'; import AlertDialog from '@/_ui/AlertDialog'; import { useTranslation } from 'react-i18next'; @@ -18,10 +18,10 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => { const [isSlugDisabled, setSlugDisabled] = useState(true); const darkMode = localStorage.getItem('darkMode') === 'true'; const { t } = useTranslation(); + const isSlugSet = useRef(false); // Flag to track if slug has been initially set const createOrganization = () => { let emptyError = false; - [name, slug].map((field, index) => { if (!field?.value?.trim()) { index === 0 @@ -77,7 +77,6 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => { !(field === 'slug'), field === 'slug' ); - /* If the basic validation is passing. then check the uniqueness */ if (error?.status === true) { try { @@ -92,7 +91,6 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => { }; } } - const disabled = !error?.status; const updatedValue = { value, @@ -126,17 +124,45 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => { setShowCreateOrg(false); setNameDisabled(true); setSlugDisabled(true); + isSlugSet.current = false; }; const delayedSlugChange = _.debounce(async (value) => { setSlugProgress(true); await handleInputChange(value, 'slug'); }, 300); - const delayedNameChange = _.debounce(async (value) => { setWorkspaceNameProgress(true); await handleInputChange(value, 'name'); }, 300); + useEffect(() => { + if (!isSlugSet.current && name.value && !slugProgress && !workspaceNameProgress) { + const defaultValue = + name.value + .replace(/\s+/g, '') + .toLowerCase() + .replace(/[^a-z0-9-\s]/g, '') || ''; + setSlug({ value: defaultValue, error: '' }); + + const checkWorkspaceUniqueness = async () => { + try { + await organizationService.checkWorkspaceUniqueness(null, defaultValue); + } catch (errResponse) { + let error = { + status: false, + errorMsg: errResponse?.error, + }; + setSlug({ value: defaultValue, error: error?.errorMsg }); + } + }; + checkWorkspaceUniqueness(); + setSlugDisabled(false); + setSlugProgress(false); + } + if (slugProgress && !isSlugSet.current) { + isSlugSet.current = true; + } + }, [name.value, slugProgress, workspaceNameProgress, isSlugSet]); const isDisabled = isCreating || isNameDisabled || isSlugDisabled || slugProgress || workspaceNameProgress; @@ -184,6 +210,7 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => { placeholder={t('header.organization.workspaceSlug', 'Unique workspace slug')} disabled={isCreating} maxLength={50} + defaultValue={slug.value || ''} onChange={async (e) => { e.persist(); await delayedSlugChange(e.target.value); @@ -203,6 +230,7 @@ export const CreateOrganization = ({ showCreateOrg, setShowCreateOrg }) => {
)} + {slug?.error ? (