ToolJet/frontend/src/Editor/LeftSidebar/index.jsx
Johnson Cherian 3169d38d63
Release: Appbuilder S1 (#10081)
* fix : color for all new columns

* revert

* Fix: selection of copy of selected component for ease (#9818)

* fix: selection of copy of selected component for ease

* add pre selection for clonig as well

* add clone check

* fixes selection of components on empty canvas

* Fix: sizing issues in horizontal divider (#9942)

* fix horizontal divider sizing issues

* fix dark mode color in horizontal divider and remove unused class

* add custom fallback for images when not found (#9943)

* cherry pick error message log changes and fix tjdb error logs in debugger (#9951)

* Fix: mouse release on canvas when properties/styles values selected (#9732)

* fix: mouse release on canvas when properties/styles values selected

* fix: event name

* fix: rest api headers empty state while creating new query (#9729)

* fix: selection issue in table row while editing  (#9944)

* allow selection in table cell

* update classname for selection

* display date picker date as text instead of input in read only mode

* Add new revamped multiselect widget (#9837)

* init textinput revamp

* updated styles panel

* bugfix

* updates

* fix :: accordion

* fix :: styling

* add box shadow , additional property,tooltip

* fix conditional render for styles

* feat :: fixed order of each property and styles

* feat :: styling input

* bugfix

* feat :: add option to add icon

* add option to add icon

* adding option to toggle visibility

* updated password input with new design

* chnaging component location

* bugfix

* style fixes

* fix :: added loader

* updated :: few detailing

* few bugfixes

* fix :: for form widget label

* fixes

* added option to add icon color

* including label field for password input

* fix for label

* fix

* test fix backward compatibility for height

* updates

* revert

* adding key for distinguishing older and newer widgets

* testing

* test

* test

* update

* update

* migration testing

* limit vertical resizing in textinput

* testing

* throw test

* test

* adding check for label length

* fixing edge cases

* removing resize

* backward compatibility height

* backward compatibility

* number input review fixes

* added exposed items

* fixing csa

* ui fixes

* fix height compatibility

* feat :: csa for all inputs and exposed variables

* backward compatibility fixes and validation fixes

* fixes :: textinput positioning of loader and icon

* fix :: password input

* cleanup and fixes

* fixes

* cleanup

* fixes

* review fixes

* review fixes

* typo fix

* fix padding

* review fixes styles component panel

* fix naming

* fix padding

* feat :: toggle switch revamp

* init checkbox

* fixes

* fixes

* switch fixes

* validation fix

* fixes

* cleanup

* height fix

* fix height toggle

* updates

* fix :: icons position

* updates

* cleanup

* updates events , csa

* cleanup

* backward compatibility

* clean

* backward compatibility fix

* label fixed to one line

* feat :: change validation from properties

* ui fixes

* icon name

* removed 'px' text from tooltip

* added onchange event for checkbox

* fixes placeholder

* few updates :: removing label in form

* ui in form

* fire onchange

* update :: number input validation behaviour

* testing fixes

* added side handlers

* removing unwanted fx

* disabling fx for padding field

* ordering change

* fix

* label issue + restricted side handler

* fix :: box shadow bug

* fix

* on change event doesnt propagate exposed vars correctly

* adding debounce for slider value change

* fix :: for modal ooen bug during onfocus event

* test slider

* fix :: bugs regarding state update in checbox , slider , slider bug

* update slider with radix slider

* bugfix

* update tooltip

* fix toggle switch

* fixes : inspector

* fix : checkbox label

* Remove date-fns depedency from table datepicker

* Revert Remove date-fns depedency from table datepicker

* feat : checkbox completed

* update checkbox review changes

* feat : toggle component

* feat : added new toggle component

* fix : colors

* updated review changes

* update name for old and new version

* update

* case change

* update

* update icon

* removed padding from checkbox and toggle

* fix naming

* product review and bugfixes : changes

* fix : checkbox setvalue action

* Update setvalue action in toggle

* fixed: section for legacy and new components

* add new version of dropdown

* Add same styles as other input components

* fix height issues

* Add new revamped multiselect widget

* Fix design review

* fix design issues

* Fix

* Fix merge issues

* Add menu portal target

* resolve code comments

* widget config changes

* add hover for clear icon

* fix

* Fix review comments

* Multiselect changes after dropdown merge

* exposed variables

* Delete unused components

* Multiselect fixes

* Dropdown CSS fixes and multiselect fixes

* Fix merge issues

* fix

* Add highlight text

* Change multiselect UI

* fix error message

* fix multiselect opening closing

* placeholder fix

* fix highlighting in multiselect

* fix : testing bugs

* fix : default value

* Fix merge issues

* Fix Qa bugs

* Fix QA bugs

* Fix codehinter default values

* fix fireEvent on focus

* Fixes

* Provide minwidth to dropdown and multiselect

* Fix search input value not getting updated

---------

Co-authored-by: stepinfwd <stepinfwd@gmail.com>
Co-authored-by: Johnson Cherian <johnsonc.dev@gmail.com>

* Fix: remove mandatory key from password input (#9786)

* Remove date-fns depedency from table datepicker

* Revert Remove date-fns depedency from table datepicker

* remove mandatory key from password input

---------

Co-authored-by: Nakul Nagargade <nakul@tooljet.com>
Co-authored-by: Johnson Cherian <johnsonc.dev@gmail.com>

* feat : Query manager separated to different tabs (#9823)

* change toggle for query manager and revamp preview

* feat : query manger body revamp

* updates

* fix : tranformation switch

* preview integration

* loader safari changes and overflow fix

* fix

* fix : settings tab QM

* revert few changes to fix datasources page

* revert header options change

* zindex fix for query-pane

* fix : events ui

* fix :events widget manager

* code optimised for this file

* QM header fixes

* dark mode changes

* fix : info icon

* open preview drawer on run query

* fix : query manager query section icons update

* update color

* design feedbacks and make preview panel resizable

* update toggle for preview result & increate draggable area

* fix :review changes

* merge fixes

* Merge branch 'appbuilder-1.8' into feature/query-manager-body

* fix : codehinter in disabled state

* ui fix

* code refactor

* cleanup

* fix fontsize in datasource selector popup

* fix border issue in preview container and increase draggable area

* fix : review fixes

* fix: fixed text css formatting for safari support

* Revert "code refactor"

This reverts commit 4763dd11a3.

* typo

* fix : not able to select text in preview

* fix : not able to view add params

* fix selection issue in preview

* fix : add scroll in query  manager when preview is blocking view

---------

Co-authored-by: Kartik Gupta <gupta.kartik18kg@gmail.com>

* Fixes: select all click behaviour on label (#10108)

* fixes: select all click behaviour on label

* fix: legacy component names

* fix: selecto issue (#10107)

* Fix : Prevent component autofill (#10040)

* fix : prevent other component from autofilling data when password is filled from browser suggestions

* optimise

* feat: skip onDragStop execution if drag event is empty (#10118)

* feat: skip onDragStop execution if drag event is empty

* fix: added additonal logs for  error

* display query preview data in preview panel and display transformation failure stacktrace data in previewpanel as well (#10129)

* Fix while adding new rows in table components when ever entered the text and pressed enter it doubles the text (#10112)

* Integration bugfixes appbuilder 1.8 (#10109)

* fix : query maanager duplicate and preview issue

* fix : multiselect breaking on making dynamic options null

* fix : preview and query panel integration bugs

* fix : placeholder

* fix : doc links

* fix : scroll in TJDB filter section

* fix : portal for multiselect

* fixes

* fix : image column table alignment

* fix : doc link for multiselect

* fix : codehinter state being persited across components

* fix :export app qery manager items not coming in correct order

* fix: search icon position

* code refactor

---------

Co-authored-by: Johnson Cherian <johnsonc.dev@gmail.com>

* add z-index to app name info header container (#10116)

* Fix dropdown and multiselect crash on integer labels (#10128)

* cast integer labels to string

* add null check for label and provide default value for empty labels

* empty and null handle for schemas and other values

* revert changes

* Fix: dark mode on preview names (#10136)

* fix: dark mode of preview names

* fix background color of preview

* fix tjdb query import (#10134)

* fix :revert radio button name change (#10153)

* Fix: select issue on multiselect (#10137)

* remove portal from multiselect

* fix: dynamic values for options in dropdown/multiselect

* remove fx from default option

* Fix: delete on options delete in dropdown (#10192)

* fix: delete on options delete

* fix: overlapping of multiselect on parent container

* fix: outside click of multiselect

* hotfix : Table breaking on importing older apps with null value in column (#10185)

* fix : table breaking on importing older apps with null value in column

* fix : table crash , codehinter not saving values upon page change

* remove low priority wrapper from autosave

* remove logs

* added delay to autosave as callback

* fix: dropdown crash on invalid data (#10202)

* revert to previous transformation code , fix darkmode color (#10216)

* fix : doclink for dropdown (#10217)

* fix : Transformations value getting cleared / not getting saved (#10218)

* fix : transformation value not getting saved

* remove dependency

* chore: version update for release

---------

Co-authored-by: stepinfwd <stepinfwd@gmail.com>
Co-authored-by: vjaris42 <vjy239@gmail.com>
Co-authored-by: Kartik Gupta <gupta.kartik18kg@gmail.com>
Co-authored-by: Nakul Nagargade <133095394+nakulnagargade@users.noreply.github.com>
Co-authored-by: Nakul Nagargade <nakul@tooljet.com>
Co-authored-by: Akshay <akshaysasidharan93@gmail.com>
2024-07-01 08:46:22 +05:30

323 lines
11 KiB
JavaScript

import '@/_styles/left-sidebar.scss';
import React, { useState, useImperativeHandle, forwardRef, useEffect, useRef } from 'react';
import _ from 'lodash';
import { LeftSidebarInspector } from './SidebarInspector';
import { LeftSidebarDataSources } from './SidebarDatasources';
import { DarkModeToggle } from '../../_components/DarkModeToggle';
import useRouter from '../../_hooks/use-router';
import { LeftSidebarDebugger } from './SidebarDebugger/SidebarDebugger';
import { LeftSidebarComment } from './SidebarComment';
import LeftSidebarPageSelector from './SidebarPageSelector';
import { ConfirmDialog } from '@/_components';
import config from 'config';
import { LeftSidebarItem } from './SidebarItem';
import Popover from '@/_ui/Popover';
import { usePanelHeight } from '@/_stores/queryPanelStore';
import { useAppVersionStore } from '@/_stores/appVersionStore';
import { useEditorStore } from '@/_stores/editorStore';
import { useDataSources } from '@/_stores/dataSourcesStore';
import { shallow } from 'zustand/shallow';
import useDebugger from './SidebarDebugger/useDebugger';
import { GlobalSettings } from '../Header/GlobalSettings';
import cx from 'classnames';
import { deepClone } from '@/_helpers/utilities/utils.helpers';
export const LeftSidebar = forwardRef((props, ref) => {
const router = useRouter();
const {
appId,
switchDarkMode,
darkMode = false,
dataSourcesChanged,
globalDataSourcesChanged,
dataQueriesChanged,
appDefinition,
setSelectedComponent,
removeComponent,
runQuery,
currentPageId,
addNewPage,
switchPage,
deletePage,
renamePage,
hidePage,
unHidePage,
updateHomePage,
updatePageHandle,
showHideViewerNavigationControls,
updateOnSortingPages,
apps,
clonePage,
setEditorMarginLeft,
globalSettingsChanged,
toggleAppMaintenance,
app,
disableEnablePage,
isMaintenanceOn,
} = props;
const dataSources = useDataSources();
const prevSelectedSidebarItem = localStorage.getItem('selectedSidebarItem');
const queryPanelHeight = usePanelHeight();
const [selectedSidebarItem, setSelectedSidebarItem] = useState(
dataSources?.length === 0 && prevSelectedSidebarItem === 'datasource' ? 'inspect' : prevSelectedSidebarItem
);
const [showLeaveDialog, setShowLeaveDialog] = useState(false);
const [showDataSourceManagerModal, toggleDataSourceManagerModal] = useState(false);
const [popoverContentHeight, setPopoverContentHeight] = useState(queryPanelHeight);
const { isVersionReleased } = useAppVersionStore(
(state) => ({
isVersionReleased: state.isVersionReleased,
}),
shallow
);
const { showComments, appMode } = useEditorStore(
(state) => ({
showComments: state?.showComments,
appMode: state?.appMode,
}),
shallow
);
const [pinned, setPinned] = useState(!!localStorage.getItem('selectedSidebarItem'));
const { errorLogs, clearErrorLogs, unReadErrorCount, allLog } = useDebugger({
currentPageId,
isDebuggerOpen: !!selectedSidebarItem,
});
const sideBarBtnRefs = useRef({});
useEffect(() => {
setPopoverContentHeight(((window.innerHeight - queryPanelHeight - 45) / window.innerHeight) * 100);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [queryPanelHeight]);
useEffect(() => {
if (!selectedSidebarItem) {
setEditorMarginLeft(0);
} else {
setEditorMarginLeft(350);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedSidebarItem]);
useImperativeHandle(ref, () => ({
dataSourceModalToggleStateHandler() {
toggleDataSourceManagerModal(true);
},
}));
const handleSelectedSidebarItem = (item) => {
if (item === selectedSidebarItem && !pinned) {
setSelectedSidebarItem(null);
} else {
setSelectedSidebarItem(item);
pinned && localStorage.setItem('selectedSidebarItem', item);
}
};
const handlePin = (isPin) => {
isPin
? localStorage.setItem('selectedSidebarItem', selectedSidebarItem)
: localStorage.removeItem('selectedSidebarItem');
setPinned(isPin);
};
const handleInteractOutside = (ev) => {
const isBtnClicked = Object.values(sideBarBtnRefs.current).some((btnRef) => {
return btnRef.contains(ev.target);
});
if (!isBtnClicked && !pinned) {
setSelectedSidebarItem(null);
}
};
const setSideBarBtnRefs = (page) => (ref) => {
sideBarBtnRefs.current[page] = ref;
};
const backgroundFxQuery = appDefinition?.globalSettings?.backgroundFxQuery;
const renderPopoverContent = () => {
if (selectedSidebarItem === null) return null;
switch (selectedSidebarItem) {
case 'page':
return (
<LeftSidebarPageSelector
darkMode={darkMode}
selectedSidebarItem={selectedSidebarItem}
appDefinition={appDefinition}
currentPageId={currentPageId}
addNewPage={addNewPage}
switchPage={switchPage}
deletePage={deletePage}
renamePage={renamePage}
hidePage={hidePage}
unHidePage={unHidePage}
disableEnablePage={disableEnablePage}
updateHomePage={updateHomePage}
updatePageHandle={updatePageHandle}
clonePage={clonePage}
pages={
Object.entries(deepClone(appDefinition).pages)
.map(([id, page]) => ({ id, ...page }))
.sort((a, b) => a.index - b.index) || []
}
homePageId={appDefinition.homePageId}
showHideViewerNavigationControls={showHideViewerNavigationControls}
updateOnSortingPages={updateOnSortingPages}
apps={apps}
setPinned={handlePin}
pinned={pinned}
/>
);
case 'inspect':
return (
<LeftSidebarInspector
darkMode={darkMode}
selectedSidebarItem={selectedSidebarItem}
appDefinition={appDefinition}
setSelectedComponent={setSelectedComponent}
removeComponent={removeComponent}
runQuery={runQuery}
popoverContentHeight={popoverContentHeight}
setPinned={handlePin}
pinned={pinned}
/>
);
case 'datasource':
return (
<LeftSidebarDataSources
darkMode={darkMode}
appId={appId}
dataSourcesChanged={dataSourcesChanged}
globalDataSourcesChanged={globalDataSourcesChanged}
dataQueriesChanged={dataQueriesChanged}
toggleDataSourceManagerModal={toggleDataSourceManagerModal}
showDataSourceManagerModal={showDataSourceManagerModal}
onDeleteofAllDataSources={() => {
handleSelectedSidebarItem(null);
handlePin(false);
delete sideBarBtnRefs.current['datasource'];
}}
setPinned={handlePin}
pinned={pinned}
/>
);
case 'debugger':
return (
<LeftSidebarDebugger
darkMode={darkMode}
errors={errorLogs}
clearErrorLogs={clearErrorLogs}
setPinned={handlePin}
pinned={pinned}
allLog={allLog}
/>
);
case 'settings':
return (
<GlobalSettings
globalSettingsChanged={globalSettingsChanged}
globalSettings={appDefinition.globalSettings}
darkMode={darkMode}
toggleAppMaintenance={toggleAppMaintenance}
isMaintenanceOn={isMaintenanceOn}
app={app}
backgroundFxQuery={backgroundFxQuery}
/>
);
}
};
return (
<div className={cx('left-sidebar', { 'dark-theme theme-dark': darkMode })} data-cy="left-sidebar-inspector">
<LeftSidebarItem
selectedSidebarItem={selectedSidebarItem}
onClick={() => handleSelectedSidebarItem('page')}
icon="page"
className={`left-sidebar-item left-sidebar-layout left-sidebar-page-selector`}
tip="Pages"
ref={setSideBarBtnRefs('page')}
/>
<LeftSidebarItem
selectedSidebarItem={selectedSidebarItem}
onClick={() => handleSelectedSidebarItem('inspect')}
icon="inspect"
className={`left-sidebar-item left-sidebar-layout left-sidebar-inspector`}
tip="Inspector"
ref={setSideBarBtnRefs('inspect')}
/>
<LeftSidebarItem
icon="debugger"
selectedSidebarItem={selectedSidebarItem}
// eslint-disable-next-line no-unused-vars
onClick={(e) => handleSelectedSidebarItem('debugger')}
className={`left-sidebar-item left-sidebar-layout`}
badge={true}
count={unReadErrorCount.unread}
tip="Debugger"
ref={setSideBarBtnRefs('debugger')}
/>
<LeftSidebarItem
icon="settings"
selectedSidebarItem={selectedSidebarItem}
// eslint-disable-next-line no-unused-vars
onClick={(e) => handleSelectedSidebarItem('settings')}
className={`left-sidebar-item left-sidebar-layout`}
badge={true}
tip="Settings"
ref={setSideBarBtnRefs('settings')}
/>
{dataSources?.length > 0 && (
<LeftSidebarItem
selectedSidebarItem={selectedSidebarItem}
onClick={() => handleSelectedSidebarItem('datasource')}
icon="datasource"
className={`left-sidebar-item left-sidebar-layout sidebar-datasources`}
tip="Sources"
ref={setSideBarBtnRefs('datasource')}
/>
)}
<Popover
onInteractOutside={handleInteractOutside}
open={pinned || !!selectedSidebarItem}
popoverContentClassName={`p-0 sidebar-h-100-popover ${selectedSidebarItem}`}
side="right"
popoverContent={renderPopoverContent()}
popoverContentHeight={popoverContentHeight}
/>
<ConfirmDialog
show={showLeaveDialog}
message={'The unsaved changes will be lost if you leave the editor, do you want to leave'}
onConfirm={() => router.push('/')}
onCancel={() => setShowLeaveDialog(false)}
darkMode={darkMode}
/>
<div className="left-sidebar-stack-bottom">
<div className="">
{config.COMMENT_FEATURE_ENABLE && (
<div
className={`${isVersionReleased && 'disabled'}`}
style={{ maxHeight: '32px', maxWidth: '32px', marginBottom: '16px' }}
>
<LeftSidebarComment
selectedSidebarItem={showComments ? 'comments' : ''}
currentPageId={currentPageId}
ref={setSideBarBtnRefs('comments')}
/>
</div>
)}
<DarkModeToggle switchDarkMode={switchDarkMode} darkMode={darkMode} tooltipPlacement="right" />
</div>
</div>
</div>
);
});