mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
Merge pull request #13231 from ToolJet/fix/page-bugs-01
Fix: page bugs and design changes
This commit is contained in:
commit
33f77dda7c
45 changed files with 770 additions and 334 deletions
|
|
@ -1 +1 @@
|
||||||
Subproject commit 3b2d439f681f3879da6663f4c9b6d30deffc0380
|
Subproject commit 8ed7be478b266e8b812ce1d3c43f2cb7e2ee3d07
|
||||||
|
|
@ -8,7 +8,13 @@ import './appCanvas.scss';
|
||||||
import useStore from '@/AppBuilder/_stores/store';
|
import useStore from '@/AppBuilder/_stores/store';
|
||||||
import { shallow } from 'zustand/shallow';
|
import { shallow } from 'zustand/shallow';
|
||||||
import { computeViewerBackgroundColor, getCanvasWidth } from './appCanvasUtils';
|
import { computeViewerBackgroundColor, getCanvasWidth } from './appCanvasUtils';
|
||||||
import { NO_OF_GRIDS } from './appCanvasConstants';
|
import {
|
||||||
|
LEFT_SIDEBAR_WIDTH,
|
||||||
|
NO_OF_GRIDS,
|
||||||
|
PAGES_SIDEBAR_WIDTH_COLLAPSED,
|
||||||
|
PAGES_SIDEBAR_WIDTH_EXPANDED,
|
||||||
|
RIGHT_SIDEBAR_WIDTH,
|
||||||
|
} from './appCanvasConstants';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import FreezeVersionInfo from '@/AppBuilder/Header/FreezeVersionInfo';
|
import FreezeVersionInfo from '@/AppBuilder/Header/FreezeVersionInfo';
|
||||||
import { computeCanvasContainerHeight } from '../_helpers/editorHelpers';
|
import { computeCanvasContainerHeight } from '../_helpers/editorHelpers';
|
||||||
|
|
@ -134,7 +140,7 @@ export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode })
|
||||||
width: currentMode === 'edit' ? `calc(100% - 96px)` : '100%',
|
width: currentMode === 'edit' ? `calc(100% - 96px)` : '100%',
|
||||||
alignItems: 'unset',
|
alignItems: 'unset',
|
||||||
justifyContent: 'unset',
|
justifyContent: 'unset',
|
||||||
borderRight: currentMode === 'edit' && isRightSidebarOpen && '299' + 'px solid',
|
borderRight: currentMode === 'edit' && isRightSidebarOpen && `300px solid ${canvasBgColor}`,
|
||||||
padding: currentMode === 'edit' && '8px',
|
padding: currentMode === 'edit' && '8px',
|
||||||
paddingBottom: currentMode === 'edit' && '2px',
|
paddingBottom: currentMode === 'edit' && '2px',
|
||||||
};
|
};
|
||||||
|
|
@ -152,15 +158,34 @@ export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode })
|
||||||
const shouldAdjust = isSidebarOpen || (isRightSidebarOpen && currentMode === 'edit');
|
const shouldAdjust = isSidebarOpen || (isRightSidebarOpen && currentMode === 'edit');
|
||||||
|
|
||||||
if (!shouldAdjust) return '';
|
if (!shouldAdjust) return '';
|
||||||
|
|
||||||
let offset;
|
let offset;
|
||||||
if (isViewerSidebarPinned) {
|
if (isViewerSidebarPinned && !isPagesSidebarHidden) {
|
||||||
offset = position === 'side' ? '352px' : '126px';
|
if (position === 'side' && isSidebarOpen && isRightSidebarOpen && !isPagesSidebarHidden) {
|
||||||
|
offset = `${LEFT_SIDEBAR_WIDTH + RIGHT_SIDEBAR_WIDTH - PAGES_SIDEBAR_WIDTH_EXPANDED}px`;
|
||||||
|
} else if (position === 'side' && isSidebarOpen && !isRightSidebarOpen && !isPagesSidebarHidden) {
|
||||||
|
offset = `${LEFT_SIDEBAR_WIDTH - PAGES_SIDEBAR_WIDTH_EXPANDED}px`;
|
||||||
|
} else if (position === 'side' && isRightSidebarOpen && !isSidebarOpen && !isPagesSidebarHidden) {
|
||||||
|
offset = `${RIGHT_SIDEBAR_WIDTH - PAGES_SIDEBAR_WIDTH_EXPANDED}px`;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
offset = position === 'side' ? '171px' : '126px';
|
if (position === 'side' && isSidebarOpen && isRightSidebarOpen && !isPagesSidebarHidden) {
|
||||||
|
offset = `${LEFT_SIDEBAR_WIDTH + RIGHT_SIDEBAR_WIDTH - PAGES_SIDEBAR_WIDTH_COLLAPSED}px`;
|
||||||
|
} else if (position === 'side' && isSidebarOpen && !isRightSidebarOpen && !isPagesSidebarHidden) {
|
||||||
|
offset = `${LEFT_SIDEBAR_WIDTH - PAGES_SIDEBAR_WIDTH_COLLAPSED}px`;
|
||||||
|
} else if (position === 'side' && isRightSidebarOpen && !isSidebarOpen && !isPagesSidebarHidden) {
|
||||||
|
offset = `${RIGHT_SIDEBAR_WIDTH - PAGES_SIDEBAR_WIDTH_COLLAPSED}px`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return `calc(100vw - ${offset})`;
|
if ((position === 'top' || isPagesSidebarHidden) && isSidebarOpen && isRightSidebarOpen) {
|
||||||
|
offset = `${LEFT_SIDEBAR_WIDTH + RIGHT_SIDEBAR_WIDTH}px`;
|
||||||
|
} else if ((position === 'top' || isPagesSidebarHidden) && isSidebarOpen && !isRightSidebarOpen) {
|
||||||
|
offset = `${LEFT_SIDEBAR_WIDTH}px`;
|
||||||
|
} else if ((position === 'top' || isPagesSidebarHidden) && isRightSidebarOpen && !isSidebarOpen) {
|
||||||
|
offset = `${RIGHT_SIDEBAR_WIDTH}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `calc(100% + ${offset})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -177,7 +202,7 @@ export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode })
|
||||||
'canvas-container d-flex page-container',
|
'canvas-container d-flex page-container',
|
||||||
{ 'dark-theme theme-dark': isAppDarkMode, close: !isViewerSidebarPinned },
|
{ 'dark-theme theme-dark': isAppDarkMode, close: !isViewerSidebarPinned },
|
||||||
{ 'overflow-x-auto': currentMode === 'edit' },
|
{ 'overflow-x-auto': currentMode === 'edit' },
|
||||||
{ 'position-top': position === 'top' },
|
{ 'position-top': position === 'top' || isPagesSidebarHidden },
|
||||||
{ 'overflow-x-hidden': moduleId !== 'canvas' } // Disbling horizontal scroll for modules in view mode
|
{ 'overflow-x-hidden': moduleId !== 'canvas' } // Disbling horizontal scroll for modules in view mode
|
||||||
)}
|
)}
|
||||||
style={canvasContainerStyles}
|
style={canvasContainerStyles}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
.empty-box-cont{
|
.empty-box-cont{
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
margin: unset !important;
|
||||||
|
|
||||||
.dotted-cont{
|
.dotted-cont{
|
||||||
border: 1px dashed var(--indigo8);
|
border: 1px dashed var(--indigo8);
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,13 @@ export const DEFAULT_CANVAS_WIDTH = 1292;
|
||||||
|
|
||||||
export const APP_HEADER_HEIGHT = 47;
|
export const APP_HEADER_HEIGHT = 47;
|
||||||
|
|
||||||
export const LEFT_SIDEBAR_WIDTH = 348; // exclusive of border
|
export const LEFT_SIDEBAR_WIDTH = 350;
|
||||||
|
|
||||||
export const RIGHT_SIDEBAR_WIDTH = 299;
|
export const RIGHT_SIDEBAR_WIDTH = 300;
|
||||||
|
|
||||||
|
export const PAGES_SIDEBAR_WIDTH_EXPANDED = 226;
|
||||||
|
|
||||||
|
export const PAGES_SIDEBAR_WIDTH_COLLAPSED = 44;
|
||||||
|
|
||||||
export const SUBCONTAINER_WIDGETS = ['Container', 'Tabs', 'Listview', 'Kanban', 'Form'];
|
export const SUBCONTAINER_WIDGETS = ['Container', 'Tabs', 'Listview', 'Kanban', 'Form'];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ const useSidebarMargin = (canvasContainerRef) => {
|
||||||
const { moduleId } = useModuleContext();
|
const { moduleId } = useModuleContext();
|
||||||
const [editorMarginLeft, setEditorMarginLeft] = useState(0);
|
const [editorMarginLeft, setEditorMarginLeft] = useState(0);
|
||||||
const isSidebarOpen = useStore((state) => state.isSidebarOpen, shallow);
|
const isSidebarOpen = useStore((state) => state.isSidebarOpen, shallow);
|
||||||
|
const isRightSidebarOpen = useStore((state) => state.isRightSidebarOpen, shallow);
|
||||||
const mode = useStore((state) => state.modeStore.modules[moduleId].currentMode, shallow);
|
const mode = useStore((state) => state.modeStore.modules[moduleId].currentMode, shallow);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -17,10 +18,10 @@ const useSidebarMargin = (canvasContainerRef) => {
|
||||||
}, [isSidebarOpen, mode]);
|
}, [isSidebarOpen, mode]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isEmpty(canvasContainerRef?.current)) {
|
if (!isEmpty(canvasContainerRef?.current) && isSidebarOpen && canvasContainerRef.current.scrollLeft === 0) {
|
||||||
canvasContainerRef.current.scrollLeft += editorMarginLeft;
|
canvasContainerRef.current.scrollLeft += editorMarginLeft;
|
||||||
}
|
}
|
||||||
}, [editorMarginLeft, canvasContainerRef]);
|
}, [editorMarginLeft, canvasContainerRef, isSidebarOpen]);
|
||||||
|
|
||||||
return editorMarginLeft;
|
return editorMarginLeft;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ const GlobalSettings = ({ darkMode }) => {
|
||||||
</div>
|
</div>
|
||||||
<div style={{ padding: '12px 16px' }} className={cx({ disabled: shouldFreeze })}>
|
<div style={{ padding: '12px 16px' }} className={cx({ disabled: shouldFreeze })}>
|
||||||
<MaintenanceMode darkMode={darkMode} />
|
<MaintenanceMode darkMode={darkMode} />
|
||||||
<HideHeaderToggle darkMode={darkMode} />
|
|
||||||
</div>
|
</div>
|
||||||
<div className={cx({ 'dark-theme': darkMode })}>
|
<div className={cx({ 'dark-theme': darkMode })}>
|
||||||
<span className="canvas-styles-header">Canvas Styles</span>
|
<span className="canvas-styles-header">Canvas Styles</span>
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,7 @@ export const QueryPanel = ({ darkMode }) => {
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -9,17 +9,21 @@ import SolidIcon from '@/_ui/Icon/SolidIcons';
|
||||||
export const ComponentConfigurationTab = ({ darkMode, isModuleEditor }) => {
|
export const ComponentConfigurationTab = ({ darkMode, isModuleEditor }) => {
|
||||||
const selectedComponentId = useStore((state) => state.selectedComponents?.[0], shallow);
|
const selectedComponentId = useStore((state) => state.selectedComponents?.[0], shallow);
|
||||||
const activeTab = useStore((state) => state.activeRightSideBarTab, shallow);
|
const activeTab = useStore((state) => state.activeRightSideBarTab, shallow);
|
||||||
const toggleRightSidebarPin = useStore((state) => state.toggleRightSidebarPin);
|
const setRightSidebarOpen = useStore((state) => state.setRightSidebarOpen);
|
||||||
const isRightSidebarPinned = useStore((state) => state.isRightSidebarPinned);
|
|
||||||
const setActiveRightSideBarTab = useStore((state) => state.setActiveRightSideBarTab);
|
const setActiveRightSideBarTab = useStore((state) => state.setActiveRightSideBarTab);
|
||||||
|
|
||||||
|
const handleToggle = () => {
|
||||||
|
setActiveRightSideBarTab(null);
|
||||||
|
setRightSidebarOpen(false);
|
||||||
|
};
|
||||||
if (!selectedComponentId && activeTab !== RIGHT_SIDE_BAR_TAB.PAGES) {
|
if (!selectedComponentId && activeTab !== RIGHT_SIDE_BAR_TAB.PAGES) {
|
||||||
// return setActiveRightSideBarTab(RIGHT_SIDE_BAR_TAB.COMPONENTS);
|
// return setActiveRightSideBarTab(RIGHT_SIDE_BAR_TAB.COMPONENTS);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="empty-configuration-header">
|
<div className="empty-configuration-header">
|
||||||
<div className="header">Component properties</div>
|
<div className="header">Component properties</div>
|
||||||
<div className="icon-btn cursor-pointer" onClick={() => toggleRightSidebarPin()}>
|
<div className="icon-btn cursor-pointer flex-shrink-0 p-2 h-4 w-4" onClick={handleToggle}>
|
||||||
<SolidIcon fill="var(--icon-strong)" name={isRightSidebarPinned ? 'unpin' : 'pin'} width="16" />
|
<SolidIcon fill="var(--icon-strong)" name={'remove03'} width="16" viewBox="0 0 16 16" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex align-items-center justify-content-center no-component-selected">
|
<div className="d-flex align-items-center justify-content-center no-component-selected">
|
||||||
|
|
@ -39,6 +43,7 @@ export const ComponentConfigurationTab = ({ darkMode, isModuleEditor }) => {
|
||||||
selectedComponentId={selectedComponentId}
|
selectedComponentId={selectedComponentId}
|
||||||
pages={[]}
|
pages={[]}
|
||||||
isModuleEditor={isModuleEditor}
|
isModuleEditor={isModuleEditor}
|
||||||
|
handleRightSidebarToggle={handleToggle}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,10 @@ export const ComponentsManagerTab = ({ darkMode, isModuleEditor }) => {
|
||||||
}
|
}
|
||||||
}, [hasModuleAccess, activeTab]);
|
}, [hasModuleAccess, activeTab]);
|
||||||
|
|
||||||
const toggleRightSidebarPin = useStore((state) => state.toggleRightSidebarPin);
|
const setRightSidebarOpen = useStore((state) => state.setRightSidebarOpen);
|
||||||
const isRightSidebarPinned = useStore((state) => state.isRightSidebarPinned);
|
const activeRightSideBarTab = useStore((state) => state.activeRightSideBarTab);
|
||||||
|
const setActiveRightSideBarTab = useStore((state) => state.setActiveRightSideBarTab);
|
||||||
|
const isRightSidebarOpen = useStore((state) => state.isRightSidebarOpen);
|
||||||
|
|
||||||
const handleSearchQueryChange = useCallback(
|
const handleSearchQueryChange = useCallback(
|
||||||
debounce((value) => {
|
debounce((value) => {
|
||||||
|
|
@ -88,6 +90,11 @@ export const ComponentsManagerTab = ({ darkMode, isModuleEditor }) => {
|
||||||
[activeTab]
|
[activeTab]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleToggle = () => {
|
||||||
|
setActiveRightSideBarTab(null);
|
||||||
|
setRightSidebarOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
const filterComponents = useCallback((value) => {
|
const filterComponents = useCallback((value) => {
|
||||||
if (value !== '') {
|
if (value !== '') {
|
||||||
const fuse = new Fuse(componentList, {
|
const fuse = new Fuse(componentList, {
|
||||||
|
|
@ -223,11 +230,16 @@ export const ComponentsManagerTab = ({ darkMode, isModuleEditor }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`components-container ${shouldFreeze ? 'disabled' : ''}`}>
|
<div className={`components-container ${shouldFreeze ? 'disabled' : ''}`}>
|
||||||
{isModuleEditor ? (
|
<div className="d-flex align-items-center">
|
||||||
<p className="widgets-manager-header">Components</p>
|
{isModuleEditor ? (
|
||||||
) : (
|
<p className="widgets-manager-header">Components</p>
|
||||||
<ComponentModuleTab onChangeTab={handleChangeTab} hasModuleAccess={hasModuleAccess} />
|
) : (
|
||||||
)}
|
<ComponentModuleTab onChangeTab={handleChangeTab} hasModuleAccess={hasModuleAccess} />
|
||||||
|
)}
|
||||||
|
<div className="icon-btn cursor-pointer flex-shrink-0 me-3 p-2 h-4 w-4" onClick={handleToggle}>
|
||||||
|
<SolidIcon fill="var(--icon-strong)" name={'remove03'} width="16" viewBox="0 0 16 16" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="input-icon tj-app-input">
|
<div className="input-icon tj-app-input">
|
||||||
<SearchBox
|
<SearchBox
|
||||||
dataCy={`widget-search-box`}
|
dataCy={`widget-search-box`}
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,13 @@ const NEW_REVAMPED_COMPONENTS = [
|
||||||
'FilePicker',
|
'FilePicker',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const Inspector = ({ componentDefinitionChanged, darkMode, pages, selectedComponentId }) => {
|
export const Inspector = ({
|
||||||
|
componentDefinitionChanged,
|
||||||
|
darkMode,
|
||||||
|
pages,
|
||||||
|
selectedComponentId,
|
||||||
|
handleRightSidebarToggle,
|
||||||
|
}) => {
|
||||||
const allComponents = useStore((state) => state.getCurrentPageComponents());
|
const allComponents = useStore((state) => state.getCurrentPageComponents());
|
||||||
const setComponentProperty = useStore((state) => state.setComponentProperty, shallow);
|
const setComponentProperty = useStore((state) => state.setComponentProperty, shallow);
|
||||||
const setComponentName = useStore((state) => state.setComponentName, shallow);
|
const setComponentName = useStore((state) => state.setComponentName, shallow);
|
||||||
|
|
@ -528,19 +534,19 @@ export const Inspector = ({ componentDefinitionChanged, darkMode, pages, selecte
|
||||||
<div className={`inspector ${isModuleContainer && 'module-editor-inspector'}`}>
|
<div className={`inspector ${isModuleContainer && 'module-editor-inspector'}`}>
|
||||||
<div>
|
<div>
|
||||||
<div className={`row inspector-component-title-input-holder ${shouldFreeze && 'disabled'}`}>
|
<div className={`row inspector-component-title-input-holder ${shouldFreeze && 'disabled'}`}>
|
||||||
<div className="col-1" onClick={() => clearSelectedComponents()}>
|
<div className="p-0 width-unset flex-shrink-0" onClick={() => clearSelectedComponents()}>
|
||||||
<span
|
<span
|
||||||
data-cy={`inspector-close-icon`}
|
data-cy={`inspector-close-icon`}
|
||||||
className="cursor-pointer d-flex align-items-center "
|
className="cursor-pointer d-flex align-items-center "
|
||||||
style={{ height: '28px', width: '28px' }}
|
style={{ height: '28px' }}
|
||||||
>
|
>
|
||||||
<ArrowLeft fill={'var(--slate12)'} width={'14'} />
|
<ArrowLeft fill={'var(--slate12)'} width={'14'} />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={`col-9 p-0 ${shouldFreeze && 'disabled'}`}>{renderAppNameInput()}</div>
|
<div className={`flex-shrink p-0 width-unset ${shouldFreeze && 'disabled'}`}>{renderAppNameInput()}</div>
|
||||||
{!isModuleContainer && (
|
{!isModuleContainer && (
|
||||||
<>
|
<>
|
||||||
<div className="col-2" data-cy={'component-inspector-options'}>
|
<div className="width-unset" data-cy={'component-inspector-options'}>
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
trigger={'click'}
|
trigger={'click'}
|
||||||
placement={'bottom-end'}
|
placement={'bottom-end'}
|
||||||
|
|
@ -613,6 +619,9 @@ export const Inspector = ({ componentDefinitionChanged, darkMode, pages, selecte
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
<div className="icon-btn cursor-pointer flex-shrink-0 p-2 h-4 w-4" onClick={handleRightSidebarToggle}>
|
||||||
|
<SolidIcon fill="var(--icon-strong)" name={'remove03'} width="16" viewBox="0 0 16 16" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={`${shouldFreeze && 'disabled'}`}>{renderTabs()}</div>
|
<div className={`${shouldFreeze && 'disabled'}`}>{renderTabs()}</div>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ export function AddNewPageMenu({ darkMode, isLicensed }) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page-type-buttons-container">
|
<div className={`page-type-buttons-container ${darkMode && 'dark-mode'}`}>
|
||||||
<Button
|
<Button
|
||||||
ref={newPageBtnRef}
|
ref={newPageBtnRef}
|
||||||
key="new-page-btn"
|
key="new-page-btn"
|
||||||
|
|
@ -54,7 +54,7 @@ export function AddNewPageMenu({ darkMode, isLicensed }) {
|
||||||
rootClose
|
rootClose
|
||||||
onHide={() => setShowMenuPopover(false)}
|
onHide={() => setShowMenuPopover(false)}
|
||||||
>
|
>
|
||||||
<Popover id="add-new-page-popover">
|
<Popover className={darkMode && 'darkMode'} id="add-new-page-popover">
|
||||||
<div className="menu-options mb-0">
|
<div className="menu-options mb-0">
|
||||||
<PageOptions
|
<PageOptions
|
||||||
type="url"
|
type="url"
|
||||||
|
|
@ -70,7 +70,7 @@ export function AddNewPageMenu({ darkMode, isLicensed }) {
|
||||||
darkMode={darkMode}
|
darkMode={darkMode}
|
||||||
onClick={() => handleOpenPopup('app')}
|
onClick={() => handleOpenPopup('app')}
|
||||||
/>
|
/>
|
||||||
<div className={`d-flex ${!isLicensed && 'disabled licensed-page-option'}`}>
|
<div className={`${!isLicensed && 'd-flex disabled licensed-page-option'}`}>
|
||||||
<PageOptions
|
<PageOptions
|
||||||
type="group"
|
type="group"
|
||||||
text="Add nav group"
|
text="Add nav group"
|
||||||
|
|
@ -79,7 +79,7 @@ export function AddNewPageMenu({ darkMode, isLicensed }) {
|
||||||
onClick={() => handleOpenPopup('group')}
|
onClick={() => handleOpenPopup('group')}
|
||||||
/>
|
/>
|
||||||
<LicenseTooltip
|
<LicenseTooltip
|
||||||
message={"App header can't be hidden on free plans"}
|
message={"Nav group can't be created on free plans"}
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
show={!isLicensed}
|
show={!isLicensed}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -338,22 +338,10 @@ export const AddEditPagePopup = forwardRef(({ darkMode, ...props }, ref) => {
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={isHomePage}
|
checked={isHomePage}
|
||||||
onChange={() => markAsHomePage(page?.id)}
|
onChange={() => markAsHomePage(page?.id)}
|
||||||
disabled={isHomePage}
|
disabled={isHomePage || resolveReferences(page?.hidden?.value) || page?.disabled}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{/* <div className=" d-flex justify-content-between align-items-center pb-2">
|
|
||||||
<label className="form-label font-weight-400 mb-0">Hide this page on navigation</label>
|
|
||||||
<label className={`form-switch`}>
|
|
||||||
<input
|
|
||||||
className="form-check-input"
|
|
||||||
type="checkbox"
|
|
||||||
checked={page?.hidden}
|
|
||||||
onChange={(e) => updatePageVisibility(page?.id, !page?.hidden)}
|
|
||||||
disabled={isHomePage}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div> */}
|
|
||||||
<HidePageOnNavigation
|
<HidePageOnNavigation
|
||||||
hidden={page?.hidden}
|
hidden={page?.hidden}
|
||||||
page={page}
|
page={page}
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ export default function IconSelector({ iconName, iconColor, pageId, iconStyles,
|
||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line import/namespace
|
// eslint-disable-next-line import/namespace
|
||||||
const IconElement = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
|
const IconElement = Icons?.[iconName] ?? Icons?.['IconFile'];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/* eslint-disable import/namespace */
|
/* eslint-disable import/namespace */
|
||||||
import React, { useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import * as Icons from '@tabler/icons-react';
|
import * as Icons from '@tabler/icons-react';
|
||||||
// eslint-disable-next-line import/no-unresolved
|
// eslint-disable-next-line import/no-unresolved
|
||||||
|
|
@ -26,12 +26,13 @@ export const RenderPage = ({
|
||||||
isSidebarPinned,
|
isSidebarPinned,
|
||||||
callback,
|
callback,
|
||||||
position,
|
position,
|
||||||
|
onPageClick,
|
||||||
}) => {
|
}) => {
|
||||||
const currentMode = useStore((state) => state.currentMode);
|
const currentMode = useStore((state) => state.currentMode);
|
||||||
const isHomePage = page.id === homePageId;
|
const isHomePage = page.id === homePageId;
|
||||||
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
||||||
const IconElement = (props) => {
|
const IconElement = (props) => {
|
||||||
const Icon = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
|
const Icon = Icons?.[iconName] ?? Icons?.['IconFile'];
|
||||||
|
|
||||||
if (!isSidebarPinned || labelStyle?.label?.hidden) {
|
if (!isSidebarPinned || labelStyle?.label?.hidden) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -59,7 +60,7 @@ export const RenderPage = ({
|
||||||
key={page.handle}
|
key={page.handle}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
switchPageWrapper(page);
|
switchPageWrapper(page);
|
||||||
callback && position !== 'side' && callback();
|
position !== 'side' && onPageClick();
|
||||||
}}
|
}}
|
||||||
selectedItem={page?.id === currentPageId}
|
selectedItem={page?.id === currentPageId}
|
||||||
CustomIcon={!labelStyle?.icon?.hidden && IconElement}
|
CustomIcon={!labelStyle?.icon?.hidden && IconElement}
|
||||||
|
|
@ -67,14 +68,15 @@ export const RenderPage = ({
|
||||||
darkMode={darkMode}
|
darkMode={darkMode}
|
||||||
>
|
>
|
||||||
{!labelStyle?.label?.hidden && (
|
{!labelStyle?.label?.hidden && (
|
||||||
<span
|
<div
|
||||||
|
style={{ position: 'relative', overflow: 'hidden' }}
|
||||||
// className={isSelected && 'tj-list-item-selected'}
|
// className={isSelected && 'tj-list-item-selected'}
|
||||||
data-cy={`pages-name-${String(page?.name).toLowerCase()}`}
|
data-cy={`pages-name-${String(page?.name).toLowerCase()}`}
|
||||||
>
|
>
|
||||||
<OverflowTooltip style={{ width: '110px', position: 'relative' }} childrenClassName={'page-name'}>
|
<OverflowTooltip style={{ width: '110px', position: 'relative' }} childrenClassName={'page-name'}>
|
||||||
{page.name}
|
{page.name}
|
||||||
</OverflowTooltip>
|
</OverflowTooltip>
|
||||||
</span>
|
</div>
|
||||||
)}
|
)}
|
||||||
</FolderList>
|
</FolderList>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -94,12 +96,15 @@ const RenderPageGroup = ({
|
||||||
linkRefs,
|
linkRefs,
|
||||||
isSidebarPinned,
|
isSidebarPinned,
|
||||||
position,
|
position,
|
||||||
|
isExpanded,
|
||||||
|
onToggle,
|
||||||
|
onPageClick,
|
||||||
}) => {
|
}) => {
|
||||||
const currentMode = useStore((state) => state.currentMode);
|
const currentMode = useStore((state) => state.currentMode);
|
||||||
|
|
||||||
const [hovered, setHovered] = useState(false);
|
const [hovered, setHovered] = useState(false);
|
||||||
const [isExpanded, setIsExpanded] = useState(false);
|
|
||||||
const contentRef = useRef(null);
|
const contentRef = useRef(null);
|
||||||
|
const groupItemRootRef = useRef(null);
|
||||||
|
|
||||||
const IconElement = (props) => {
|
const IconElement = (props) => {
|
||||||
const Icon = Icons?.[pageGroup.icon] ?? Icons?.['IconHome2'];
|
const Icon = Icons?.[pageGroup.icon] ?? Icons?.['IconHome2'];
|
||||||
|
|
@ -116,9 +121,25 @@ const RenderPageGroup = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleToggle = () => {
|
const handleToggle = () => {
|
||||||
setIsExpanded(!isExpanded);
|
onToggle(pageGroup.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleClickOutside = (event) => {
|
||||||
|
if (isExpanded && groupItemRootRef.current && !groupItemRootRef.current.contains(event.target)) {
|
||||||
|
onToggle(pageGroup.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isExpanded) {
|
||||||
|
document.addEventListener('mousedown', handleClickOutside);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('mousedown', handleClickOutside);
|
||||||
|
};
|
||||||
|
}, [isExpanded, onToggle, pageGroup.id]);
|
||||||
|
|
||||||
if (labelStyle?.label?.hidden) {
|
if (labelStyle?.label?.hidden) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -133,6 +154,8 @@ const RenderPageGroup = ({
|
||||||
darkMode={darkMode}
|
darkMode={darkMode}
|
||||||
homePageId={homePageId}
|
homePageId={homePageId}
|
||||||
position={position}
|
position={position}
|
||||||
|
callback={handleToggle}
|
||||||
|
onPageClick={onPageClick}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
|
|
@ -145,7 +168,12 @@ const RenderPageGroup = ({
|
||||||
<div
|
<div
|
||||||
key={pageGroup.name}
|
key={pageGroup.name}
|
||||||
data-id={pageGroup.id}
|
data-id={pageGroup.id}
|
||||||
ref={(el) => linkRefs?.current && (linkRefs.current[pageGroup.id] = el)}
|
ref={(el) => {
|
||||||
|
if (linkRefs?.current) {
|
||||||
|
linkRefs.current[pageGroup.id] = el;
|
||||||
|
}
|
||||||
|
groupItemRootRef.current = el;
|
||||||
|
}}
|
||||||
className={`accordion-item ${darkMode ? 'dark-mode' : ''}`}
|
className={`accordion-item ${darkMode ? 'dark-mode' : ''}`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
@ -153,40 +181,31 @@ const RenderPageGroup = ({
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
}}
|
}}
|
||||||
|
onClick={isSidebarPinned && handleToggle}
|
||||||
>
|
>
|
||||||
<FolderList
|
<FolderList
|
||||||
key={pageGroup.id}
|
key={pageGroup.id}
|
||||||
onClick={isSidebarPinned && handleToggle}
|
|
||||||
CustomIcon={!labelStyle?.icon?.hidden && IconElement}
|
CustomIcon={!labelStyle?.icon?.hidden && IconElement}
|
||||||
customStyles={computeStyles}
|
customStyles={computeStyles}
|
||||||
darkMode={darkMode}
|
darkMode={darkMode}
|
||||||
hovered={hovered}
|
hovered={hovered}
|
||||||
>
|
>
|
||||||
{!labelStyle?.label?.hidden && (
|
{!labelStyle?.label?.hidden && (
|
||||||
<span data-cy={`pages-name-${String(pageGroup?.name).toLowerCase()}`}>
|
<div
|
||||||
<OverflowTooltip style={{ width: '110px' }} childrenClassName={'page-name'}>
|
style={{ position: 'relative', overflow: 'hidden' }}
|
||||||
{pageGroup.name}
|
data-cy={`pages-name-${String(pageGroup?.name).toLowerCase()}`}
|
||||||
</OverflowTooltip>
|
>
|
||||||
</span>
|
<OverflowTooltip childrenClassName={'page-name'}>{pageGroup.name}</OverflowTooltip>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</FolderList>
|
</FolderList>
|
||||||
<div style={{ marginRight: '12px' }}>
|
<div className="icon-btn cursor-pointer flex-shrink-0">
|
||||||
<svg
|
<SolidIcon
|
||||||
onMouseEnter={() => setHovered(true)}
|
fill="var(--icon-default)"
|
||||||
onMouseLeave={() => setHovered(false)}
|
name={isExpanded ? 'caretup' : 'caretdown'}
|
||||||
onClick={handleToggle}
|
width="16"
|
||||||
className={`page-group-collapse ${isExpanded ? 'expanded' : 'collapsed'}`}
|
viewBox="0 0 16 16"
|
||||||
width={17}
|
/>
|
||||||
height={16}
|
|
||||||
viewBox="0 0 17 16"
|
|
||||||
fill="black"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M11.1257 4L5.27446 4C4.50266 4 4.02179 4.83721 4.41068 5.50387L7.33631 10.5192C7.72218 11.1807 8.67798 11.1807 9.06386 10.5192L11.9895 5.50387C12.3784 4.83721 11.8975 4 11.1257 4Z"
|
|
||||||
fill="#ACB2B9"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -205,6 +224,7 @@ const RenderPageGroup = ({
|
||||||
linkRefs={linkRefs}
|
linkRefs={linkRefs}
|
||||||
callback={handleToggle}
|
callback={handleToggle}
|
||||||
position={position}
|
position={position}
|
||||||
|
onPageClick={onPageClick}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -228,6 +248,7 @@ export const RenderPageAndPageGroup = ({
|
||||||
isSidebarPinned,
|
isSidebarPinned,
|
||||||
}) => {
|
}) => {
|
||||||
const { moduleId } = useModuleContext();
|
const { moduleId } = useModuleContext();
|
||||||
|
const [expandedPageGroupId, setExpandedPageGroupId] = useState(null);
|
||||||
// Don't render empty folders if displaying only icons
|
// Don't render empty folders if displaying only icons
|
||||||
const visibleTree = buildTree(position === 'top' ? visibleLinks : pages, !!labelStyle?.label?.hidden);
|
const visibleTree = buildTree(position === 'top' ? visibleLinks : pages, !!labelStyle?.label?.hidden);
|
||||||
const overflowTree = buildTree(overflowLinks, !!labelStyle?.label?.hidden);
|
const overflowTree = buildTree(overflowLinks, !!labelStyle?.label?.hidden);
|
||||||
|
|
@ -241,6 +262,17 @@ export const RenderPageAndPageGroup = ({
|
||||||
const currentPage = pages.find((page) => page.id === currentPageId);
|
const currentPage = pages.find((page) => page.id === currentPageId);
|
||||||
const homePageId = useStore((state) => state.appStore.modules[moduleId].app.homePageId);
|
const homePageId = useStore((state) => state.appStore.modules[moduleId].app.homePageId);
|
||||||
const [showPopover, setShowPopover] = useState(false);
|
const [showPopover, setShowPopover] = useState(false);
|
||||||
|
|
||||||
|
const handleAccordionToggle = (groupId) => {
|
||||||
|
setExpandedPageGroupId((prevId) => (prevId === groupId ? null : groupId));
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeAllAccordions = () => {
|
||||||
|
if (showPopover) {
|
||||||
|
setShowPopover(false);
|
||||||
|
}
|
||||||
|
setExpandedPageGroupId(null);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className={cx('page-handler-wrapper viewer', { 'dark-theme': darkMode })}>
|
<div className={cx('page-handler-wrapper viewer', { 'dark-theme': darkMode })}>
|
||||||
{/* <Accordion alwaysOpen defaultActiveKey={tree.map((page) => page.id)}> */}
|
{/* <Accordion alwaysOpen defaultActiveKey={tree.map((page) => page.id)}> */}
|
||||||
|
|
@ -273,6 +305,9 @@ export const RenderPageAndPageGroup = ({
|
||||||
linkRefs={linkRefs}
|
linkRefs={linkRefs}
|
||||||
isSidebarPinned={isSidebarPinned}
|
isSidebarPinned={isSidebarPinned}
|
||||||
position={position}
|
position={position}
|
||||||
|
isExpanded={expandedPageGroupId === page.id}
|
||||||
|
onToggle={handleAccordionToggle}
|
||||||
|
onPageClick={closeAllAccordions}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
@ -290,6 +325,7 @@ export const RenderPageAndPageGroup = ({
|
||||||
linkRefs={linkRefs}
|
linkRefs={linkRefs}
|
||||||
isSidebarPinned={isSidebarPinned}
|
isSidebarPinned={isSidebarPinned}
|
||||||
position={position}
|
position={position}
|
||||||
|
onPageClick={closeAllAccordions}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -299,10 +335,11 @@ export const RenderPageAndPageGroup = ({
|
||||||
<button
|
<button
|
||||||
ref={moreBtnRef}
|
ref={moreBtnRef}
|
||||||
onClick={() => setShowPopover(!showPopover)}
|
onClick={() => setShowPopover(!showPopover)}
|
||||||
className="tj-list-item page-name"
|
className={`tj-list-item page-name more-btn-pages ${showPopover && 'tj-list-item-selected'}`}
|
||||||
style={{ cursor: 'pointer', fontSize: '14px', marginLeft: '0px' }}
|
style={{ cursor: 'pointer', fontSize: '14px', marginLeft: '0px' }}
|
||||||
>
|
>
|
||||||
<SolidIcon fill={'var(--icon-weak)'} viewBox="0 3 21 18" width="16px" name="morevertical" />
|
<SolidIcon fill={'var(--icon-weak)'} viewBox="0 3 21 18" width="16px" name="morevertical" />
|
||||||
|
|
||||||
<div style={{ marginLeft: '6px' }}>More</div>
|
<div style={{ marginLeft: '6px' }}>More</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
@ -344,6 +381,9 @@ export const RenderPageAndPageGroup = ({
|
||||||
darkMode={darkMode}
|
darkMode={darkMode}
|
||||||
linkRefs={linkRefs}
|
linkRefs={linkRefs}
|
||||||
isSidebarPinned={isSidebarPinned}
|
isSidebarPinned={isSidebarPinned}
|
||||||
|
isExpanded={expandedPageGroupId === page.id}
|
||||||
|
onToggle={handleAccordionToggle}
|
||||||
|
onPageClick={closeAllAccordions}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
@ -360,6 +400,7 @@ export const RenderPageAndPageGroup = ({
|
||||||
homePageId={homePageId}
|
homePageId={homePageId}
|
||||||
linkRefs={linkRefs}
|
linkRefs={linkRefs}
|
||||||
isSidebarPinned={isSidebarPinned}
|
isSidebarPinned={isSidebarPinned}
|
||||||
|
onPageClick={closeAllAccordions}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ export const PageGroupItem = memo(({ page, index, collapsed, onCollapse, highlig
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`page-menu-item page-group-item ${highlight ? 'highlight' : ''} ${darkMode ? 'dark-theme' : ''} ${
|
className={`page-menu-item page-group-item ${highlight ? 'highlight' : ''} ${darkMode ? 'dark-theme' : ''} ${
|
||||||
showPageOptions && isEditing ? 'is-selected' : ''
|
(showPageOptions || showEditPopover) && isEditing ? 'is-selected' : ''
|
||||||
}`}
|
}`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleOpenPopup('group', page);
|
handleOpenPopup('group', page);
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ export const PageMenuItem = withRouter(
|
||||||
const icon = (props) => {
|
const icon = (props) => {
|
||||||
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
||||||
// eslint-disable-next-line import/namespace
|
// eslint-disable-next-line import/namespace
|
||||||
const Icon = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
|
const Icon = Icons?.[iconName] ?? Icons?.['IconFile'];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Icon {...props} style={{ width: '16px', height: '16px', color: 'var(--icons-default)', marginRight: '6px' }} />
|
<Icon {...props} style={{ width: '16px', height: '16px', color: 'var(--icons-default)', marginRight: '6px' }} />
|
||||||
|
|
@ -269,7 +269,6 @@ export const PageMenuItem = withRouter(
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onMouseEnter={() => setIsHovered(true)}
|
onMouseEnter={() => setIsHovered(true)}
|
||||||
|
|
@ -281,7 +280,7 @@ export const PageMenuItem = withRouter(
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={`page-menu-item ${darkMode && 'dark-theme'} ${
|
className={`page-menu-item ${darkMode && 'dark-theme'} ${
|
||||||
showPageOptions && isEditingPage ? 'is-selected' : ''
|
showPageOptions || showEditingPopover || isEditingPage ? 'is-selected' : ''
|
||||||
}`}
|
}`}
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
|
@ -308,14 +307,14 @@ export const PageMenuItem = withRouter(
|
||||||
<>
|
<>
|
||||||
{' '}
|
{' '}
|
||||||
<div ref={optionBtnRef} className="left" data-cy={`pages-name-${page.name.toLowerCase()}`}>
|
<div ref={optionBtnRef} className="left" data-cy={`pages-name-${page.name.toLowerCase()}`}>
|
||||||
{icon()}
|
<div className="main-page-icon-wrapper">{icon()}</div>
|
||||||
<OverflowTooltip childrenClassName="page-name" style={{ ...computedStyles?.text, maxWidth: '159px' }}>
|
<OverflowTooltip childrenClassName="page-name" style={{ ...computedStyles?.text }}>
|
||||||
{page.name}
|
{page.name}
|
||||||
</OverflowTooltip>
|
</OverflowTooltip>
|
||||||
<span className="meta-text" style={{ marginLeft: '6px' }}>
|
|
||||||
{PAGE_TYPES[page?.type]}
|
|
||||||
</span>
|
|
||||||
<span className="color-slate09 meta-text d-flex align-items-center justify-content-center">
|
<span className="color-slate09 meta-text d-flex align-items-center justify-content-center">
|
||||||
|
{PAGE_TYPES[page?.type] && ( // If 'page' object has a 'type' property like 'URL'
|
||||||
|
<span className="page-type-text">{PAGE_TYPES[page?.type]}</span>
|
||||||
|
)}
|
||||||
{isHomePage && (
|
{isHomePage && (
|
||||||
<ToolTip message="Home page" placement="bottom">
|
<ToolTip message="Home page" placement="bottom">
|
||||||
<div className=" d-flex align-items-center justify-content-center">
|
<div className=" d-flex align-items-center justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,9 @@ export default function PagePermission({ darkMode }) {
|
||||||
const togglePagePermissionModal = useStore((state) => state.togglePagePermissionModal);
|
const togglePagePermissionModal = useStore((state) => state.togglePagePermissionModal);
|
||||||
const editingPage = useStore((state) => state.editingPage);
|
const editingPage = useStore((state) => state.editingPage);
|
||||||
const appId = useStore((state) => state.appStore.modules[moduleId].app.appId);
|
const appId = useStore((state) => state.appStore.modules[moduleId].app.appId);
|
||||||
const selectedUserGroups = useStore((state) => state.selectedUserGroups);
|
const selectedUserGroups = useStore((state) => state.appPermission.selectedUserGroups);
|
||||||
const setSelectedUserGroups = useStore((state) => state.setSelectedUserGroups);
|
const setSelectedUserGroups = useStore((state) => state.setSelectedUserGroups);
|
||||||
const selectedUsers = useStore((state) => state.selectedUsers);
|
const selectedUsers = useStore((state) => state.appPermission.selectedUsers);
|
||||||
const setSelectedUsers = useStore((state) => state.setSelectedUsers);
|
const setSelectedUsers = useStore((state) => state.setSelectedUsers);
|
||||||
const pagePermission = useStore((state) => state.pagePermission);
|
const pagePermission = useStore((state) => state.pagePermission);
|
||||||
const setPagePermission = useStore((state) => state.setPagePermission);
|
const setPagePermission = useStore((state) => state.setPagePermission);
|
||||||
|
|
@ -353,7 +353,7 @@ export default function PagePermission({ darkMode }) {
|
||||||
const UserGroupSelect = () => {
|
const UserGroupSelect = () => {
|
||||||
const { moduleId } = useModuleContext();
|
const { moduleId } = useModuleContext();
|
||||||
const appId = useStore((state) => state.appStore.modules[moduleId].app.appId);
|
const appId = useStore((state) => state.appStore.modules[moduleId].app.appId);
|
||||||
const selectedUserGroups = useStore((state) => state.selectedUserGroups);
|
const selectedUserGroups = useStore((state) => state.appPermission.selectedUserGroups);
|
||||||
const setSelectedUserGroups = useStore((state) => state.setSelectedUserGroups);
|
const setSelectedUserGroups = useStore((state) => state.setSelectedUserGroups);
|
||||||
const [userGroups, setUserGroups] = useState([]);
|
const [userGroups, setUserGroups] = useState([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -415,7 +415,7 @@ const UserSelect = () => {
|
||||||
const { moduleId } = useModuleContext();
|
const { moduleId } = useModuleContext();
|
||||||
const appId = useStore((state) => state.appStore.modules[moduleId].app.appId);
|
const appId = useStore((state) => state.appStore.modules[moduleId].app.appId);
|
||||||
const editingPage = useStore((state) => state.editingPage);
|
const editingPage = useStore((state) => state.editingPage);
|
||||||
const selectedUsers = useStore((state) => state.selectedUsers);
|
const selectedUsers = useStore((state) => state.appPermission.selectedUsers);
|
||||||
const setSelectedUsers = useStore((state) => state.setSelectedUsers);
|
const setSelectedUsers = useStore((state) => state.setSelectedUsers);
|
||||||
const [users, setUsers] = useState([]);
|
const [users, setUsers] = useState([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export const PagesSidebarNavigation = ({
|
||||||
const { moduleId } = useModuleContext();
|
const { moduleId } = useModuleContext();
|
||||||
const { definition: { styles = {}, properties = {} } = {} } = useStore((state) => state.pageSettings) || {};
|
const { definition: { styles = {}, properties = {} } = {} } = useStore((state) => state.pageSettings) || {};
|
||||||
const selectedVersionName = useStore((state) => state.selectedVersion?.name);
|
const selectedVersionName = useStore((state) => state.selectedVersion?.name);
|
||||||
const currentMode = useStore((state) => state.currentMode);
|
const currentMode = useStore((state) => state.modeStore.modules[moduleId].currentMode);
|
||||||
const selectedEnvironmentName = useStore((state) => state.selectedEnvironment?.name);
|
const selectedEnvironmentName = useStore((state) => state.selectedEnvironment?.name);
|
||||||
const homePageId = useStore((state) => state.appStore.modules[moduleId].app.homePageId);
|
const homePageId = useStore((state) => state.appStore.modules[moduleId].app.homePageId);
|
||||||
const license = useStore((state) => state.license);
|
const license = useStore((state) => state.license);
|
||||||
|
|
@ -266,6 +266,10 @@ export const PagesSidebarNavigation = ({
|
||||||
const headerHidden = isLicensed ? hideHeader : false;
|
const headerHidden = isLicensed ? hideHeader : false;
|
||||||
const isPagesSidebarHidden = resolveReferences(disableMenu?.value);
|
const isPagesSidebarHidden = resolveReferences(disableMenu?.value);
|
||||||
|
|
||||||
|
if (hideHeader && hideLogo && isPagesSidebarHidden) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
|
|
@ -297,58 +301,60 @@ export const PagesSidebarNavigation = ({
|
||||||
ref={navRef}
|
ref={navRef}
|
||||||
className={cx('navigation-area', {
|
className={cx('navigation-area', {
|
||||||
close: !isSidebarPinned && properties?.collapsable && style !== 'text' && position === 'side',
|
close: !isSidebarPinned && properties?.collapsable && style !== 'text' && position === 'side',
|
||||||
// 'sidebar-overlay': !isSidebarPinned && properties?.collapsable,
|
|
||||||
'icon-only': style === 'icon' || (style === 'texticon' && !isSidebarPinned && position === 'side'),
|
'icon-only': style === 'icon' || (style === 'texticon' && !isSidebarPinned && position === 'side'),
|
||||||
'position-top': position === 'top',
|
'position-top': position === 'top' || isPagesSidebarHidden,
|
||||||
'text-only': style === 'text',
|
'text-only': style === 'text',
|
||||||
'right-sidebar-open': isRightSidebarOpen && position === 'top',
|
'right-sidebar-open': isRightSidebarOpen && (position === 'top' || isPagesSidebarHidden),
|
||||||
'left-sidebar-open': isSidebarOpen && position === 'top',
|
'left-sidebar-open': isSidebarOpen && (position === 'top' || isPagesSidebarHidden),
|
||||||
})}
|
})}
|
||||||
style={{
|
style={{
|
||||||
width: 226,
|
width: 226,
|
||||||
position: 'sticky',
|
position: 'sticky',
|
||||||
// height: `calc(100% - ${showHeader ? APP_HEADER_HEIGHT : 0}px)`,
|
height: currentMode === 'edit' ? '100%' : `calc(100% - 32px)`,
|
||||||
// height,
|
|
||||||
height: '100%',
|
|
||||||
// top: showHeader ? '47px' : '0px',
|
|
||||||
top: '4px',
|
top: '4px',
|
||||||
bottom: '0px',
|
bottom: '0px',
|
||||||
background: !styles?.backgroundColor?.isDefault && styles?.backgroundColor?.value,
|
background: !styles?.backgroundColor?.isDefault && styles?.backgroundColor?.value,
|
||||||
border: `${styles?.pillRadius?.value}px`,
|
border: `${styles?.pillRadius?.value}px`,
|
||||||
borderRight: !styles?.borderColor?.isDefault ? `1px solid ${styles?.borderColor?.value}` : '',
|
borderRight:
|
||||||
borderTop: !styles?.borderColor?.isDefault ? `1px solid ${styles?.borderColor?.value}` : '',
|
!styles?.borderColor?.isDefault && position === 'side' ? `1px solid ${styles?.borderColor?.value}` : '',
|
||||||
|
borderBottom:
|
||||||
|
!styles?.borderColor?.isDefault && position === 'top' ? `1px solid ${styles?.borderColor?.value}` : '',
|
||||||
overflow: 'scroll',
|
overflow: 'scroll',
|
||||||
boxShadow: 'var(--elevation-100-box-shadow)',
|
boxShadow: 'var(--elevation-100-box-shadow)',
|
||||||
scrollbarWidth: 'none',
|
|
||||||
// ...(position === 'side' && isSidebarOpen ? { marginLeft: isSidebarPinned ? '574px' : '392px' } : {}),
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="position-relative">
|
<div style={{ overflow: 'hidden' }} className="position-relative">
|
||||||
<div
|
{(collapsable || !headerHidden || !hideLogo) && (
|
||||||
style={{
|
<div
|
||||||
marginRight: headerHidden && position == 'top' && '0px',
|
style={{
|
||||||
}}
|
marginRight: hideHeader && hideLogo && position == 'top' && '0px',
|
||||||
className="app-name"
|
}}
|
||||||
>
|
className="app-name"
|
||||||
{!hideLogo && (
|
>
|
||||||
<div onClick={switchToHomePage} className="cursor-pointer">
|
{!hideLogo && (
|
||||||
<AppLogo isLoadingFromHeader={false} />
|
<div onClick={switchToHomePage} className="cursor-pointer flex-shrink-0">
|
||||||
</div>
|
<AppLogo isLoadingFromHeader={false} />
|
||||||
)}
|
</div>
|
||||||
{!headerHidden && ((isPinnedWithLabel && !labelHidden) || position === 'top') && (
|
)}
|
||||||
<span>{name?.trim() ? name : appName}</span>
|
{!headerHidden && ((isPinnedWithLabel && !labelHidden) || position === 'top') && (
|
||||||
)}
|
<OverflowTooltip>{name?.trim() ? name : appName}</OverflowTooltip>
|
||||||
{collapsable && !isTopPositioned && style == 'texticon' && position === 'side' && (
|
)}
|
||||||
<div onClick={toggleSidebarPinned} className="icon-btn collapse-icon ">
|
{collapsable &&
|
||||||
<SolidIcon
|
!isTopPositioned &&
|
||||||
className="cursor-pointer"
|
style == 'texticon' &&
|
||||||
fill="var(--icon-strong)"
|
position === 'side' &&
|
||||||
width="14px"
|
!isPagesSidebarHidden && (
|
||||||
name={isSidebarPinned ? 'remove03' : 'menu'}
|
<div onClick={toggleSidebarPinned} className="icon-btn collapse-icon ">
|
||||||
/>
|
<SolidIcon
|
||||||
</div>
|
className="cursor-pointer"
|
||||||
)}
|
fill="var(--icon-strong)"
|
||||||
</div>
|
width="14px"
|
||||||
|
name={isSidebarPinned ? 'remove03' : 'menu'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{isLicensed && !isPagesSidebarHidden ? (
|
{isLicensed && !isPagesSidebarHidden ? (
|
||||||
<RenderPageAndPageGroup
|
<RenderPageAndPageGroup
|
||||||
switchPageWrapper={switchPageWrapper}
|
switchPageWrapper={switchPageWrapper}
|
||||||
|
|
@ -414,12 +420,13 @@ const RenderPagesWithoutGroup = ({
|
||||||
moreBtnRef,
|
moreBtnRef,
|
||||||
}) => {
|
}) => {
|
||||||
const [showPopover, setShowPopover] = useState(false);
|
const [showPopover, setShowPopover] = useState(false);
|
||||||
const filteredPagesVisible = visibleLinks.filter(
|
const filteredPagesVisible = (position == 'top' ? visibleLinks : pages).filter(
|
||||||
(page) => (!page?.isPageGroup || page.children?.length > 0) && !page?.restricted
|
(page) => (!page?.isPageGroup || page.children?.length > 0) && !page?.restricted
|
||||||
);
|
);
|
||||||
const filteredPagesOverflow = overflowLinks.filter(
|
const filteredPagesOverflow = overflowLinks.filter(
|
||||||
(page) => (!page?.isPageGroup || page.children?.length > 0) && !page?.restricted
|
(page) => (!page?.isPageGroup || page.children?.length > 0) && !page?.restricted
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx('page-handler-wrapper', { 'dark-theme': darkMode })}>
|
<div className={cx('page-handler-wrapper', { 'dark-theme': darkMode })}>
|
||||||
{filteredPagesVisible.map((page) => {
|
{filteredPagesVisible.map((page) => {
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 7px 8px;
|
padding: 7px 8px;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
|
width: 100%;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
background-color: var(--interactive-default);
|
background-color: var(--interactive-default);
|
||||||
&.highlight {
|
&.highlight {
|
||||||
|
|
@ -112,6 +113,8 @@
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
button.edit-page-overlay-toggle{
|
button.edit-page-overlay-toggle{
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
@ -134,13 +137,23 @@
|
||||||
// margin-left: 15px;
|
// margin-left: 15px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
min-width: 0;
|
||||||
|
.main-page-icon-wrapper {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
.page-name{
|
.page-name{
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
color: var(--slate12);
|
color: var(--slate12);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
max-width: 246px;
|
flex-shrink: 1;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,8 +423,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.licensed-page-option {
|
.licensed-page-option {
|
||||||
|
pointer-events: unset !important;
|
||||||
button {
|
button {
|
||||||
pointer-events: none;
|
cursor: default;
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: unset !important;
|
background-color: unset !important;
|
||||||
}
|
}
|
||||||
|
|
@ -468,6 +482,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-control.is-invalid {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='text'], textarea {
|
||||||
|
border-radius: 6px;
|
||||||
|
&:focus {
|
||||||
|
border: 2px solid var(--border-accent-strong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.page-events {
|
.page-events {
|
||||||
.page-empty-events {
|
.page-empty-events {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import useStore from '@/AppBuilder/_stores/store';
|
import useStore from '@/AppBuilder/_stores/store';
|
||||||
import ArrowLeft from '@/_ui/Icon/solidIcons/ArrowLeft';
|
import ArrowLeft from '@/_ui/Icon/solidIcons/ArrowLeft';
|
||||||
|
|
@ -45,7 +45,12 @@ export const PageSettings = () => {
|
||||||
const isVersionReleased = useStore((state) => state.isVersionReleased);
|
const isVersionReleased = useStore((state) => state.isVersionReleased);
|
||||||
const switchPage = useStore((state) => state.switchPage);
|
const switchPage = useStore((state) => state.switchPage);
|
||||||
const toggleRightSidebarPin = useStore((state) => state.toggleRightSidebarPin);
|
const toggleRightSidebarPin = useStore((state) => state.toggleRightSidebarPin);
|
||||||
const isRightSidebarPinned = useStore((state) => state.isRightSidebarPinned);
|
const setRightSidebarOpen = useStore((state) => state.setRightSidebarOpen);
|
||||||
|
|
||||||
|
const handleToggle = () => {
|
||||||
|
setActiveRightSideBarTab(null);
|
||||||
|
setRightSidebarOpen(false);
|
||||||
|
};
|
||||||
const treeRef = useRef(null);
|
const treeRef = useRef(null);
|
||||||
|
|
||||||
const license = useStore((state) => state.license);
|
const license = useStore((state) => state.license);
|
||||||
|
|
@ -161,10 +166,12 @@ export const PageSettings = () => {
|
||||||
<div className="inspector pages-settings">
|
<div className="inspector pages-settings">
|
||||||
<div>
|
<div>
|
||||||
<div className="row inspector-component-title-input-holder d-flex align-items-center">
|
<div className="row inspector-component-title-input-holder d-flex align-items-center">
|
||||||
<div className={`col-9 p-0 ${isVersionReleased && 'disabled'}`}>Pages and navigation</div>
|
<div style={{ padding: '7px 6px' }} className={`col-9 ${isVersionReleased && 'disabled'}`}>
|
||||||
|
Pages and navigation
|
||||||
|
</div>
|
||||||
<div className="d-flex icon-holder">
|
<div className="d-flex icon-holder">
|
||||||
<div className="icon-btn cursor-pointer" onClick={() => toggleRightSidebarPin()}>
|
<div className="icon-btn cursor-pointer flex-shrink-0 p-2 h-4 w-4" onClick={handleToggle}>
|
||||||
<SolidIcon fill="var(--icon-strong)" name={isRightSidebarPinned ? 'unpin' : 'pin'} width="16" />
|
<SolidIcon fill="var(--icon-strong)" name={'remove03'} width="16" viewBox="0 0 16 16" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -223,13 +230,51 @@ const RenderStyles = React.memo(({ pagesMeta, renderCustomStyles }) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const AppHeaderMenu = ({ darkMode, pageSettings, pageSettingChanged, licenseValid }) => {
|
export const AppHeaderMenu = ({ darkMode, pageSettings, pageSettingChanged, licenseValid }) => {
|
||||||
const { moduleId } = useModuleContext();
|
const { moduleId } = useModuleContext();
|
||||||
const [appName] = useStore((state) => [state.appStore.modules[moduleId].app.appName], shallow);
|
const [appName] = useStore((state) => [state.appStore.modules[moduleId].app.appName], shallow);
|
||||||
|
|
||||||
const { definition: { properties = {} } = {} } = pageSettings ?? {};
|
const { definition: { properties = {} } = {} } = pageSettings ?? {};
|
||||||
const { hideHeader, name, hideLogo } = properties ?? {};
|
const { hideHeader, name, hideLogo } = properties ?? {};
|
||||||
|
|
||||||
const [_name, _setName] = useState(name?.trim() ? name : appName);
|
const [_name, _setName] = useState(name?.trim() ? name : appName);
|
||||||
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const newNameValue = name?.trim() ? name : appName;
|
||||||
|
if (_name !== newNameValue) {
|
||||||
|
_setName(newNameValue);
|
||||||
|
}
|
||||||
|
}, [name, appName]);
|
||||||
|
|
||||||
|
const handleNameChange = (e) => {
|
||||||
|
const newValue = e.target.value;
|
||||||
|
_setName(newValue);
|
||||||
|
setError(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNameBlur = (e) => {
|
||||||
|
const newValue = e.target.value.trim();
|
||||||
|
|
||||||
|
if (newValue === '') {
|
||||||
|
setError('Title cannot be empty.');
|
||||||
|
_setName(name?.trim() ? name : appName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newValue.length > 32) {
|
||||||
|
setError('Title cannot exceed 32 characters.');
|
||||||
|
_setName(name?.trim() ? name : appName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newValue !== (name?.trim() ? name : appName)) {
|
||||||
|
pageSettingChanged({ name: newValue }, 'properties');
|
||||||
|
setError(null);
|
||||||
|
} else {
|
||||||
|
setError(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -279,14 +324,17 @@ const AppHeaderMenu = ({ darkMode, pageSettings, pageSettingChanged, licenseVali
|
||||||
<label className="form-label font-weight-400 mb-0">Title</label>
|
<label className="form-label font-weight-400 mb-0">Title</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
onBlur={(e) => {
|
onBlur={handleNameBlur}
|
||||||
pageSettingChanged({ name: e.target.value }, 'properties');
|
onChange={handleNameChange}
|
||||||
}}
|
className={`form-control ${error ? 'is-invalid' : ''}`}
|
||||||
onChange={(e) => _setName(e.target.value)}
|
|
||||||
className="form-control"
|
|
||||||
value={_name}
|
value={_name}
|
||||||
minLength="1"
|
maxLength={32}
|
||||||
/>
|
/>
|
||||||
|
{error && (
|
||||||
|
<div className="invalid-feedback" style={{ display: 'block' }}>
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
@ -318,6 +366,8 @@ const NavigationMenu = ({ darkMode, pageSettings, pageSettingChanged }) => {
|
||||||
return str.toLowerCase() === 'true';
|
return str.toLowerCase() === 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [selectedStyle, setSelectedStyle] = useState(style);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="section-header pb-2">
|
<div className="section-header pb-2">
|
||||||
|
|
@ -357,6 +407,7 @@ const NavigationMenu = ({ darkMode, pageSettings, pageSettingChanged }) => {
|
||||||
pageSettingChanged({ position: value }, 'properties');
|
pageSettingChanged({ position: value }, 'properties');
|
||||||
}}
|
}}
|
||||||
defaultValue={position?.toString()}
|
defaultValue={position?.toString()}
|
||||||
|
style={{ width: '168px' }}
|
||||||
>
|
>
|
||||||
{POSTIONS.map((mode) => (
|
{POSTIONS.map((mode) => (
|
||||||
<ToggleGroupItem key={mode.value} value={mode.value}>
|
<ToggleGroupItem key={mode.value} value={mode.value}>
|
||||||
|
|
@ -371,14 +422,14 @@ const NavigationMenu = ({ darkMode, pageSettings, pageSettingChanged }) => {
|
||||||
<label className="form-label font-weight-400 mb-0">Style</label>
|
<label className="form-label font-weight-400 mb-0">Style</label>
|
||||||
<Select
|
<Select
|
||||||
options={styleOptions}
|
options={styleOptions}
|
||||||
search={true}
|
value={selectedStyle}
|
||||||
value={style}
|
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
|
setSelectedStyle(value);
|
||||||
pageSettingChanged({ style: value }, 'properties');
|
pageSettingChanged({ style: value }, 'properties');
|
||||||
}}
|
}}
|
||||||
placeholder={'Select...'}
|
placeholder={'Select...'}
|
||||||
useMenuPortal={false}
|
useMenuPortal={false}
|
||||||
width={'142px'}
|
width={'168px'}
|
||||||
className={`${darkMode ? 'select-search-dark' : 'select-search'}`}
|
className={`${darkMode ? 'select-search-dark' : 'select-search'}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -389,12 +440,10 @@ const NavigationMenu = ({ darkMode, pageSettings, pageSettingChanged }) => {
|
||||||
<div className="ms-auto position-relative app-mode-switch" style={{ paddingLeft: '0px' }}>
|
<div className="ms-auto position-relative app-mode-switch" style={{ paddingLeft: '0px' }}>
|
||||||
<ToggleGroup
|
<ToggleGroup
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
// if (position === 'side' && value == 'false') {
|
|
||||||
// pageSettingChanged({ style: 'texticon' }, 'properties');
|
|
||||||
// }
|
|
||||||
pageSettingChanged({ collapsable: stringToBoolean(value) }, 'properties');
|
pageSettingChanged({ collapsable: stringToBoolean(value) }, 'properties');
|
||||||
}}
|
}}
|
||||||
defaultValue={collapsable?.toString()}
|
defaultValue={collapsable?.toString()}
|
||||||
|
style={{ width: '168px' }}
|
||||||
>
|
>
|
||||||
{COLLAPSABLE_TOGGLES.map((mode) => (
|
{COLLAPSABLE_TOGGLES.map((mode) => (
|
||||||
<ToggleGroupItem key={mode.value} value={mode.value}>
|
<ToggleGroupItem key={mode.value} value={mode.value}>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import useStore from '@/AppBuilder/_stores/store';
|
import useStore from '@/AppBuilder/_stores/store';
|
||||||
import { ComponentConfigurationTab } from './ComponentConfigurationTab';
|
import { ComponentConfigurationTab } from './ComponentConfigurationTab';
|
||||||
import ComponentsManagerTab from './ComponentManagerTab';
|
import ComponentsManagerTab from './ComponentManagerTab';
|
||||||
|
|
@ -8,14 +8,29 @@ import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext';
|
||||||
|
|
||||||
export const RightSideBar = ({ darkMode }) => {
|
export const RightSideBar = ({ darkMode }) => {
|
||||||
const { isModuleEditor } = useModuleContext();
|
const { isModuleEditor } = useModuleContext();
|
||||||
|
const queryPanelHeight = useStore((state) => state.queryPanel.queryPanelHeight);
|
||||||
|
const isDraggingQueryPane = useStore((state) => state.queryPanel.isDraggingQueryPane);
|
||||||
|
|
||||||
const activeTab = useStore((state) => state.activeRightSideBarTab);
|
const activeTab = useStore((state) => state.activeRightSideBarTab);
|
||||||
const isRightSidebarOpen = useStore((state) => state.isRightSidebarOpen);
|
const isRightSidebarOpen = useStore((state) => state.isRightSidebarOpen);
|
||||||
const setRightSidebarOpen = useStore((state) => state.setRightSidebarOpen);
|
const setRightSidebarOpen = useStore((state) => state.setRightSidebarOpen);
|
||||||
const isRightSidebarPinned = useStore((state) => state.isRightSidebarPinned);
|
const isRightSidebarPinned = useStore((state) => state.isRightSidebarPinned);
|
||||||
const setActiveRightSideBarTab = useStore((state) => state.setActiveRightSideBarTab);
|
const setActiveRightSideBarTab = useStore((state) => state.setActiveRightSideBarTab);
|
||||||
|
const [popoverContentHeight, setPopoverContentHeight] = useState(queryPanelHeight);
|
||||||
|
|
||||||
const sidebarRef = useRef(null);
|
const sidebarRef = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isDraggingQueryPane) {
|
||||||
|
setPopoverContentHeight(
|
||||||
|
((window.innerHeight - (queryPanelHeight == 0 ? 40 : queryPanelHeight) - 45) / window.innerHeight) * 100
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setPopoverContentHeight(100);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [queryPanelHeight, isDraggingQueryPane]);
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
// const rigthSidebarMenu = document.querySelector('.right-sidebar-toggle');
|
// const rigthSidebarMenu = document.querySelector('.right-sidebar-toggle');
|
||||||
// function handleClickOutside(event) {
|
// function handleClickOutside(event) {
|
||||||
|
|
@ -40,7 +55,10 @@ export const RightSideBar = ({ darkMode }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={sidebarRef} className="sub-section">
|
<div ref={sidebarRef} className="sub-section">
|
||||||
<div className={cx('editor-sidebar', { 'dark-theme theme-dark': darkMode })}>
|
<div
|
||||||
|
style={{ height: `${popoverContentHeight}vh`, overflow: 'auto' }}
|
||||||
|
className={cx('editor-sidebar', { 'dark-theme theme-dark': darkMode })}
|
||||||
|
>
|
||||||
<div className={cx({ 'dark-theme theme-dark': darkMode })} style={{ position: 'relative', height: '100%' }}>
|
<div className={cx({ 'dark-theme theme-dark': darkMode })} style={{ position: 'relative', height: '100%' }}>
|
||||||
{activeTab === 'pages' && <PageSettings />}
|
{activeTab === 'pages' && <PageSettings />}
|
||||||
{activeTab === 'components' && <ComponentsManagerTab darkMode={darkMode} isModuleEditor={isModuleEditor} />}
|
{activeTab === 'components' && <ComponentsManagerTab darkMode={darkMode} isModuleEditor={isModuleEditor} />}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@ const RightSidebarToggle = ({ darkMode = false }) => {
|
||||||
handleToggle(RIGHT_SIDE_BAR_TAB.CONFIGURATION);
|
handleToggle(RIGHT_SIDE_BAR_TAB.CONFIGURATION);
|
||||||
}}
|
}}
|
||||||
darkMode={darkMode}
|
darkMode={darkMode}
|
||||||
icon="inspect"
|
icon="propertiesstyles"
|
||||||
|
iconWidth="14"
|
||||||
className={`left-sidebar-item left-sidebar-layout left-sidebar-inspector`}
|
className={`left-sidebar-item left-sidebar-layout left-sidebar-inspector`}
|
||||||
tip="Component properties"
|
tip="Component properties"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,39 @@
|
||||||
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
||||||
import React, { forwardRef } from 'react';
|
import React, { forwardRef } from 'react';
|
||||||
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
|
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
|
||||||
import Tooltip from 'react-bootstrap/Tooltip';
|
import { ToolTip } from '@/_components';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
// TODO: remove refs and related dependancies
|
// TODO: remove refs and related dependancies
|
||||||
export const SidebarItem = forwardRef(
|
export const SidebarItem = forwardRef(
|
||||||
({ tip = '', selectedSidebarItem, className, icon, iconFill = 'var(--slate8)', text, onClick, ...rest }, ref) => {
|
(
|
||||||
const { t } = useTranslation();
|
{
|
||||||
|
tip = '',
|
||||||
|
selectedSidebarItem,
|
||||||
|
className,
|
||||||
|
icon,
|
||||||
|
iconFill = 'var(--slate8)',
|
||||||
|
text,
|
||||||
|
onClick,
|
||||||
|
iconWidth = 20,
|
||||||
|
...rest
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
let displayIcon = icon;
|
let displayIcon = icon;
|
||||||
return (
|
return (
|
||||||
<div {...rest} className={className} onClick={onClick && onClick} ref={ref}>
|
<ToolTip placement="left" message={tip}>
|
||||||
{icon && (
|
<div {...rest} className={className} onClick={onClick && onClick} ref={ref}>
|
||||||
<div
|
{icon && (
|
||||||
className={`sidebar-svg-icon position-relative ${selectedSidebarItem && 'sidebar-item'}`}
|
<div
|
||||||
data-cy={`right-sidebar-${icon.toLowerCase()}-button`}
|
className={`sidebar-svg-icon position-relative ${selectedSidebarItem && 'sidebar-item'}`}
|
||||||
>
|
data-cy={`right-sidebar-${icon.toLowerCase()}-button`}
|
||||||
<SolidIcon name={displayIcon} width={20} fill={selectedSidebarItem ? '#3E63DD' : iconFill} />
|
>
|
||||||
</div>
|
<SolidIcon name={displayIcon} width={iconWidth} fill={selectedSidebarItem ? '#3E63DD' : iconFill} />
|
||||||
)}
|
</div>
|
||||||
<p>{text && t(`leftSidebar.${text}.text`, text)}</p>
|
)}
|
||||||
</div>
|
<p></p>
|
||||||
|
</div>
|
||||||
|
</ToolTip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import { redirectToDashboard } from '@/_helpers/routes';
|
||||||
import AppLogo from '@/_components/AppLogo';
|
import AppLogo from '@/_components/AppLogo';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext';
|
import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext';
|
||||||
|
import OverflowTooltip from '@/_components/OverflowTooltip';
|
||||||
|
|
||||||
const RenderGroup = ({ pages, pageGroup, currentPage, darkMode, handlepageSwitch, currentPageId, icon }) => {
|
const RenderGroup = ({ pages, pageGroup, currentPage, darkMode, handlepageSwitch, currentPageId, icon }) => {
|
||||||
const { moduleId } = useModuleContext();
|
const { moduleId } = useModuleContext();
|
||||||
|
|
@ -23,7 +24,7 @@ const RenderGroup = ({ pages, pageGroup, currentPage, darkMode, handlepageSwitch
|
||||||
setIsExpanded(!isExpanded);
|
setIsExpanded(!isExpanded);
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line import/namespace
|
// eslint-disable-next-line import/namespace
|
||||||
const IconElement = Icons?.[pageGroup?.icon] ?? Icons?.['IconFileDescription'];
|
const IconElement = Icons?.[pageGroup?.icon] ?? Icons?.['IconFile'];
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div style={{ border: 'none' }} className={`accordion-item ${darkMode ? 'dark-mode' : ''} `}>
|
<div style={{ border: 'none' }} className={`accordion-item ${darkMode ? 'dark-mode' : ''} `}>
|
||||||
|
|
@ -60,7 +61,7 @@ const RenderGroup = ({ pages, pageGroup, currentPage, darkMode, handlepageSwitch
|
||||||
const isHomePage = page.id === homePageId;
|
const isHomePage = page.id === homePageId;
|
||||||
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
||||||
// eslint-disable-next-line import/namespace
|
// eslint-disable-next-line import/namespace
|
||||||
const IconElement = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
|
const IconElement = Icons?.[iconName] ?? Icons?.['IconFile'];
|
||||||
return page?.hidden || page?.disabled ? null : (
|
return page?.hidden || page?.disabled ? null : (
|
||||||
<div
|
<div
|
||||||
key={page.handle}
|
key={page.handle}
|
||||||
|
|
@ -107,7 +108,7 @@ const RenderPageGroups = ({ pages, handlepageSwitch, darkMode, currentPageId, cu
|
||||||
const isHomePage = page.id === homePageId;
|
const isHomePage = page.id === homePageId;
|
||||||
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
||||||
// eslint-disable-next-line import/namespace
|
// eslint-disable-next-line import/namespace
|
||||||
const IconElement = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
|
const IconElement = Icons?.[iconName] ?? Icons?.['IconFile'];
|
||||||
return page?.hidden || page?.disabled ? null : (
|
return page?.hidden || page?.disabled ? null : (
|
||||||
<div
|
<div
|
||||||
key={page.handle}
|
key={page.handle}
|
||||||
|
|
@ -187,6 +188,7 @@ const MobileNavigationMenu = ({
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
padding: '0.5rem 0rem',
|
padding: '0.5rem 0rem',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
overflow: 'hidden',
|
||||||
},
|
},
|
||||||
bmOverlay: {
|
bmOverlay: {
|
||||||
background: 'rgba(0, 0, 0, 0.3)',
|
background: 'rgba(0, 0, 0, 0.3)',
|
||||||
|
|
@ -242,7 +244,7 @@ const MobileNavigationMenu = ({
|
||||||
{!hideLogo && <AppLogo isLoadingFromHeader={false} viewer={true} />}
|
{!hideLogo && <AppLogo isLoadingFromHeader={false} viewer={true} />}
|
||||||
{!hideHeader && (
|
{!hideHeader && (
|
||||||
<div className="d-flex align-items-center app-title">
|
<div className="d-flex align-items-center app-title">
|
||||||
<span>{name?.trim() ? name : appName}</span>
|
<OverflowTooltip>{name?.trim() ? name : appName}</OverflowTooltip>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -250,7 +252,7 @@ const MobileNavigationMenu = ({
|
||||||
</div>
|
</div>
|
||||||
</Header>
|
</Header>
|
||||||
|
|
||||||
<div className="w-100">
|
<div style={{ paddingBottom: '48px' }} className="w-100 overflow-auto h-100">
|
||||||
<div className={`pages-container ${darkMode && 'dark'}`}>
|
<div className={`pages-container ${darkMode && 'dark'}`}>
|
||||||
{isLicensed ? (
|
{isLicensed ? (
|
||||||
<RenderPageGroups
|
<RenderPageGroups
|
||||||
|
|
@ -265,7 +267,7 @@ const MobileNavigationMenu = ({
|
||||||
const isHomePage = page.id === homePageId;
|
const isHomePage = page.id === homePageId;
|
||||||
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
||||||
// eslint-disable-next-line import/namespace
|
// eslint-disable-next-line import/namespace
|
||||||
const IconElement = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
|
const IconElement = Icons?.[iconName] ?? Icons?.['IconFile'];
|
||||||
return page?.hidden || page?.disabled ? null : (
|
return page?.hidden || page?.disabled ? null : (
|
||||||
<div
|
<div
|
||||||
key={page.handle}
|
key={page.handle}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,9 @@ import Popups from '../Popups';
|
||||||
import { ModuleProvider } from '@/AppBuilder/_contexts/ModuleContext';
|
import { ModuleProvider } from '@/AppBuilder/_contexts/ModuleContext';
|
||||||
import { getPatToken, setPatToken } from '@/AppBuilder/EmbedApp';
|
import { getPatToken, setPatToken } from '@/AppBuilder/EmbedApp';
|
||||||
import Spinner from '@/_ui/Spinner';
|
import Spinner from '@/_ui/Spinner';
|
||||||
|
import { checkIfLicenseNotValid } from '@/_helpers/appUtils';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
|
import TooljetBanner from '../../Editor/Viewer/TooljetBanner';
|
||||||
|
|
||||||
export const Viewer = ({
|
export const Viewer = ({
|
||||||
id: appId,
|
id: appId,
|
||||||
|
|
@ -107,15 +109,13 @@ export const Viewer = ({
|
||||||
const { position, hideHeader } = properties ?? {};
|
const { position, hideHeader } = properties ?? {};
|
||||||
|
|
||||||
const canvasRef = useRef(null);
|
const canvasRef = useRef(null);
|
||||||
const isLoading = false;
|
|
||||||
const isMobilePreviewMode = selectedVersion?.id && currentLayout === 'mobile';
|
const isMobilePreviewMode = selectedVersion?.id && currentLayout === 'mobile';
|
||||||
const isAppLoaded = !!editingVersion;
|
const isAppLoaded = !!editingVersion;
|
||||||
const isMobileDevice = deviceWindowWidth < 600;
|
|
||||||
const switchPage = useStore((state) => state.switchPage);
|
const switchPage = useStore((state) => state.switchPage);
|
||||||
|
|
||||||
const showHeader = !globalSettings?.hideHeader && isAppLoaded;
|
const showHeader = !globalSettings?.hideHeader && isAppLoaded;
|
||||||
const isLicenseValid = useStore((state) => state.isLicenseValid);
|
const isLicenseNotValid = checkIfLicenseNotValid();
|
||||||
const licenseValid = isLicenseValid();
|
|
||||||
// ---remove
|
// ---remove
|
||||||
const handleAppEnvironmentChanged = useCallback((environment) => {
|
const handleAppEnvironmentChanged = useCallback((environment) => {
|
||||||
console.log('setAppVersionCurrentEnvironment', environment);
|
console.log('setAppVersionCurrentEnvironment', environment);
|
||||||
|
|
@ -229,19 +229,6 @@ export const Viewer = ({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className={`areas d-flex flex-rows app-${appId}`}>
|
<div className={`areas d-flex flex-rows app-${appId}`}>
|
||||||
{/* {currentLayout !== 'mobile' && !isPagesSidebarHidden && (
|
|
||||||
<PagesSidebarNavigation
|
|
||||||
showHeader={showHeader}
|
|
||||||
isMobileDevice={currentLayout === 'mobile'}
|
|
||||||
pages={pages}
|
|
||||||
currentPageId={currentPageId ?? homePageId}
|
|
||||||
darkMode={darkMode}
|
|
||||||
isSidebarPinned={isSidebarPinned}
|
|
||||||
toggleSidebarPinned={toggleSidebarPinned}
|
|
||||||
switchPage={switchPage}
|
|
||||||
/>
|
|
||||||
)} */}
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={cx('flex-grow-1 d-flex justify-content-center canvas-box', {
|
className={cx('flex-grow-1 d-flex justify-content-center canvas-box', {
|
||||||
close: !isSidebarPinned,
|
close: !isSidebarPinned,
|
||||||
|
|
@ -292,6 +279,7 @@ export const Viewer = ({
|
||||||
darkMode={darkMode}
|
darkMode={darkMode}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{isLicenseNotValid && isAppLoaded && <TooljetBanner isDarkMode={darkMode} />}
|
||||||
{isMobilePreviewMode && <div className="hide-drawer-transition" style={{ right: 0 }}></div>}
|
{isMobilePreviewMode && <div className="hide-drawer-transition" style={{ right: 0 }}></div>}
|
||||||
{isMobilePreviewMode && <div className="hide-drawer-transition" style={{ left: 0 }}></div>}
|
{isMobilePreviewMode && <div className="hide-drawer-transition" style={{ left: 0 }}></div>}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -193,6 +193,7 @@
|
||||||
.mobile-nav-container {
|
.mobile-nav-container {
|
||||||
.header-container {
|
.header-container {
|
||||||
background-color: unset !important;
|
background-color: unset !important;
|
||||||
|
flex-wrap: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1557,7 +1557,6 @@ export const createComponentsSlice = (set, get) => ({
|
||||||
!selectedText
|
!selectedText
|
||||||
) {
|
) {
|
||||||
clearSelectedComponents();
|
clearSelectedComponents();
|
||||||
setActiveRightSideBarTab(RIGHT_SIDE_BAR_TAB.COMPONENTS);
|
|
||||||
// if (!isRightSidebarPinned) {
|
// if (!isRightSidebarPinned) {
|
||||||
// setRightSidebarOpen(false);
|
// setRightSidebarOpen(false);
|
||||||
// }
|
// }
|
||||||
|
|
|
||||||
|
|
@ -119,14 +119,7 @@ export const createPageMenuSlice = (set, get) => {
|
||||||
state.showSearch = show;
|
state.showSearch = show;
|
||||||
if (!show) state.pageSearchResults = null;
|
if (!show) state.pageSearchResults = null;
|
||||||
}),
|
}),
|
||||||
openPageEditPopover: (page, ref) =>
|
|
||||||
set((state) => {
|
|
||||||
state.editingPage = page;
|
|
||||||
if (ref) {
|
|
||||||
state.popoverTargetId = ref?.current?.id;
|
|
||||||
state.showEditingPopover = true;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
setNewPagePopupConfig: (config) =>
|
setNewPagePopupConfig: (config) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.newPagePopupConfig = {
|
state.newPagePopupConfig = {
|
||||||
|
|
@ -134,14 +127,6 @@ export const createPageMenuSlice = (set, get) => {
|
||||||
...config,
|
...config,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
closePageEditPopover: () =>
|
|
||||||
set((state) => {
|
|
||||||
state.showEditingPopover = false;
|
|
||||||
state.showEditPageEventsModal = false;
|
|
||||||
state.showRenamePageHandleModal = false;
|
|
||||||
state.showEditPageNameInput = false;
|
|
||||||
state.showDeleteConfirmationModal = false;
|
|
||||||
}),
|
|
||||||
|
|
||||||
toggleEditPageHandleModal: (show) =>
|
toggleEditPageHandleModal: (show) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
|
|
@ -481,5 +466,28 @@ export const createPageMenuSlice = (set, get) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.editingPage = page;
|
state.editingPage = page;
|
||||||
}),
|
}),
|
||||||
|
openPageEditPopover: (type, page, ref) => {
|
||||||
|
// Assuming ref is passed for targeting
|
||||||
|
set((state) => ({
|
||||||
|
editingPage: page,
|
||||||
|
showEditingPopover: true, // Make sure this is explicitly set to true
|
||||||
|
newPagePopupConfig: {
|
||||||
|
// Set default values or infer from page
|
||||||
|
show: true, // This might be redundant if showEditingPopover is the primary flag
|
||||||
|
mode: type,
|
||||||
|
type: page?.type || 'default',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
// You might store the target ref in the state if overlays need to dynamically pick it up
|
||||||
|
// For react-bootstrap Overlay, the target is passed as a prop, not globally
|
||||||
|
},
|
||||||
|
// And when closing:
|
||||||
|
closePageEditPopover: () => {
|
||||||
|
set((state) => ({
|
||||||
|
editingPage: null,
|
||||||
|
showEditingPopover: false,
|
||||||
|
newPagePopupConfig: { show: false, mode: null, type: null },
|
||||||
|
}));
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ export const AppsRoute = ({ children, componentType }) => {
|
||||||
|
|
||||||
const handleBrowserNavigation = (e) => {
|
const handleBrowserNavigation = (e) => {
|
||||||
const { id, handle } = e.state;
|
const { id, handle } = e.state;
|
||||||
switchPage(id, handle, [], true);
|
switchPage(id, handle, []);
|
||||||
};
|
};
|
||||||
|
|
||||||
return <RouteLoader isLoading={isLoading}>{clonedElement}</RouteLoader>;
|
return <RouteLoader isLoading={isLoading}>{clonedElement}</RouteLoader>;
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,8 @@ export const DarkModeToggle = function DarkModeToggle({
|
||||||
springConfig: { mass: 4, tension: 250, friction: 35 },
|
springConfig: { mass: 4, tension: 250, friction: 35 },
|
||||||
};
|
};
|
||||||
|
|
||||||
const { r, transform, cx, cy, opacity } = properties[darkMode ? 'moon' : 'sun'];
|
const { r, transform, cx, cy, opacity } =
|
||||||
|
properties[darkMode || (appMode === 'dark' && toggleForCanvas) ? 'moon' : 'sun'];
|
||||||
|
|
||||||
const svgContainerProps = useSpring({
|
const svgContainerProps = useSpring({
|
||||||
transform,
|
transform,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState, useCallback } from 'react';
|
||||||
import { ToolTip } from '@/_components';
|
import { ToolTip } from '@/_components';
|
||||||
|
|
||||||
|
const isTextOverflowing = (element, verticalTolerance = 4) => {
|
||||||
|
if (!element) return false;
|
||||||
|
|
||||||
|
const horizontalOverflow = element.scrollWidth > element.clientWidth;
|
||||||
|
const verticalOverflow = element.scrollHeight > element.clientHeight + verticalTolerance;
|
||||||
|
|
||||||
|
return horizontalOverflow || verticalOverflow;
|
||||||
|
};
|
||||||
|
|
||||||
export default function OverflowTooltip({
|
export default function OverflowTooltip({
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
|
|
@ -10,21 +19,44 @@ export default function OverflowTooltip({
|
||||||
maxLetters,
|
maxLetters,
|
||||||
...rest
|
...rest
|
||||||
}) {
|
}) {
|
||||||
const [isOverflowed, setIsOverflow] = useState(false);
|
const [isOverflowed, setIsOverflowed] = useState(false);
|
||||||
const textElementRef = useRef();
|
const textContentRef = useRef(null);
|
||||||
|
|
||||||
|
const checkOverflow = useCallback(() => {
|
||||||
|
if (textContentRef.current) {
|
||||||
|
setIsOverflowed(isTextOverflowing(textContentRef.current));
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsOverflow(
|
const currentTextElement = textContentRef.current;
|
||||||
textElementRef.current.scrollWidth > textElementRef.current.clientWidth ||
|
if (!currentTextElement) {
|
||||||
textElementRef.current.clientHeight < textElementRef.current.scrollHeight - 4
|
return;
|
||||||
);
|
}
|
||||||
}, [children, boxWidth]);
|
|
||||||
|
checkOverflow();
|
||||||
|
|
||||||
|
const observer = new ResizeObserver((entries) => {
|
||||||
|
checkOverflow();
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(currentTextElement);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
observer.unobserve(currentTextElement);
|
||||||
|
observer.disconnect();
|
||||||
|
};
|
||||||
|
}, [children, checkOverflow]);
|
||||||
|
|
||||||
const displayText =
|
const displayText =
|
||||||
maxLetters && typeof children === 'string' && children.length > maxLetters
|
maxLetters && typeof children === 'string' && children.length > maxLetters
|
||||||
? `${children.substring(0, maxLetters)}...`
|
? `${children.substring(0, maxLetters)}...`
|
||||||
: children;
|
: children;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
checkOverflow();
|
||||||
|
}, [maxLetters, checkOverflow]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToolTip
|
<ToolTip
|
||||||
className={className}
|
className={className}
|
||||||
|
|
@ -36,7 +68,7 @@ export default function OverflowTooltip({
|
||||||
width={rest?.width}
|
width={rest?.width}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
ref={textElementRef}
|
ref={textContentRef}
|
||||||
className={rest.childrenClassName}
|
className={rest.childrenClassName}
|
||||||
style={{
|
style={{
|
||||||
whiteSpace,
|
whiteSpace,
|
||||||
|
|
|
||||||
|
|
@ -1106,42 +1106,42 @@ export function previewQuery(_ref, query, calledFromQuery = false, userSuppliedP
|
||||||
queryStatusCode === 400 ||
|
queryStatusCode === 400 ||
|
||||||
queryStatusCode === 404 ||
|
queryStatusCode === 404 ||
|
||||||
queryStatusCode === 422: {
|
queryStatusCode === 422: {
|
||||||
let errorData = {};
|
let errorData = {};
|
||||||
switch (query.kind) {
|
switch (query.kind) {
|
||||||
case 'runpy':
|
case 'runpy':
|
||||||
errorData = data.data;
|
errorData = data.data;
|
||||||
break;
|
break;
|
||||||
case 'tooljetdb':
|
case 'tooljetdb':
|
||||||
if (data?.error) {
|
if (data?.error) {
|
||||||
errorData = {
|
errorData = {
|
||||||
message: data?.error?.message || 'Something went wrong',
|
message: data?.error?.message || 'Something went wrong',
|
||||||
description: data?.error?.message || 'Something went wrong',
|
description: data?.error?.message || 'Something went wrong',
|
||||||
status: data?.statusText || 'Failed',
|
status: data?.statusText || 'Failed',
|
||||||
data: data?.error || {},
|
data: data?.error || {},
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
errorData = data;
|
|
||||||
errorData.description = data.errorMessage || 'Something went wrong';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
errorData = data;
|
errorData = data;
|
||||||
break;
|
errorData.description = data.errorMessage || 'Something went wrong';
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
onEvent(_ref, 'onDataQueryFailure', queryEvents);
|
default:
|
||||||
useCurrentStateStore.getState().actions.setErrors({
|
errorData = data;
|
||||||
[query.name]: {
|
break;
|
||||||
type: 'query',
|
|
||||||
kind: query.kind,
|
|
||||||
data: errorData,
|
|
||||||
options: options,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!calledFromQuery) setPreviewData(errorData);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onEvent(_ref, 'onDataQueryFailure', queryEvents);
|
||||||
|
useCurrentStateStore.getState().actions.setErrors({
|
||||||
|
[query.name]: {
|
||||||
|
type: 'query',
|
||||||
|
kind: query.kind,
|
||||||
|
data: errorData,
|
||||||
|
options: options,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!calledFromQuery) setPreviewData(errorData);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case queryStatus === 'needs_oauth': {
|
case queryStatus === 'needs_oauth': {
|
||||||
const url = data.data.auth_url; // Backend generates and return sthe auth url
|
const url = data.data.auth_url; // Backend generates and return sthe auth url
|
||||||
const kind = data.data?.kind;
|
const kind = data.data?.kind;
|
||||||
|
|
@ -1158,44 +1158,44 @@ export function previewQuery(_ref, query, calledFromQuery = false, userSuppliedP
|
||||||
queryStatus === 'Created' ||
|
queryStatus === 'Created' ||
|
||||||
queryStatus === 'Accepted' ||
|
queryStatus === 'Accepted' ||
|
||||||
queryStatus === 'No Content': {
|
queryStatus === 'No Content': {
|
||||||
if (query.options.enableTransformation) {
|
if (query.options.enableTransformation) {
|
||||||
finalData = await runTransformation(
|
finalData = await runTransformation(
|
||||||
_ref,
|
_ref,
|
||||||
finalData,
|
finalData,
|
||||||
query.options.transformation,
|
query.options.transformation,
|
||||||
query.options.transformationLanguage,
|
query.options.transformationLanguage,
|
||||||
query,
|
query,
|
||||||
'edit'
|
'edit'
|
||||||
);
|
);
|
||||||
if (finalData?.status === 'failed') {
|
if (finalData?.status === 'failed') {
|
||||||
useCurrentStateStore.getState().actions.setErrors({
|
useCurrentStateStore.getState().actions.setErrors({
|
||||||
[query.name]: {
|
|
||||||
type: 'transformations',
|
|
||||||
data: finalData,
|
|
||||||
options: options,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
onEvent(_ref, 'onDataQueryFailure', queryEvents);
|
|
||||||
setPreviewLoading(false);
|
|
||||||
resolve({ status: data.status, data: finalData });
|
|
||||||
// console.log('Test', finalData);
|
|
||||||
if (!calledFromQuery) setPreviewData(finalData);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useCurrentStateStore.getState().actions.setCurrentState({
|
|
||||||
succededQuery: {
|
|
||||||
[query.name]: {
|
[query.name]: {
|
||||||
type: 'query',
|
type: 'transformations',
|
||||||
kind: query.kind,
|
data: finalData,
|
||||||
|
options: options,
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
});
|
onEvent(_ref, 'onDataQueryFailure', queryEvents);
|
||||||
if (!calledFromQuery) setPreviewData(finalData);
|
setPreviewLoading(false);
|
||||||
onEvent(_ref, 'onDataQuerySuccess', queryEvents, 'edit');
|
resolve({ status: data.status, data: finalData });
|
||||||
break;
|
// console.log('Test', finalData);
|
||||||
|
if (!calledFromQuery) setPreviewData(finalData);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useCurrentStateStore.getState().actions.setCurrentState({
|
||||||
|
succededQuery: {
|
||||||
|
[query.name]: {
|
||||||
|
type: 'query',
|
||||||
|
kind: query.kind,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!calledFromQuery) setPreviewData(finalData);
|
||||||
|
onEvent(_ref, 'onDataQuerySuccess', queryEvents, 'edit');
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setPreviewLoading(false);
|
setPreviewLoading(false);
|
||||||
|
|
||||||
|
|
@ -1411,10 +1411,10 @@ export function runQuery(
|
||||||
},
|
},
|
||||||
query.kind === 'restapi'
|
query.kind === 'restapi'
|
||||||
? {
|
? {
|
||||||
request: data.data.requestObject,
|
request: data.data.requestObject,
|
||||||
response: data.data.responseObject,
|
response: data.data.responseObject,
|
||||||
responseHeaders: data.data.responseHeaders,
|
responseHeaders: data.data.responseHeaders,
|
||||||
}
|
}
|
||||||
: {}
|
: {}
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -2405,11 +2405,11 @@ export const removeFunctionObjects = (obj) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const checkIfLicenseNotValid = () => {
|
export const checkIfLicenseNotValid = () => {
|
||||||
const licenseStatus = useEditorStore.getState().featureAccess?.licenseStatus;
|
const licenseStatus = useStore.getState().license.featureAccess?.licenseStatus;
|
||||||
// When purchased, then isExpired key is also avialale else its not available
|
// When purchased, then isExpired key is also avialale else its not available
|
||||||
if (licenseStatus) {
|
if (licenseStatus) {
|
||||||
if (_.has(licenseStatus, 'isExpired')) {
|
if (_.has(licenseStatus, 'isExpired')) {
|
||||||
return licenseStatus?.isExpired && !licenseStatus?.isLicenseValid;
|
return licenseStatus?.isExpired;
|
||||||
}
|
}
|
||||||
return !licenseStatus?.isLicenseValid;
|
return !licenseStatus?.isLicenseValid;
|
||||||
}
|
}
|
||||||
|
|
@ -2431,12 +2431,12 @@ export function isPDFSupported() {
|
||||||
|
|
||||||
function getBrowserUserAgent(userAgent) {
|
function getBrowserUserAgent(userAgent) {
|
||||||
var regexps = {
|
var regexps = {
|
||||||
Chrome: [/Chrome\/(\S+)/],
|
Chrome: [/Chrome\/(\S+)/],
|
||||||
Firefox: [/Firefox\/(\S+)/],
|
Firefox: [/Firefox\/(\S+)/],
|
||||||
MSIE: [/MSIE (\S+);/],
|
MSIE: [/MSIE (\S+);/],
|
||||||
Opera: [/Opera\/.*?Version\/(\S+)/ /* Opera 10 */, /Opera\/(\S+)/ /* Opera 9 and older */],
|
Opera: [/Opera\/.*?Version\/(\S+)/ /* Opera 10 */, /Opera\/(\S+)/ /* Opera 9 and older */],
|
||||||
Safari: [/Version\/(\S+).*?Safari\//],
|
Safari: [/Version\/(\S+).*?Safari\//],
|
||||||
},
|
},
|
||||||
re,
|
re,
|
||||||
m,
|
m,
|
||||||
browser,
|
browser,
|
||||||
|
|
|
||||||
|
|
@ -617,15 +617,14 @@
|
||||||
|
|
||||||
.page-handler-wrapper {
|
.page-handler-wrapper {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
height: 100%;
|
|
||||||
scrollbar-width: none;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
&.viewer{
|
scrollbar-width: thin;
|
||||||
overflow: visible !important;
|
height: 100%;
|
||||||
}
|
padding-bottom: 48px;
|
||||||
|
scrollbar-color: var(--interactive-selected) transparent;
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar-track {
|
||||||
display: none;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tj-list-item-selected {
|
.tj-list-item-selected {
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,6 @@
|
||||||
|
|
||||||
.accordion-header {
|
.accordion-header {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
background-color: var(--interactive-default);
|
|
||||||
|
|
||||||
.accordion-title-text {
|
.accordion-title-text {
|
||||||
color: var(--text-default);
|
color: var(--text-default);
|
||||||
|
|
@ -150,6 +149,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-control.is-invalid {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='text'] {
|
||||||
|
border-radius: 6px;
|
||||||
|
&:focus {
|
||||||
|
border: 2px solid var(--border-accent-strong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.accordion-body {
|
.accordion-body {
|
||||||
padding: 16px !important;
|
padding: 16px !important;
|
||||||
|
|
||||||
|
|
@ -217,7 +227,7 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
bottom: 2px;
|
bottom: 2px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding-top: 32px;
|
padding-top: 16px;
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
|
|
||||||
.sidebar-svg-icon {
|
.sidebar-svg-icon {
|
||||||
|
|
@ -241,6 +251,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: unset !important;
|
width: unset !important;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
min-height: 28px;
|
||||||
|
|
||||||
.collapse-icon {
|
.collapse-icon {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
|
@ -276,6 +287,23 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-group-wrapper {
|
.page-group-wrapper {
|
||||||
|
padding: 0px !important;
|
||||||
|
|
||||||
|
.icon-btn {
|
||||||
|
height: unset !important;
|
||||||
|
width: unset !important;
|
||||||
|
padding: 0px !important;
|
||||||
|
padding-right: 12px !important;
|
||||||
|
&:hover {
|
||||||
|
background-color: unset !important
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tj-list-item {
|
||||||
|
margin-bottom: 0px !important;
|
||||||
|
padding-right: 0px !important;
|
||||||
|
flex-shrink: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
&.tj-list-item-selected {
|
&.tj-list-item-selected {
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: var(--background-accent-weak);
|
background: var(--background-accent-weak);
|
||||||
|
|
@ -342,14 +370,15 @@
|
||||||
.app-name {
|
.app-name {
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
|
gap: 0px;
|
||||||
.cursor-pointer {
|
.cursor-pointer {
|
||||||
img {
|
img {
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.icon-btn {
|
.icon-btn {
|
||||||
margin-left: 0px;
|
margin-left: 0px;
|
||||||
|
margin-bottom: 20px
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -365,6 +394,7 @@
|
||||||
}
|
}
|
||||||
.accordion-body{
|
.accordion-body{
|
||||||
padding: 4px 0 4px 16px !important;
|
padding: 4px 0 4px 16px !important;
|
||||||
|
border-bottom: 0px !important;
|
||||||
}
|
}
|
||||||
.accordion-header{
|
.accordion-header{
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
|
|
@ -429,11 +459,12 @@
|
||||||
padding-top: 0px;
|
padding-top: 0px;
|
||||||
overflow: hidden !important;
|
overflow: hidden !important;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
border-right: 0px !important;
|
||||||
|
|
||||||
.page-handler-wrapper {
|
.page-handler-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-dark-mode-btn-wrapper {
|
.page-dark-mode-btn-wrapper {
|
||||||
|
|
@ -453,6 +484,36 @@
|
||||||
.tj-list-item {
|
.tj-list-item {
|
||||||
padding-right: 0px !important;
|
padding-right: 0px !important;
|
||||||
width: unset !important;
|
width: unset !important;
|
||||||
|
margin-bottom: 0px !important;
|
||||||
|
}
|
||||||
|
.page-group-wrapper {
|
||||||
|
gap: 2px;
|
||||||
|
padding: 6px 10px !important;
|
||||||
|
padding-right: 0px !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--interactive-overlays-fill-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
&:hover {
|
||||||
|
background-color: unset !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-btn {
|
||||||
|
height: unset !important;
|
||||||
|
width: unset !important;
|
||||||
|
padding: 0px !important;
|
||||||
|
padding-right: 10px !important;
|
||||||
|
&:hover {
|
||||||
|
background-color: unset !important
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tj-list-item {
|
||||||
|
padding: 0px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -484,8 +545,9 @@
|
||||||
|
|
||||||
.tj-list-item {
|
.tj-list-item {
|
||||||
outline: none !important;
|
outline: none !important;
|
||||||
padding: 6px 10px;
|
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
padding: 6px 10px !important;
|
||||||
|
margin-bottom: 0px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-name {
|
.page-name {
|
||||||
|
|
@ -498,11 +560,23 @@
|
||||||
|
|
||||||
.page-handler-wrapper {
|
.page-handler-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
padding-bottom: unset !important;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.more-btn-pages {
|
||||||
|
&.tj-list-item-selected {
|
||||||
|
svg {
|
||||||
|
path {
|
||||||
|
fill: var(--icon-accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.right-sidebar-open {
|
&.right-sidebar-open {
|
||||||
width: calc(100% + 299px) !important;
|
width: calc(100% + 300px) !important;
|
||||||
position: sticky !important;
|
position: sticky !important;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -514,7 +588,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.right-sidebar-open.left-sidebar-open {
|
&.right-sidebar-open.left-sidebar-open {
|
||||||
width: calc(100% + 646px) !important;
|
width: calc(100% + 650px) !important;
|
||||||
position: sticky !important;
|
position: sticky !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -526,7 +600,7 @@
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
|
|
||||||
.tj-list-item{
|
.tj-list-item{
|
||||||
padding: 8px 12px;
|
padding: 6px 12px;
|
||||||
color: var(--text-placeholder);
|
color: var(--text-placeholder);
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
|
@ -550,12 +624,9 @@
|
||||||
.accordion-body {
|
.accordion-body {
|
||||||
padding: 0px 12px !important;
|
padding: 0px 12px !important;
|
||||||
padding-left: 28px !important;
|
padding-left: 28px !important;
|
||||||
|
border-bottom: 0px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.accordion-body {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-group-collapse {
|
.page-group-collapse {
|
||||||
// right: 4px;
|
// right: 4px;
|
||||||
transform: rotate(30deg);
|
transform: rotate(30deg);
|
||||||
|
|
@ -601,8 +672,19 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
|
|
||||||
|
.icon-btn {
|
||||||
|
height: unset !important;
|
||||||
|
width: unset !important;
|
||||||
|
padding: 0px !important;
|
||||||
|
padding-right: 12px !important;
|
||||||
|
&:hover {
|
||||||
|
background-color: unset !important
|
||||||
|
}
|
||||||
|
}
|
||||||
.tj-list-item {
|
.tj-list-item {
|
||||||
padding-right: 0px;
|
padding: 8px 12px !important;
|
||||||
|
padding-right: 0px !important;
|
||||||
width: unset !important;
|
width: unset !important;
|
||||||
}
|
}
|
||||||
&.tj-list-item-selected {
|
&.tj-list-item-selected {
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@
|
||||||
|
|
||||||
div[data-radix-popper-content-wrapper]:has(.PopoverContent.drawer-height) {
|
div[data-radix-popper-content-wrapper]:has(.PopoverContent.drawer-height) {
|
||||||
margin-top: 48px;
|
margin-top: 48px;
|
||||||
margin-left: 47px !important;
|
margin-left: 48px !important;
|
||||||
transform: none !important;
|
transform: none !important;
|
||||||
z-index: 2 !important;
|
z-index: 2 !important;
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +59,6 @@ div[data-radix-popper-content-wrapper]:has(.PopoverContent.drawer-height) {
|
||||||
@-moz-document url-prefix() {
|
@-moz-document url-prefix() {
|
||||||
div[data-radix-popper-content-wrapper] {
|
div[data-radix-popper-content-wrapper] {
|
||||||
z-index: 100 !important;
|
z-index: 100 !important;
|
||||||
left: 1px !important;
|
// left: 1px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -93,7 +93,7 @@ $border-radius: 4px;
|
||||||
height: 400px;
|
height: 400px;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 48px;
|
left: 48px;
|
||||||
right: 348px;
|
right: 48px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
|
|
||||||
|
|
@ -662,11 +662,13 @@ button {
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid var(--border-weak);
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
color: var(--text-default);
|
color: var(--text-default);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
padding: 7px 6px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -823,8 +825,13 @@ button {
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.canvas-container {
|
:hover {
|
||||||
scrollbar-width: none;
|
.canvas-container {
|
||||||
|
scrollbar-width: thin;
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.canvas-container {
|
.canvas-container {
|
||||||
|
|
@ -839,6 +846,16 @@ button {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
-webkit-box-align: center;
|
-webkit-box-align: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
scrollbar-color: var(--interactive-selected) transparent;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--interactive-default) !important;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
.real-canvas {
|
.real-canvas {
|
||||||
outline: 1px dotted transparent;
|
outline: 1px dotted transparent;
|
||||||
|
|
@ -5203,12 +5220,13 @@ input[type="text"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
.inspector-component-title-input-holder {
|
.inspector-component-title-input-holder {
|
||||||
padding: 2px 12px;
|
padding: 4px 12px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
.icon-btn {
|
.icon-btn {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
|
|
@ -18706,4 +18724,12 @@ section.ai-message-prompt-input-wrapper {
|
||||||
.git-sync-modal .modal-header .modal-title .push-pull-tabs .tab-push.active,
|
.git-sync-modal .modal-header .modal-title .push-pull-tabs .tab-push.active,
|
||||||
.git-sync-modal .modal-header .modal-title .push-pull-tabs .tab-pull.active {
|
.git-sync-modal .modal-header .modal-title .push-pull-tabs .tab-pull.active {
|
||||||
border-bottom: 2px solid var(--indigo9) !important;
|
border-bottom: 2px solid var(--indigo9) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.min-width-0 {
|
||||||
|
min-width: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.width-unset {
|
||||||
|
width: unset !important;
|
||||||
}
|
}
|
||||||
14
frontend/src/_ui/Icon/solidIcons/CaretDown.jsx
Normal file
14
frontend/src/_ui/Icon/solidIcons/CaretDown.jsx
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const CaretDown = ({ fill = '#C1C8CD', width = '16', className = '', viewBox = '0 0 16 16' }) => (
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width={width} height={width} viewBox={viewBox} fill="none">
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M11.3271 7.16832C11.4633 6.97259 11.504 6.67822 11.4303 6.42249C11.3566 6.16674 11.183 6 10.9903 6H5.2761C5.08348 6 4.90986 6.16674 4.83615 6.42249C4.76244 6.67822 4.8032 6.97259 4.93939 7.16832L7.62814 11.0327C7.90709 11.4335 8.35935 11.4335 8.63829 11.0327L11.3271 7.16832Z"
|
||||||
|
fill={fill}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default CaretDown;
|
||||||
14
frontend/src/_ui/Icon/solidIcons/CaretUp.jsx
Normal file
14
frontend/src/_ui/Icon/solidIcons/CaretUp.jsx
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const CaretUp = ({ fill = '#C1C8CD', width = '16', className = '', viewBox = '0 0 16 16' }) => (
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width={width} height={width} viewBox={viewBox} fill="none">
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M12.5272 8.83298C12.6634 9.02872 12.7041 9.32308 12.6304 9.57882C12.5567 9.83456 12.3831 10.0013 12.1905 10.0013L6.47621 10.0013C6.28359 10.0013 6.10998 9.83456 6.03626 9.57882C5.96255 9.32308 6.00331 9.02872 6.1395 8.83298L8.82826 4.9686C9.1072 4.56776 9.55946 4.56776 9.83841 4.9686L12.5272 8.83298Z"
|
||||||
|
fill={fill}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default CaretUp;
|
||||||
14
frontend/src/_ui/Icon/solidIcons/PropertiesStyles.jsx
Normal file
14
frontend/src/_ui/Icon/solidIcons/PropertiesStyles.jsx
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const PropertiesStyles = ({ fill = '#ACB2B9', width = '14', viewBox = '0 0 14 14', className = '' }) => (
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width={width} height={width} viewBox={viewBox} fill={fill}>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M4.98645 1.1867L3.98282 2.19035C3.73248 2.44068 3.73248 2.84655 3.98282 3.09689C4.23315 3.34722 4.63902 3.34722 4.88936 3.09689L5.893 2.09325L6.73764 2.9379L2.92525 6.72979L0.483747 4.28827C0.283478 4.08801 0.283478 3.76331 0.483747 3.56305L3.56066 0.486139C3.76092 0.28587 4.08562 0.28587 4.28588 0.486139L4.98645 1.1867ZM11.9101 8.10968L11.0505 7.25008L7.24656 11.0504L9.71517 13.519C9.91545 13.7193 10.2402 13.7193 10.4405 13.519L13.5174 10.4421C13.7176 10.2419 13.7176 9.91719 13.5174 9.71693L12.8167 9.01622L11.8129 10.02C11.5625 10.2703 11.1567 10.2703 10.9063 10.02C10.6559 9.76964 10.6559 9.36377 10.9063 9.11344L11.9101 8.10968ZM10.6981 0.806912C11.0981 0.409053 11.7444 0.408969 12.1445 0.806721L13.1895 1.84555C13.5921 2.24587 13.593 2.89717 13.1913 3.2985L3.64133 12.8396C3.57898 12.9018 3.50164 12.947 3.41675 12.9707L0.98224 13.6502C0.805496 13.6996 0.615861 13.6507 0.484968 13.5221C0.354074 13.3935 0.301872 13.2048 0.34808 13.0271L0.988875 10.5645C1.01197 10.4757 1.05848 10.3948 1.12353 10.33L10.6981 0.806912Z"
|
||||||
|
fill={fill}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default PropertiesStyles;
|
||||||
|
|
@ -12,7 +12,7 @@ const Remove03 = ({ width = '14', fill = '#6A727C', className = '', viewBox = '0
|
||||||
<path
|
<path
|
||||||
fill-rule="evenodd"
|
fill-rule="evenodd"
|
||||||
clip-rule="evenodd"
|
clip-rule="evenodd"
|
||||||
d="M12.5487 2.82638C12.9283 2.44677 12.9283 1.83131 12.5487 1.45169C12.1691 1.07209 11.5536 1.07209 11.1741 1.45169L7.0001 5.62566L2.82614 1.45169C2.44652 1.07209 1.83106 1.07209 1.45145 1.45169C1.07185 1.83131 1.07185 2.44677 1.45145 2.82638L5.62542 7.00035L1.45145 11.1743C1.07185 11.5539 1.07185 12.1694 1.45145 12.549C1.83106 12.9286 2.44652 12.9286 2.82614 12.549L7.0001 8.37502L11.1741 12.549C11.5536 12.9286 12.1691 12.9286 12.5487 12.549C12.9283 12.1694 12.9283 11.5539 12.5487 11.1743L8.37478 7.00035L12.5487 2.82638Z"
|
d="M14.3412 3.22848C14.775 2.79463 14.775 2.09125 14.3412 1.65741C13.9074 1.22357 13.204 1.22357 12.7702 1.65741L7.99994 6.42765L3.2297 1.65741C2.79585 1.22357 2.09247 1.22357 1.65863 1.65741C1.22479 2.09125 1.22479 2.79463 1.65863 3.22848L6.42887 7.99872L1.65863 12.769C1.22479 13.2028 1.22479 13.9062 1.65863 14.34C2.09247 14.7738 2.79585 14.7738 3.2297 14.34L7.99994 9.56978L12.7702 14.34C13.204 14.7738 13.9074 14.7738 14.3412 14.34C14.775 13.9062 14.775 13.2028 14.3412 12.769L9.571 7.99872L14.3412 3.22848Z"
|
||||||
fill={fill}
|
fill={fill}
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ import CheveronLeft from './CheveronLeft.jsx';
|
||||||
import CheveronRight from './CheveronRight.jsx';
|
import CheveronRight from './CheveronRight.jsx';
|
||||||
import CheveronUp from './CheveronUp.jsx';
|
import CheveronUp from './CheveronUp.jsx';
|
||||||
import ClearRectangle from './ClearRectangle.jsx';
|
import ClearRectangle from './ClearRectangle.jsx';
|
||||||
|
import CaretDown from './CaretDown.jsx';
|
||||||
|
import CaretUp from './CaretUp.jsx';
|
||||||
import Clock from './Clock.jsx';
|
import Clock from './Clock.jsx';
|
||||||
import CursorClick from './CursorClick.jsx';
|
import CursorClick from './CursorClick.jsx';
|
||||||
import LockGradient from './LockGradient.jsx';
|
import LockGradient from './LockGradient.jsx';
|
||||||
|
|
@ -261,6 +263,7 @@ import Delete01 from './Delete01.jsx';
|
||||||
import SourceControl from './SourceControl.jsx';
|
import SourceControl from './SourceControl.jsx';
|
||||||
import Push from './PushIcon.jsx';
|
import Push from './PushIcon.jsx';
|
||||||
import Pull from './PullIcon.jsx';
|
import Pull from './PullIcon.jsx';
|
||||||
|
import PropertiesStyles from './PropertiesStyles.jsx';
|
||||||
import RemoveFolder from './RemoveFolder.jsx';
|
import RemoveFolder from './RemoveFolder.jsx';
|
||||||
|
|
||||||
const Icon = (props) => {
|
const Icon = (props) => {
|
||||||
|
|
@ -335,6 +338,10 @@ const Icon = (props) => {
|
||||||
return <Debugger {...props} />;
|
return <Debugger {...props} />;
|
||||||
case 'calender':
|
case 'calender':
|
||||||
return <Calender {...props} />;
|
return <Calender {...props} />;
|
||||||
|
case 'caretdown':
|
||||||
|
return <CaretDown {...props} />;
|
||||||
|
case 'caretup':
|
||||||
|
return <CaretUp {...props} />;
|
||||||
case 'checkrectangle':
|
case 'checkrectangle':
|
||||||
return <CheckRectangle {...props} />;
|
return <CheckRectangle {...props} />;
|
||||||
case 'cheverondown':
|
case 'cheverondown':
|
||||||
|
|
@ -535,6 +542,8 @@ const Icon = (props) => {
|
||||||
return <Pin {...props} />;
|
return <Pin {...props} />;
|
||||||
case 'unpin01':
|
case 'unpin01':
|
||||||
return <Unpin01 {...props} />;
|
return <Unpin01 {...props} />;
|
||||||
|
case 'propertiesstyles':
|
||||||
|
return <PropertiesStyles {...props} />;
|
||||||
case 'unpin':
|
case 'unpin':
|
||||||
return <Unpin {...props} />;
|
return <Unpin {...props} />;
|
||||||
case 'play':
|
case 'play':
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class MoveHideHeaderAndAddPositionToPageSettings1751283157638 implements MigrationInterface {
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
const appVersions = await queryRunner.manager.query(`
|
||||||
|
SELECT id, page_settings, global_settings FROM app_versions
|
||||||
|
`);
|
||||||
|
|
||||||
|
for (const version of appVersions) {
|
||||||
|
let pageSettings = version.page_settings;
|
||||||
|
let globalSettings = version.global_settings;
|
||||||
|
|
||||||
|
if (typeof pageSettings === 'string') {
|
||||||
|
pageSettings = JSON.parse(pageSettings);
|
||||||
|
}
|
||||||
|
if (typeof globalSettings === 'string') {
|
||||||
|
globalSettings = JSON.parse(globalSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pageSettings) {
|
||||||
|
pageSettings = { properties: {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pageSettings.properties) {
|
||||||
|
pageSettings.properties = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!('position' in pageSettings.properties)) {
|
||||||
|
pageSettings.properties.position = 'side';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (globalSettings && 'hideHeader' in globalSettings) {
|
||||||
|
pageSettings.properties.hideHeader = globalSettings.hideHeader;
|
||||||
|
pageSettings.properties.hideLogo = globalSettings.hideHeader;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
await queryRunner.manager.query(
|
||||||
|
`UPDATE app_versions SET page_settings = $1, global_settings = $2 WHERE id = $3`,
|
||||||
|
[JSON.stringify(pageSettings), JSON.stringify(globalSettings), version.id]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 8c0e6dec37f1b0bb7fb5552d8eef4db3ddc18b31
|
Subproject commit dac59b75498c7b7cf4356432c24991eabd13b568
|
||||||
|
|
@ -92,14 +92,14 @@ export class PageService implements IPageService {
|
||||||
|
|
||||||
await this.clonePageEventsAndComponents(pageId, clonedpage.id, manager);
|
await this.clonePageEventsAndComponents(pageId, clonedpage.id, manager);
|
||||||
|
|
||||||
const pages = await this.findPagesForVersion(appVersionId, organizationId, manager);
|
const pages = await this.findPagesForVersion(appVersionId, organizationId, '', manager);
|
||||||
const events = await this.eventHandlerService.findEventsForVersion(appVersionId, manager);
|
const events = await this.eventHandlerService.findEventsForVersion(appVersionId, manager);
|
||||||
|
|
||||||
return { pages, events };
|
return { pages, events };
|
||||||
}, appVersionId);
|
}, appVersionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async cloneGroup(groupPageId: string, appVersionId: string) {
|
async cloneGroup(groupPageId: string, appVersionId: string, organizationId) {
|
||||||
return dbTransactionForAppVersionAssociationsUpdate(async (manager) => {
|
return dbTransactionForAppVersionAssociationsUpdate(async (manager) => {
|
||||||
const groupToClone = await manager.findOne(Page, {
|
const groupToClone = await manager.findOne(Page, {
|
||||||
where: { id: groupPageId, appVersionId, isPageGroup: true },
|
where: { id: groupPageId, appVersionId, isPageGroup: true },
|
||||||
|
|
@ -185,7 +185,7 @@ export class PageService implements IPageService {
|
||||||
await this.clonePageEventsAndComponents(child.id, newChildPage.id, manager);
|
await this.clonePageEventsAndComponents(child.id, newChildPage.id, manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pages = await this.findPagesForVersion(appVersionId, '', manager);
|
const pages = await this.findPagesForVersion(appVersionId,organizationId, '', manager);
|
||||||
const events = await this.eventHandlerService.findEventsForVersion(appVersionId, manager);
|
const events = await this.eventHandlerService.findEventsForVersion(appVersionId, manager);
|
||||||
|
|
||||||
return { pages, events };
|
return { pages, events };
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue