mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-05 22:38:48 +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 { shallow } from 'zustand/shallow';
|
||||
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 FreezeVersionInfo from '@/AppBuilder/Header/FreezeVersionInfo';
|
||||
import { computeCanvasContainerHeight } from '../_helpers/editorHelpers';
|
||||
|
|
@ -134,7 +140,7 @@ export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode })
|
|||
width: currentMode === 'edit' ? `calc(100% - 96px)` : '100%',
|
||||
alignItems: 'unset',
|
||||
justifyContent: 'unset',
|
||||
borderRight: currentMode === 'edit' && isRightSidebarOpen && '299' + 'px solid',
|
||||
borderRight: currentMode === 'edit' && isRightSidebarOpen && `300px solid ${canvasBgColor}`,
|
||||
padding: currentMode === 'edit' && '8px',
|
||||
paddingBottom: currentMode === 'edit' && '2px',
|
||||
};
|
||||
|
|
@ -152,15 +158,34 @@ export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode })
|
|||
const shouldAdjust = isSidebarOpen || (isRightSidebarOpen && currentMode === 'edit');
|
||||
|
||||
if (!shouldAdjust) return '';
|
||||
|
||||
let offset;
|
||||
if (isViewerSidebarPinned) {
|
||||
offset = position === 'side' ? '352px' : '126px';
|
||||
if (isViewerSidebarPinned && !isPagesSidebarHidden) {
|
||||
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 {
|
||||
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 (
|
||||
|
|
@ -177,7 +202,7 @@ export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode })
|
|||
'canvas-container d-flex page-container',
|
||||
{ 'dark-theme theme-dark': isAppDarkMode, close: !isViewerSidebarPinned },
|
||||
{ '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
|
||||
)}
|
||||
style={canvasContainerStyles}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
.empty-box-cont{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: unset !important;
|
||||
|
||||
.dotted-cont{
|
||||
border: 1px dashed var(--indigo8);
|
||||
|
|
|
|||
|
|
@ -14,9 +14,13 @@ export const DEFAULT_CANVAS_WIDTH = 1292;
|
|||
|
||||
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'];
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const useSidebarMargin = (canvasContainerRef) => {
|
|||
const { moduleId } = useModuleContext();
|
||||
const [editorMarginLeft, setEditorMarginLeft] = useState(0);
|
||||
const isSidebarOpen = useStore((state) => state.isSidebarOpen, shallow);
|
||||
const isRightSidebarOpen = useStore((state) => state.isRightSidebarOpen, shallow);
|
||||
const mode = useStore((state) => state.modeStore.modules[moduleId].currentMode, shallow);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -17,10 +18,10 @@ const useSidebarMargin = (canvasContainerRef) => {
|
|||
}, [isSidebarOpen, mode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isEmpty(canvasContainerRef?.current)) {
|
||||
if (!isEmpty(canvasContainerRef?.current) && isSidebarOpen && canvasContainerRef.current.scrollLeft === 0) {
|
||||
canvasContainerRef.current.scrollLeft += editorMarginLeft;
|
||||
}
|
||||
}, [editorMarginLeft, canvasContainerRef]);
|
||||
}, [editorMarginLeft, canvasContainerRef, isSidebarOpen]);
|
||||
|
||||
return editorMarginLeft;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ const GlobalSettings = ({ darkMode }) => {
|
|||
</div>
|
||||
<div style={{ padding: '12px 16px' }} className={cx({ disabled: shouldFreeze })}>
|
||||
<MaintenanceMode darkMode={darkMode} />
|
||||
<HideHeaderToggle darkMode={darkMode} />
|
||||
</div>
|
||||
<div className={cx({ 'dark-theme': darkMode })}>
|
||||
<span className="canvas-styles-header">Canvas Styles</span>
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ export const QueryPanel = ({ darkMode }) => {
|
|||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
zIndex: 2,
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -9,17 +9,21 @@ import SolidIcon from '@/_ui/Icon/SolidIcons';
|
|||
export const ComponentConfigurationTab = ({ darkMode, isModuleEditor }) => {
|
||||
const selectedComponentId = useStore((state) => state.selectedComponents?.[0], shallow);
|
||||
const activeTab = useStore((state) => state.activeRightSideBarTab, shallow);
|
||||
const toggleRightSidebarPin = useStore((state) => state.toggleRightSidebarPin);
|
||||
const isRightSidebarPinned = useStore((state) => state.isRightSidebarPinned);
|
||||
const setRightSidebarOpen = useStore((state) => state.setRightSidebarOpen);
|
||||
const setActiveRightSideBarTab = useStore((state) => state.setActiveRightSideBarTab);
|
||||
|
||||
const handleToggle = () => {
|
||||
setActiveRightSideBarTab(null);
|
||||
setRightSidebarOpen(false);
|
||||
};
|
||||
if (!selectedComponentId && activeTab !== RIGHT_SIDE_BAR_TAB.PAGES) {
|
||||
// return setActiveRightSideBarTab(RIGHT_SIDE_BAR_TAB.COMPONENTS);
|
||||
return (
|
||||
<>
|
||||
<div className="empty-configuration-header">
|
||||
<div className="header">Component properties</div>
|
||||
<div className="icon-btn cursor-pointer" onClick={() => toggleRightSidebarPin()}>
|
||||
<SolidIcon fill="var(--icon-strong)" name={isRightSidebarPinned ? 'unpin' : 'pin'} width="16" />
|
||||
<div className="icon-btn cursor-pointer flex-shrink-0 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="d-flex align-items-center justify-content-center no-component-selected">
|
||||
|
|
@ -39,6 +43,7 @@ export const ComponentConfigurationTab = ({ darkMode, isModuleEditor }) => {
|
|||
selectedComponentId={selectedComponentId}
|
||||
pages={[]}
|
||||
isModuleEditor={isModuleEditor}
|
||||
handleRightSidebarToggle={handleToggle}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -74,8 +74,10 @@ export const ComponentsManagerTab = ({ darkMode, isModuleEditor }) => {
|
|||
}
|
||||
}, [hasModuleAccess, activeTab]);
|
||||
|
||||
const toggleRightSidebarPin = useStore((state) => state.toggleRightSidebarPin);
|
||||
const isRightSidebarPinned = useStore((state) => state.isRightSidebarPinned);
|
||||
const setRightSidebarOpen = useStore((state) => state.setRightSidebarOpen);
|
||||
const activeRightSideBarTab = useStore((state) => state.activeRightSideBarTab);
|
||||
const setActiveRightSideBarTab = useStore((state) => state.setActiveRightSideBarTab);
|
||||
const isRightSidebarOpen = useStore((state) => state.isRightSidebarOpen);
|
||||
|
||||
const handleSearchQueryChange = useCallback(
|
||||
debounce((value) => {
|
||||
|
|
@ -88,6 +90,11 @@ export const ComponentsManagerTab = ({ darkMode, isModuleEditor }) => {
|
|||
[activeTab]
|
||||
);
|
||||
|
||||
const handleToggle = () => {
|
||||
setActiveRightSideBarTab(null);
|
||||
setRightSidebarOpen(false);
|
||||
};
|
||||
|
||||
const filterComponents = useCallback((value) => {
|
||||
if (value !== '') {
|
||||
const fuse = new Fuse(componentList, {
|
||||
|
|
@ -223,11 +230,16 @@ export const ComponentsManagerTab = ({ darkMode, isModuleEditor }) => {
|
|||
|
||||
return (
|
||||
<div className={`components-container ${shouldFreeze ? 'disabled' : ''}`}>
|
||||
{isModuleEditor ? (
|
||||
<p className="widgets-manager-header">Components</p>
|
||||
) : (
|
||||
<ComponentModuleTab onChangeTab={handleChangeTab} hasModuleAccess={hasModuleAccess} />
|
||||
)}
|
||||
<div className="d-flex align-items-center">
|
||||
{isModuleEditor ? (
|
||||
<p className="widgets-manager-header">Components</p>
|
||||
) : (
|
||||
<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">
|
||||
<SearchBox
|
||||
dataCy={`widget-search-box`}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,13 @@ const NEW_REVAMPED_COMPONENTS = [
|
|||
'FilePicker',
|
||||
];
|
||||
|
||||
export const Inspector = ({ componentDefinitionChanged, darkMode, pages, selectedComponentId }) => {
|
||||
export const Inspector = ({
|
||||
componentDefinitionChanged,
|
||||
darkMode,
|
||||
pages,
|
||||
selectedComponentId,
|
||||
handleRightSidebarToggle,
|
||||
}) => {
|
||||
const allComponents = useStore((state) => state.getCurrentPageComponents());
|
||||
const setComponentProperty = useStore((state) => state.setComponentProperty, 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>
|
||||
<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
|
||||
data-cy={`inspector-close-icon`}
|
||||
className="cursor-pointer d-flex align-items-center "
|
||||
style={{ height: '28px', width: '28px' }}
|
||||
style={{ height: '28px' }}
|
||||
>
|
||||
<ArrowLeft fill={'var(--slate12)'} width={'14'} />
|
||||
</span>
|
||||
</div>
|
||||
<div className={`col-9 p-0 ${shouldFreeze && 'disabled'}`}>{renderAppNameInput()}</div>
|
||||
<div className={`flex-shrink p-0 width-unset ${shouldFreeze && 'disabled'}`}>{renderAppNameInput()}</div>
|
||||
{!isModuleContainer && (
|
||||
<>
|
||||
<div className="col-2" data-cy={'component-inspector-options'}>
|
||||
<div className="width-unset" data-cy={'component-inspector-options'}>
|
||||
<OverlayTrigger
|
||||
trigger={'click'}
|
||||
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 className={`${shouldFreeze && 'disabled'}`}>{renderTabs()}</div>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export function AddNewPageMenu({ darkMode, isLicensed }) {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="page-type-buttons-container">
|
||||
<div className={`page-type-buttons-container ${darkMode && 'dark-mode'}`}>
|
||||
<Button
|
||||
ref={newPageBtnRef}
|
||||
key="new-page-btn"
|
||||
|
|
@ -54,7 +54,7 @@ export function AddNewPageMenu({ darkMode, isLicensed }) {
|
|||
rootClose
|
||||
onHide={() => setShowMenuPopover(false)}
|
||||
>
|
||||
<Popover id="add-new-page-popover">
|
||||
<Popover className={darkMode && 'darkMode'} id="add-new-page-popover">
|
||||
<div className="menu-options mb-0">
|
||||
<PageOptions
|
||||
type="url"
|
||||
|
|
@ -70,7 +70,7 @@ export function AddNewPageMenu({ darkMode, isLicensed }) {
|
|||
darkMode={darkMode}
|
||||
onClick={() => handleOpenPopup('app')}
|
||||
/>
|
||||
<div className={`d-flex ${!isLicensed && 'disabled licensed-page-option'}`}>
|
||||
<div className={`${!isLicensed && 'd-flex disabled licensed-page-option'}`}>
|
||||
<PageOptions
|
||||
type="group"
|
||||
text="Add nav group"
|
||||
|
|
@ -79,7 +79,7 @@ export function AddNewPageMenu({ darkMode, isLicensed }) {
|
|||
onClick={() => handleOpenPopup('group')}
|
||||
/>
|
||||
<LicenseTooltip
|
||||
message={"App header can't be hidden on free plans"}
|
||||
message={"Nav group can't be created on free plans"}
|
||||
placement="bottom"
|
||||
show={!isLicensed}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -338,22 +338,10 @@ export const AddEditPagePopup = forwardRef(({ darkMode, ...props }, ref) => {
|
|||
type="checkbox"
|
||||
checked={isHomePage}
|
||||
onChange={() => markAsHomePage(page?.id)}
|
||||
disabled={isHomePage}
|
||||
disabled={isHomePage || resolveReferences(page?.hidden?.value) || page?.disabled}
|
||||
/>
|
||||
</label>
|
||||
</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
|
||||
hidden={page?.hidden}
|
||||
page={page}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export default function IconSelector({ iconName, iconColor, pageId, iconStyles,
|
|||
};
|
||||
|
||||
// eslint-disable-next-line import/namespace
|
||||
const IconElement = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
|
||||
const IconElement = Icons?.[iconName] ?? Icons?.['IconFile'];
|
||||
|
||||
return (
|
||||
<OverlayTrigger
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/* eslint-disable import/namespace */
|
||||
import React, { useRef, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import _ from 'lodash';
|
||||
import * as Icons from '@tabler/icons-react';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
|
|
@ -26,12 +26,13 @@ export const RenderPage = ({
|
|||
isSidebarPinned,
|
||||
callback,
|
||||
position,
|
||||
onPageClick,
|
||||
}) => {
|
||||
const currentMode = useStore((state) => state.currentMode);
|
||||
const isHomePage = page.id === homePageId;
|
||||
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
||||
const IconElement = (props) => {
|
||||
const Icon = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
|
||||
const Icon = Icons?.[iconName] ?? Icons?.['IconFile'];
|
||||
|
||||
if (!isSidebarPinned || labelStyle?.label?.hidden) {
|
||||
return (
|
||||
|
|
@ -59,7 +60,7 @@ export const RenderPage = ({
|
|||
key={page.handle}
|
||||
onClick={() => {
|
||||
switchPageWrapper(page);
|
||||
callback && position !== 'side' && callback();
|
||||
position !== 'side' && onPageClick();
|
||||
}}
|
||||
selectedItem={page?.id === currentPageId}
|
||||
CustomIcon={!labelStyle?.icon?.hidden && IconElement}
|
||||
|
|
@ -67,14 +68,15 @@ export const RenderPage = ({
|
|||
darkMode={darkMode}
|
||||
>
|
||||
{!labelStyle?.label?.hidden && (
|
||||
<span
|
||||
<div
|
||||
style={{ position: 'relative', overflow: 'hidden' }}
|
||||
// className={isSelected && 'tj-list-item-selected'}
|
||||
data-cy={`pages-name-${String(page?.name).toLowerCase()}`}
|
||||
>
|
||||
<OverflowTooltip style={{ width: '110px', position: 'relative' }} childrenClassName={'page-name'}>
|
||||
{page.name}
|
||||
</OverflowTooltip>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</FolderList>
|
||||
</div>
|
||||
|
|
@ -94,12 +96,15 @@ const RenderPageGroup = ({
|
|||
linkRefs,
|
||||
isSidebarPinned,
|
||||
position,
|
||||
isExpanded,
|
||||
onToggle,
|
||||
onPageClick,
|
||||
}) => {
|
||||
const currentMode = useStore((state) => state.currentMode);
|
||||
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const contentRef = useRef(null);
|
||||
const groupItemRootRef = useRef(null);
|
||||
|
||||
const IconElement = (props) => {
|
||||
const Icon = Icons?.[pageGroup.icon] ?? Icons?.['IconHome2'];
|
||||
|
|
@ -116,9 +121,25 @@ const RenderPageGroup = ({
|
|||
};
|
||||
|
||||
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) {
|
||||
return (
|
||||
<>
|
||||
|
|
@ -133,6 +154,8 @@ const RenderPageGroup = ({
|
|||
darkMode={darkMode}
|
||||
homePageId={homePageId}
|
||||
position={position}
|
||||
callback={handleToggle}
|
||||
onPageClick={onPageClick}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
|
|
@ -145,7 +168,12 @@ const RenderPageGroup = ({
|
|||
<div
|
||||
key={pageGroup.name}
|
||||
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' : ''}`}
|
||||
>
|
||||
<div
|
||||
|
|
@ -153,40 +181,31 @@ const RenderPageGroup = ({
|
|||
style={{
|
||||
position: 'relative',
|
||||
}}
|
||||
onClick={isSidebarPinned && handleToggle}
|
||||
>
|
||||
<FolderList
|
||||
key={pageGroup.id}
|
||||
onClick={isSidebarPinned && handleToggle}
|
||||
CustomIcon={!labelStyle?.icon?.hidden && IconElement}
|
||||
customStyles={computeStyles}
|
||||
darkMode={darkMode}
|
||||
hovered={hovered}
|
||||
>
|
||||
{!labelStyle?.label?.hidden && (
|
||||
<span data-cy={`pages-name-${String(pageGroup?.name).toLowerCase()}`}>
|
||||
<OverflowTooltip style={{ width: '110px' }} childrenClassName={'page-name'}>
|
||||
{pageGroup.name}
|
||||
</OverflowTooltip>
|
||||
</span>
|
||||
<div
|
||||
style={{ position: 'relative', overflow: 'hidden' }}
|
||||
data-cy={`pages-name-${String(pageGroup?.name).toLowerCase()}`}
|
||||
>
|
||||
<OverflowTooltip childrenClassName={'page-name'}>{pageGroup.name}</OverflowTooltip>
|
||||
</div>
|
||||
)}
|
||||
</FolderList>
|
||||
<div style={{ marginRight: '12px' }}>
|
||||
<svg
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
onClick={handleToggle}
|
||||
className={`page-group-collapse ${isExpanded ? 'expanded' : 'collapsed'}`}
|
||||
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 className="icon-btn cursor-pointer flex-shrink-0">
|
||||
<SolidIcon
|
||||
fill="var(--icon-default)"
|
||||
name={isExpanded ? 'caretup' : 'caretdown'}
|
||||
width="16"
|
||||
viewBox="0 0 16 16"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -205,6 +224,7 @@ const RenderPageGroup = ({
|
|||
linkRefs={linkRefs}
|
||||
callback={handleToggle}
|
||||
position={position}
|
||||
onPageClick={onPageClick}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -228,6 +248,7 @@ export const RenderPageAndPageGroup = ({
|
|||
isSidebarPinned,
|
||||
}) => {
|
||||
const { moduleId } = useModuleContext();
|
||||
const [expandedPageGroupId, setExpandedPageGroupId] = useState(null);
|
||||
// Don't render empty folders if displaying only icons
|
||||
const visibleTree = buildTree(position === 'top' ? visibleLinks : pages, !!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 homePageId = useStore((state) => state.appStore.modules[moduleId].app.homePageId);
|
||||
const [showPopover, setShowPopover] = useState(false);
|
||||
|
||||
const handleAccordionToggle = (groupId) => {
|
||||
setExpandedPageGroupId((prevId) => (prevId === groupId ? null : groupId));
|
||||
};
|
||||
|
||||
const closeAllAccordions = () => {
|
||||
if (showPopover) {
|
||||
setShowPopover(false);
|
||||
}
|
||||
setExpandedPageGroupId(null);
|
||||
};
|
||||
return (
|
||||
<div className={cx('page-handler-wrapper viewer', { 'dark-theme': darkMode })}>
|
||||
{/* <Accordion alwaysOpen defaultActiveKey={tree.map((page) => page.id)}> */}
|
||||
|
|
@ -273,6 +305,9 @@ export const RenderPageAndPageGroup = ({
|
|||
linkRefs={linkRefs}
|
||||
isSidebarPinned={isSidebarPinned}
|
||||
position={position}
|
||||
isExpanded={expandedPageGroupId === page.id}
|
||||
onToggle={handleAccordionToggle}
|
||||
onPageClick={closeAllAccordions}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
@ -290,6 +325,7 @@ export const RenderPageAndPageGroup = ({
|
|||
linkRefs={linkRefs}
|
||||
isSidebarPinned={isSidebarPinned}
|
||||
position={position}
|
||||
onPageClick={closeAllAccordions}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -299,10 +335,11 @@ export const RenderPageAndPageGroup = ({
|
|||
<button
|
||||
ref={moreBtnRef}
|
||||
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' }}
|
||||
>
|
||||
<SolidIcon fill={'var(--icon-weak)'} viewBox="0 3 21 18" width="16px" name="morevertical" />
|
||||
|
||||
<div style={{ marginLeft: '6px' }}>More</div>
|
||||
</button>
|
||||
|
||||
|
|
@ -344,6 +381,9 @@ export const RenderPageAndPageGroup = ({
|
|||
darkMode={darkMode}
|
||||
linkRefs={linkRefs}
|
||||
isSidebarPinned={isSidebarPinned}
|
||||
isExpanded={expandedPageGroupId === page.id}
|
||||
onToggle={handleAccordionToggle}
|
||||
onPageClick={closeAllAccordions}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
@ -360,6 +400,7 @@ export const RenderPageAndPageGroup = ({
|
|||
homePageId={homePageId}
|
||||
linkRefs={linkRefs}
|
||||
isSidebarPinned={isSidebarPinned}
|
||||
onPageClick={closeAllAccordions}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ export const PageGroupItem = memo(({ page, index, collapsed, onCollapse, highlig
|
|||
>
|
||||
<div
|
||||
className={`page-menu-item page-group-item ${highlight ? 'highlight' : ''} ${darkMode ? 'dark-theme' : ''} ${
|
||||
showPageOptions && isEditing ? 'is-selected' : ''
|
||||
(showPageOptions || showEditPopover) && isEditing ? 'is-selected' : ''
|
||||
}`}
|
||||
onClick={() => {
|
||||
handleOpenPopup('group', page);
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ export const PageMenuItem = withRouter(
|
|||
const icon = (props) => {
|
||||
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
||||
// eslint-disable-next-line import/namespace
|
||||
const Icon = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
|
||||
const Icon = Icons?.[iconName] ?? Icons?.['IconFile'];
|
||||
|
||||
return (
|
||||
<Icon {...props} style={{ width: '16px', height: '16px', color: 'var(--icons-default)', marginRight: '6px' }} />
|
||||
|
|
@ -269,7 +269,6 @@ export const PageMenuItem = withRouter(
|
|||
|
||||
return '';
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
|
|
@ -281,7 +280,7 @@ export const PageMenuItem = withRouter(
|
|||
<>
|
||||
<div
|
||||
className={`page-menu-item ${darkMode && 'dark-theme'} ${
|
||||
showPageOptions && isEditingPage ? 'is-selected' : ''
|
||||
showPageOptions || showEditingPopover || isEditingPage ? 'is-selected' : ''
|
||||
}`}
|
||||
style={{
|
||||
position: 'relative',
|
||||
|
|
@ -308,14 +307,14 @@ export const PageMenuItem = withRouter(
|
|||
<>
|
||||
{' '}
|
||||
<div ref={optionBtnRef} className="left" data-cy={`pages-name-${page.name.toLowerCase()}`}>
|
||||
{icon()}
|
||||
<OverflowTooltip childrenClassName="page-name" style={{ ...computedStyles?.text, maxWidth: '159px' }}>
|
||||
<div className="main-page-icon-wrapper">{icon()}</div>
|
||||
<OverflowTooltip childrenClassName="page-name" style={{ ...computedStyles?.text }}>
|
||||
{page.name}
|
||||
</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">
|
||||
{PAGE_TYPES[page?.type] && ( // If 'page' object has a 'type' property like 'URL'
|
||||
<span className="page-type-text">{PAGE_TYPES[page?.type]}</span>
|
||||
)}
|
||||
{isHomePage && (
|
||||
<ToolTip message="Home page" placement="bottom">
|
||||
<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 editingPage = useStore((state) => state.editingPage);
|
||||
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 selectedUsers = useStore((state) => state.selectedUsers);
|
||||
const selectedUsers = useStore((state) => state.appPermission.selectedUsers);
|
||||
const setSelectedUsers = useStore((state) => state.setSelectedUsers);
|
||||
const pagePermission = useStore((state) => state.pagePermission);
|
||||
const setPagePermission = useStore((state) => state.setPagePermission);
|
||||
|
|
@ -353,7 +353,7 @@ export default function PagePermission({ darkMode }) {
|
|||
const UserGroupSelect = () => {
|
||||
const { moduleId } = useModuleContext();
|
||||
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 [userGroups, setUserGroups] = useState([]);
|
||||
useEffect(() => {
|
||||
|
|
@ -415,7 +415,7 @@ const UserSelect = () => {
|
|||
const { moduleId } = useModuleContext();
|
||||
const appId = useStore((state) => state.appStore.modules[moduleId].app.appId);
|
||||
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 [users, setUsers] = useState([]);
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export const PagesSidebarNavigation = ({
|
|||
const { moduleId } = useModuleContext();
|
||||
const { definition: { styles = {}, properties = {} } = {} } = useStore((state) => state.pageSettings) || {};
|
||||
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 homePageId = useStore((state) => state.appStore.modules[moduleId].app.homePageId);
|
||||
const license = useStore((state) => state.license);
|
||||
|
|
@ -266,6 +266,10 @@ export const PagesSidebarNavigation = ({
|
|||
const headerHidden = isLicensed ? hideHeader : false;
|
||||
const isPagesSidebarHidden = resolveReferences(disableMenu?.value);
|
||||
|
||||
if (hideHeader && hideLogo && isPagesSidebarHidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button
|
||||
|
|
@ -297,58 +301,60 @@ export const PagesSidebarNavigation = ({
|
|||
ref={navRef}
|
||||
className={cx('navigation-area', {
|
||||
close: !isSidebarPinned && properties?.collapsable && style !== 'text' && position === 'side',
|
||||
// 'sidebar-overlay': !isSidebarPinned && properties?.collapsable,
|
||||
'icon-only': style === 'icon' || (style === 'texticon' && !isSidebarPinned && position === 'side'),
|
||||
'position-top': position === 'top',
|
||||
'position-top': position === 'top' || isPagesSidebarHidden,
|
||||
'text-only': style === 'text',
|
||||
'right-sidebar-open': isRightSidebarOpen && position === 'top',
|
||||
'left-sidebar-open': isSidebarOpen && position === 'top',
|
||||
'right-sidebar-open': isRightSidebarOpen && (position === 'top' || isPagesSidebarHidden),
|
||||
'left-sidebar-open': isSidebarOpen && (position === 'top' || isPagesSidebarHidden),
|
||||
})}
|
||||
style={{
|
||||
width: 226,
|
||||
position: 'sticky',
|
||||
// height: `calc(100% - ${showHeader ? APP_HEADER_HEIGHT : 0}px)`,
|
||||
// height,
|
||||
height: '100%',
|
||||
// top: showHeader ? '47px' : '0px',
|
||||
height: currentMode === 'edit' ? '100%' : `calc(100% - 32px)`,
|
||||
top: '4px',
|
||||
bottom: '0px',
|
||||
background: !styles?.backgroundColor?.isDefault && styles?.backgroundColor?.value,
|
||||
border: `${styles?.pillRadius?.value}px`,
|
||||
borderRight: !styles?.borderColor?.isDefault ? `1px solid ${styles?.borderColor?.value}` : '',
|
||||
borderTop: !styles?.borderColor?.isDefault ? `1px solid ${styles?.borderColor?.value}` : '',
|
||||
borderRight:
|
||||
!styles?.borderColor?.isDefault && position === 'side' ? `1px solid ${styles?.borderColor?.value}` : '',
|
||||
borderBottom:
|
||||
!styles?.borderColor?.isDefault && position === 'top' ? `1px solid ${styles?.borderColor?.value}` : '',
|
||||
overflow: 'scroll',
|
||||
boxShadow: 'var(--elevation-100-box-shadow)',
|
||||
scrollbarWidth: 'none',
|
||||
// ...(position === 'side' && isSidebarOpen ? { marginLeft: isSidebarPinned ? '574px' : '392px' } : {}),
|
||||
}}
|
||||
>
|
||||
<div className="position-relative">
|
||||
<div
|
||||
style={{
|
||||
marginRight: headerHidden && position == 'top' && '0px',
|
||||
}}
|
||||
className="app-name"
|
||||
>
|
||||
{!hideLogo && (
|
||||
<div onClick={switchToHomePage} className="cursor-pointer">
|
||||
<AppLogo isLoadingFromHeader={false} />
|
||||
</div>
|
||||
)}
|
||||
{!headerHidden && ((isPinnedWithLabel && !labelHidden) || position === 'top') && (
|
||||
<span>{name?.trim() ? name : appName}</span>
|
||||
)}
|
||||
{collapsable && !isTopPositioned && style == 'texticon' && position === 'side' && (
|
||||
<div onClick={toggleSidebarPinned} className="icon-btn collapse-icon ">
|
||||
<SolidIcon
|
||||
className="cursor-pointer"
|
||||
fill="var(--icon-strong)"
|
||||
width="14px"
|
||||
name={isSidebarPinned ? 'remove03' : 'menu'}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ overflow: 'hidden' }} className="position-relative">
|
||||
{(collapsable || !headerHidden || !hideLogo) && (
|
||||
<div
|
||||
style={{
|
||||
marginRight: hideHeader && hideLogo && position == 'top' && '0px',
|
||||
}}
|
||||
className="app-name"
|
||||
>
|
||||
{!hideLogo && (
|
||||
<div onClick={switchToHomePage} className="cursor-pointer flex-shrink-0">
|
||||
<AppLogo isLoadingFromHeader={false} />
|
||||
</div>
|
||||
)}
|
||||
{!headerHidden && ((isPinnedWithLabel && !labelHidden) || position === 'top') && (
|
||||
<OverflowTooltip>{name?.trim() ? name : appName}</OverflowTooltip>
|
||||
)}
|
||||
{collapsable &&
|
||||
!isTopPositioned &&
|
||||
style == 'texticon' &&
|
||||
position === 'side' &&
|
||||
!isPagesSidebarHidden && (
|
||||
<div onClick={toggleSidebarPinned} className="icon-btn collapse-icon ">
|
||||
<SolidIcon
|
||||
className="cursor-pointer"
|
||||
fill="var(--icon-strong)"
|
||||
width="14px"
|
||||
name={isSidebarPinned ? 'remove03' : 'menu'}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{isLicensed && !isPagesSidebarHidden ? (
|
||||
<RenderPageAndPageGroup
|
||||
switchPageWrapper={switchPageWrapper}
|
||||
|
|
@ -414,12 +420,13 @@ const RenderPagesWithoutGroup = ({
|
|||
moreBtnRef,
|
||||
}) => {
|
||||
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
|
||||
);
|
||||
const filteredPagesOverflow = overflowLinks.filter(
|
||||
(page) => (!page?.isPageGroup || page.children?.length > 0) && !page?.restricted
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={cx('page-handler-wrapper', { 'dark-theme': darkMode })}>
|
||||
{filteredPagesVisible.map((page) => {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@
|
|||
align-items: center;
|
||||
padding: 7px 8px;
|
||||
margin-top: 2px;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
background-color: var(--interactive-default);
|
||||
&.highlight {
|
||||
|
|
@ -112,6 +113,8 @@
|
|||
line-height: 18px;
|
||||
margin-left: 8px;
|
||||
gap: 6px;
|
||||
flex-shrink: 0;
|
||||
margin-right: 6px;
|
||||
}
|
||||
button.edit-page-overlay-toggle{
|
||||
opacity: 0;
|
||||
|
|
@ -134,13 +137,23 @@
|
|||
// margin-left: 15px;
|
||||
display: flex;
|
||||
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{
|
||||
overflow: hidden;
|
||||
color: var(--slate12);
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
max-width: 246px;
|
||||
flex-shrink: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -410,8 +423,9 @@
|
|||
}
|
||||
|
||||
.licensed-page-option {
|
||||
pointer-events: unset !important;
|
||||
button {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
&:hover {
|
||||
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-empty-events {
|
||||
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 useStore from '@/AppBuilder/_stores/store';
|
||||
import ArrowLeft from '@/_ui/Icon/solidIcons/ArrowLeft';
|
||||
|
|
@ -45,7 +45,12 @@ export const PageSettings = () => {
|
|||
const isVersionReleased = useStore((state) => state.isVersionReleased);
|
||||
const switchPage = useStore((state) => state.switchPage);
|
||||
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 license = useStore((state) => state.license);
|
||||
|
|
@ -161,10 +166,12 @@ export const PageSettings = () => {
|
|||
<div className="inspector pages-settings">
|
||||
<div>
|
||||
<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="icon-btn cursor-pointer" onClick={() => toggleRightSidebarPin()}>
|
||||
<SolidIcon fill="var(--icon-strong)" name={isRightSidebarPinned ? 'unpin' : 'pin'} width="16" />
|
||||
<div className="icon-btn cursor-pointer flex-shrink-0 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>
|
||||
|
|
@ -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 [appName] = useStore((state) => [state.appStore.modules[moduleId].app.appName], shallow);
|
||||
|
||||
const { definition: { properties = {} } = {} } = pageSettings ?? {};
|
||||
const { hideHeader, name, hideLogo } = properties ?? {};
|
||||
|
||||
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 (
|
||||
<>
|
||||
|
|
@ -279,14 +324,17 @@ const AppHeaderMenu = ({ darkMode, pageSettings, pageSettingChanged, licenseVali
|
|||
<label className="form-label font-weight-400 mb-0">Title</label>
|
||||
<input
|
||||
type="text"
|
||||
onBlur={(e) => {
|
||||
pageSettingChanged({ name: e.target.value }, 'properties');
|
||||
}}
|
||||
onChange={(e) => _setName(e.target.value)}
|
||||
className="form-control"
|
||||
onBlur={handleNameBlur}
|
||||
onChange={handleNameChange}
|
||||
className={`form-control ${error ? 'is-invalid' : ''}`}
|
||||
value={_name}
|
||||
minLength="1"
|
||||
maxLength={32}
|
||||
/>
|
||||
{error && (
|
||||
<div className="invalid-feedback" style={{ display: 'block' }}>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
|
@ -318,6 +366,8 @@ const NavigationMenu = ({ darkMode, pageSettings, pageSettingChanged }) => {
|
|||
return str.toLowerCase() === 'true';
|
||||
}
|
||||
|
||||
const [selectedStyle, setSelectedStyle] = useState(style);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="section-header pb-2">
|
||||
|
|
@ -357,6 +407,7 @@ const NavigationMenu = ({ darkMode, pageSettings, pageSettingChanged }) => {
|
|||
pageSettingChanged({ position: value }, 'properties');
|
||||
}}
|
||||
defaultValue={position?.toString()}
|
||||
style={{ width: '168px' }}
|
||||
>
|
||||
{POSTIONS.map((mode) => (
|
||||
<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>
|
||||
<Select
|
||||
options={styleOptions}
|
||||
search={true}
|
||||
value={style}
|
||||
value={selectedStyle}
|
||||
onChange={(value) => {
|
||||
setSelectedStyle(value);
|
||||
pageSettingChanged({ style: value }, 'properties');
|
||||
}}
|
||||
placeholder={'Select...'}
|
||||
useMenuPortal={false}
|
||||
width={'142px'}
|
||||
width={'168px'}
|
||||
className={`${darkMode ? 'select-search-dark' : 'select-search'}`}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -389,12 +440,10 @@ const NavigationMenu = ({ darkMode, pageSettings, pageSettingChanged }) => {
|
|||
<div className="ms-auto position-relative app-mode-switch" style={{ paddingLeft: '0px' }}>
|
||||
<ToggleGroup
|
||||
onValueChange={(value) => {
|
||||
// if (position === 'side' && value == 'false') {
|
||||
// pageSettingChanged({ style: 'texticon' }, 'properties');
|
||||
// }
|
||||
pageSettingChanged({ collapsable: stringToBoolean(value) }, 'properties');
|
||||
}}
|
||||
defaultValue={collapsable?.toString()}
|
||||
style={{ width: '168px' }}
|
||||
>
|
||||
{COLLAPSABLE_TOGGLES.map((mode) => (
|
||||
<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 { ComponentConfigurationTab } from './ComponentConfigurationTab';
|
||||
import ComponentsManagerTab from './ComponentManagerTab';
|
||||
|
|
@ -8,14 +8,29 @@ import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext';
|
|||
|
||||
export const RightSideBar = ({ darkMode }) => {
|
||||
const { isModuleEditor } = useModuleContext();
|
||||
const queryPanelHeight = useStore((state) => state.queryPanel.queryPanelHeight);
|
||||
const isDraggingQueryPane = useStore((state) => state.queryPanel.isDraggingQueryPane);
|
||||
|
||||
const activeTab = useStore((state) => state.activeRightSideBarTab);
|
||||
const isRightSidebarOpen = useStore((state) => state.isRightSidebarOpen);
|
||||
const setRightSidebarOpen = useStore((state) => state.setRightSidebarOpen);
|
||||
const isRightSidebarPinned = useStore((state) => state.isRightSidebarPinned);
|
||||
const setActiveRightSideBarTab = useStore((state) => state.setActiveRightSideBarTab);
|
||||
const [popoverContentHeight, setPopoverContentHeight] = useState(queryPanelHeight);
|
||||
|
||||
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(() => {
|
||||
// const rigthSidebarMenu = document.querySelector('.right-sidebar-toggle');
|
||||
// function handleClickOutside(event) {
|
||||
|
|
@ -40,7 +55,10 @@ export const RightSideBar = ({ darkMode }) => {
|
|||
|
||||
return (
|
||||
<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%' }}>
|
||||
{activeTab === 'pages' && <PageSettings />}
|
||||
{activeTab === 'components' && <ComponentsManagerTab darkMode={darkMode} isModuleEditor={isModuleEditor} />}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ const RightSidebarToggle = ({ darkMode = false }) => {
|
|||
handleToggle(RIGHT_SIDE_BAR_TAB.CONFIGURATION);
|
||||
}}
|
||||
darkMode={darkMode}
|
||||
icon="inspect"
|
||||
icon="propertiesstyles"
|
||||
iconWidth="14"
|
||||
className={`left-sidebar-item left-sidebar-layout left-sidebar-inspector`}
|
||||
tip="Component properties"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,26 +1,39 @@
|
|||
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
||||
import React, { forwardRef } from 'react';
|
||||
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
|
||||
import Tooltip from 'react-bootstrap/Tooltip';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ToolTip } from '@/_components';
|
||||
|
||||
// TODO: remove refs and related dependancies
|
||||
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;
|
||||
return (
|
||||
<div {...rest} className={className} onClick={onClick && onClick} ref={ref}>
|
||||
{icon && (
|
||||
<div
|
||||
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>
|
||||
)}
|
||||
<p>{text && t(`leftSidebar.${text}.text`, text)}</p>
|
||||
</div>
|
||||
<ToolTip placement="left" message={tip}>
|
||||
<div {...rest} className={className} onClick={onClick && onClick} ref={ref}>
|
||||
{icon && (
|
||||
<div
|
||||
className={`sidebar-svg-icon position-relative ${selectedSidebarItem && 'sidebar-item'}`}
|
||||
data-cy={`right-sidebar-${icon.toLowerCase()}-button`}
|
||||
>
|
||||
<SolidIcon name={displayIcon} width={iconWidth} fill={selectedSidebarItem ? '#3E63DD' : iconFill} />
|
||||
</div>
|
||||
)}
|
||||
<p></p>
|
||||
</div>
|
||||
</ToolTip>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { redirectToDashboard } from '@/_helpers/routes';
|
|||
import AppLogo from '@/_components/AppLogo';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext';
|
||||
import OverflowTooltip from '@/_components/OverflowTooltip';
|
||||
|
||||
const RenderGroup = ({ pages, pageGroup, currentPage, darkMode, handlepageSwitch, currentPageId, icon }) => {
|
||||
const { moduleId } = useModuleContext();
|
||||
|
|
@ -23,7 +24,7 @@ const RenderGroup = ({ pages, pageGroup, currentPage, darkMode, handlepageSwitch
|
|||
setIsExpanded(!isExpanded);
|
||||
};
|
||||
// eslint-disable-next-line import/namespace
|
||||
const IconElement = Icons?.[pageGroup?.icon] ?? Icons?.['IconFileDescription'];
|
||||
const IconElement = Icons?.[pageGroup?.icon] ?? Icons?.['IconFile'];
|
||||
return (
|
||||
<>
|
||||
<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 iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
||||
// eslint-disable-next-line import/namespace
|
||||
const IconElement = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
|
||||
const IconElement = Icons?.[iconName] ?? Icons?.['IconFile'];
|
||||
return page?.hidden || page?.disabled ? null : (
|
||||
<div
|
||||
key={page.handle}
|
||||
|
|
@ -107,7 +108,7 @@ const RenderPageGroups = ({ pages, handlepageSwitch, darkMode, currentPageId, cu
|
|||
const isHomePage = page.id === homePageId;
|
||||
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
||||
// eslint-disable-next-line import/namespace
|
||||
const IconElement = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
|
||||
const IconElement = Icons?.[iconName] ?? Icons?.['IconFile'];
|
||||
return page?.hidden || page?.disabled ? null : (
|
||||
<div
|
||||
key={page.handle}
|
||||
|
|
@ -187,6 +188,7 @@ const MobileNavigationMenu = ({
|
|||
display: 'inline-block',
|
||||
padding: '0.5rem 0rem',
|
||||
width: '100%',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
bmOverlay: {
|
||||
background: 'rgba(0, 0, 0, 0.3)',
|
||||
|
|
@ -242,7 +244,7 @@ const MobileNavigationMenu = ({
|
|||
{!hideLogo && <AppLogo isLoadingFromHeader={false} viewer={true} />}
|
||||
{!hideHeader && (
|
||||
<div className="d-flex align-items-center app-title">
|
||||
<span>{name?.trim() ? name : appName}</span>
|
||||
<OverflowTooltip>{name?.trim() ? name : appName}</OverflowTooltip>
|
||||
</div>
|
||||
)}
|
||||
</Link>
|
||||
|
|
@ -250,7 +252,7 @@ const MobileNavigationMenu = ({
|
|||
</div>
|
||||
</Header>
|
||||
|
||||
<div className="w-100">
|
||||
<div style={{ paddingBottom: '48px' }} className="w-100 overflow-auto h-100">
|
||||
<div className={`pages-container ${darkMode && 'dark'}`}>
|
||||
{isLicensed ? (
|
||||
<RenderPageGroups
|
||||
|
|
@ -265,7 +267,7 @@ const MobileNavigationMenu = ({
|
|||
const isHomePage = page.id === homePageId;
|
||||
const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
|
||||
// eslint-disable-next-line import/namespace
|
||||
const IconElement = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
|
||||
const IconElement = Icons?.[iconName] ?? Icons?.['IconFile'];
|
||||
return page?.hidden || page?.disabled ? null : (
|
||||
<div
|
||||
key={page.handle}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@ import Popups from '../Popups';
|
|||
import { ModuleProvider } from '@/AppBuilder/_contexts/ModuleContext';
|
||||
import { getPatToken, setPatToken } from '@/AppBuilder/EmbedApp';
|
||||
import Spinner from '@/_ui/Spinner';
|
||||
import { checkIfLicenseNotValid } from '@/_helpers/appUtils';
|
||||
import toast from 'react-hot-toast';
|
||||
import TooljetBanner from '../../Editor/Viewer/TooljetBanner';
|
||||
|
||||
export const Viewer = ({
|
||||
id: appId,
|
||||
|
|
@ -107,15 +109,13 @@ export const Viewer = ({
|
|||
const { position, hideHeader } = properties ?? {};
|
||||
|
||||
const canvasRef = useRef(null);
|
||||
const isLoading = false;
|
||||
const isMobilePreviewMode = selectedVersion?.id && currentLayout === 'mobile';
|
||||
const isAppLoaded = !!editingVersion;
|
||||
const isMobileDevice = deviceWindowWidth < 600;
|
||||
const switchPage = useStore((state) => state.switchPage);
|
||||
|
||||
const showHeader = !globalSettings?.hideHeader && isAppLoaded;
|
||||
const isLicenseValid = useStore((state) => state.isLicenseValid);
|
||||
const licenseValid = isLicenseValid();
|
||||
const isLicenseNotValid = checkIfLicenseNotValid();
|
||||
|
||||
// ---remove
|
||||
const handleAppEnvironmentChanged = useCallback((environment) => {
|
||||
console.log('setAppVersionCurrentEnvironment', environment);
|
||||
|
|
@ -229,19 +229,6 @@ export const Viewer = ({
|
|||
}}
|
||||
>
|
||||
<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
|
||||
className={cx('flex-grow-1 d-flex justify-content-center canvas-box', {
|
||||
close: !isSidebarPinned,
|
||||
|
|
@ -292,6 +279,7 @@ export const Viewer = ({
|
|||
darkMode={darkMode}
|
||||
/>
|
||||
</div>
|
||||
{isLicenseNotValid && isAppLoaded && <TooljetBanner isDarkMode={darkMode} />}
|
||||
{isMobilePreviewMode && <div className="hide-drawer-transition" style={{ right: 0 }}></div>}
|
||||
{isMobilePreviewMode && <div className="hide-drawer-transition" style={{ left: 0 }}></div>}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@
|
|||
.mobile-nav-container {
|
||||
.header-container {
|
||||
background-color: unset !important;
|
||||
flex-wrap: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1557,7 +1557,6 @@ export const createComponentsSlice = (set, get) => ({
|
|||
!selectedText
|
||||
) {
|
||||
clearSelectedComponents();
|
||||
setActiveRightSideBarTab(RIGHT_SIDE_BAR_TAB.COMPONENTS);
|
||||
// if (!isRightSidebarPinned) {
|
||||
// setRightSidebarOpen(false);
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -119,14 +119,7 @@ export const createPageMenuSlice = (set, get) => {
|
|||
state.showSearch = show;
|
||||
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) =>
|
||||
set((state) => {
|
||||
state.newPagePopupConfig = {
|
||||
|
|
@ -134,14 +127,6 @@ export const createPageMenuSlice = (set, get) => {
|
|||
...config,
|
||||
};
|
||||
}),
|
||||
closePageEditPopover: () =>
|
||||
set((state) => {
|
||||
state.showEditingPopover = false;
|
||||
state.showEditPageEventsModal = false;
|
||||
state.showRenamePageHandleModal = false;
|
||||
state.showEditPageNameInput = false;
|
||||
state.showDeleteConfirmationModal = false;
|
||||
}),
|
||||
|
||||
toggleEditPageHandleModal: (show) =>
|
||||
set((state) => {
|
||||
|
|
@ -481,5 +466,28 @@ export const createPageMenuSlice = (set, get) => {
|
|||
set((state) => {
|
||||
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 { id, handle } = e.state;
|
||||
switchPage(id, handle, [], true);
|
||||
switchPage(id, handle, []);
|
||||
};
|
||||
|
||||
return <RouteLoader isLoading={isLoading}>{clonedElement}</RouteLoader>;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ export const DarkModeToggle = function DarkModeToggle({
|
|||
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({
|
||||
transform,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState, useCallback } from 'react';
|
||||
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({
|
||||
children,
|
||||
className,
|
||||
|
|
@ -10,21 +19,44 @@ export default function OverflowTooltip({
|
|||
maxLetters,
|
||||
...rest
|
||||
}) {
|
||||
const [isOverflowed, setIsOverflow] = useState(false);
|
||||
const textElementRef = useRef();
|
||||
const [isOverflowed, setIsOverflowed] = useState(false);
|
||||
const textContentRef = useRef(null);
|
||||
|
||||
const checkOverflow = useCallback(() => {
|
||||
if (textContentRef.current) {
|
||||
setIsOverflowed(isTextOverflowing(textContentRef.current));
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setIsOverflow(
|
||||
textElementRef.current.scrollWidth > textElementRef.current.clientWidth ||
|
||||
textElementRef.current.clientHeight < textElementRef.current.scrollHeight - 4
|
||||
);
|
||||
}, [children, boxWidth]);
|
||||
const currentTextElement = textContentRef.current;
|
||||
if (!currentTextElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkOverflow();
|
||||
|
||||
const observer = new ResizeObserver((entries) => {
|
||||
checkOverflow();
|
||||
});
|
||||
|
||||
observer.observe(currentTextElement);
|
||||
|
||||
return () => {
|
||||
observer.unobserve(currentTextElement);
|
||||
observer.disconnect();
|
||||
};
|
||||
}, [children, checkOverflow]);
|
||||
|
||||
const displayText =
|
||||
maxLetters && typeof children === 'string' && children.length > maxLetters
|
||||
? `${children.substring(0, maxLetters)}...`
|
||||
: children;
|
||||
|
||||
useEffect(() => {
|
||||
checkOverflow();
|
||||
}, [maxLetters, checkOverflow]);
|
||||
|
||||
return (
|
||||
<ToolTip
|
||||
className={className}
|
||||
|
|
@ -36,7 +68,7 @@ export default function OverflowTooltip({
|
|||
width={rest?.width}
|
||||
>
|
||||
<div
|
||||
ref={textElementRef}
|
||||
ref={textContentRef}
|
||||
className={rest.childrenClassName}
|
||||
style={{
|
||||
whiteSpace,
|
||||
|
|
|
|||
|
|
@ -1106,42 +1106,42 @@ export function previewQuery(_ref, query, calledFromQuery = false, userSuppliedP
|
|||
queryStatusCode === 400 ||
|
||||
queryStatusCode === 404 ||
|
||||
queryStatusCode === 422: {
|
||||
let errorData = {};
|
||||
switch (query.kind) {
|
||||
case 'runpy':
|
||||
errorData = data.data;
|
||||
break;
|
||||
case 'tooljetdb':
|
||||
if (data?.error) {
|
||||
errorData = {
|
||||
message: data?.error?.message || 'Something went wrong',
|
||||
description: data?.error?.message || 'Something went wrong',
|
||||
status: data?.statusText || 'Failed',
|
||||
data: data?.error || {},
|
||||
};
|
||||
} else {
|
||||
errorData = data;
|
||||
errorData.description = data.errorMessage || 'Something went wrong';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
let errorData = {};
|
||||
switch (query.kind) {
|
||||
case 'runpy':
|
||||
errorData = data.data;
|
||||
break;
|
||||
case 'tooljetdb':
|
||||
if (data?.error) {
|
||||
errorData = {
|
||||
message: data?.error?.message || 'Something went wrong',
|
||||
description: data?.error?.message || 'Something went wrong',
|
||||
status: data?.statusText || 'Failed',
|
||||
data: data?.error || {},
|
||||
};
|
||||
} else {
|
||||
errorData = data;
|
||||
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;
|
||||
errorData.description = data.errorMessage || 'Something went wrong';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
errorData = data;
|
||||
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': {
|
||||
const url = data.data.auth_url; // Backend generates and return sthe auth url
|
||||
const kind = data.data?.kind;
|
||||
|
|
@ -1158,44 +1158,44 @@ export function previewQuery(_ref, query, calledFromQuery = false, userSuppliedP
|
|||
queryStatus === 'Created' ||
|
||||
queryStatus === 'Accepted' ||
|
||||
queryStatus === 'No Content': {
|
||||
if (query.options.enableTransformation) {
|
||||
finalData = await runTransformation(
|
||||
_ref,
|
||||
finalData,
|
||||
query.options.transformation,
|
||||
query.options.transformationLanguage,
|
||||
query,
|
||||
'edit'
|
||||
);
|
||||
if (finalData?.status === 'failed') {
|
||||
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: {
|
||||
if (query.options.enableTransformation) {
|
||||
finalData = await runTransformation(
|
||||
_ref,
|
||||
finalData,
|
||||
query.options.transformation,
|
||||
query.options.transformationLanguage,
|
||||
query,
|
||||
'edit'
|
||||
);
|
||||
if (finalData?.status === 'failed') {
|
||||
useCurrentStateStore.getState().actions.setErrors({
|
||||
[query.name]: {
|
||||
type: 'query',
|
||||
kind: query.kind,
|
||||
type: 'transformations',
|
||||
data: finalData,
|
||||
options: options,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!calledFromQuery) setPreviewData(finalData);
|
||||
onEvent(_ref, 'onDataQuerySuccess', queryEvents, 'edit');
|
||||
break;
|
||||
});
|
||||
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]: {
|
||||
type: 'query',
|
||||
kind: query.kind,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!calledFromQuery) setPreviewData(finalData);
|
||||
onEvent(_ref, 'onDataQuerySuccess', queryEvents, 'edit');
|
||||
break;
|
||||
}
|
||||
}
|
||||
setPreviewLoading(false);
|
||||
|
||||
|
|
@ -1411,10 +1411,10 @@ export function runQuery(
|
|||
},
|
||||
query.kind === 'restapi'
|
||||
? {
|
||||
request: data.data.requestObject,
|
||||
response: data.data.responseObject,
|
||||
responseHeaders: data.data.responseHeaders,
|
||||
}
|
||||
request: data.data.requestObject,
|
||||
response: data.data.responseObject,
|
||||
responseHeaders: data.data.responseHeaders,
|
||||
}
|
||||
: {}
|
||||
),
|
||||
},
|
||||
|
|
@ -2405,11 +2405,11 @@ export const removeFunctionObjects = (obj) => {
|
|||
};
|
||||
|
||||
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
|
||||
if (licenseStatus) {
|
||||
if (_.has(licenseStatus, 'isExpired')) {
|
||||
return licenseStatus?.isExpired && !licenseStatus?.isLicenseValid;
|
||||
return licenseStatus?.isExpired;
|
||||
}
|
||||
return !licenseStatus?.isLicenseValid;
|
||||
}
|
||||
|
|
@ -2431,12 +2431,12 @@ export function isPDFSupported() {
|
|||
|
||||
function getBrowserUserAgent(userAgent) {
|
||||
var regexps = {
|
||||
Chrome: [/Chrome\/(\S+)/],
|
||||
Firefox: [/Firefox\/(\S+)/],
|
||||
MSIE: [/MSIE (\S+);/],
|
||||
Opera: [/Opera\/.*?Version\/(\S+)/ /* Opera 10 */, /Opera\/(\S+)/ /* Opera 9 and older */],
|
||||
Safari: [/Version\/(\S+).*?Safari\//],
|
||||
},
|
||||
Chrome: [/Chrome\/(\S+)/],
|
||||
Firefox: [/Firefox\/(\S+)/],
|
||||
MSIE: [/MSIE (\S+);/],
|
||||
Opera: [/Opera\/.*?Version\/(\S+)/ /* Opera 10 */, /Opera\/(\S+)/ /* Opera 9 and older */],
|
||||
Safari: [/Version\/(\S+).*?Safari\//],
|
||||
},
|
||||
re,
|
||||
m,
|
||||
browser,
|
||||
|
|
|
|||
|
|
@ -617,15 +617,14 @@
|
|||
|
||||
.page-handler-wrapper {
|
||||
background: transparent;
|
||||
height: 100%;
|
||||
scrollbar-width: none;
|
||||
overflow: auto;
|
||||
&.viewer{
|
||||
overflow: visible !important;
|
||||
}
|
||||
scrollbar-width: thin;
|
||||
height: 100%;
|
||||
padding-bottom: 48px;
|
||||
scrollbar-color: var(--interactive-selected) transparent;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.tj-list-item-selected {
|
||||
|
|
|
|||
|
|
@ -142,7 +142,6 @@
|
|||
|
||||
.accordion-header {
|
||||
height: 32px;
|
||||
background-color: var(--interactive-default);
|
||||
|
||||
.accordion-title-text {
|
||||
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 {
|
||||
padding: 16px !important;
|
||||
|
||||
|
|
@ -217,7 +227,7 @@
|
|||
position: relative;
|
||||
bottom: 2px;
|
||||
justify-content: center;
|
||||
padding-top: 32px;
|
||||
padding-top: 16px;
|
||||
margin-top: auto;
|
||||
|
||||
.sidebar-svg-icon {
|
||||
|
|
@ -241,6 +251,7 @@
|
|||
align-items: center;
|
||||
width: unset !important;
|
||||
margin-bottom: 20px;
|
||||
min-height: 28px;
|
||||
|
||||
.collapse-icon {
|
||||
margin-left: auto;
|
||||
|
|
@ -276,6 +287,23 @@
|
|||
}
|
||||
|
||||
.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 {
|
||||
border-radius: 6px;
|
||||
background: var(--background-accent-weak);
|
||||
|
|
@ -342,14 +370,15 @@
|
|||
.app-name {
|
||||
flex-direction: column-reverse;
|
||||
margin-bottom: 0px;
|
||||
gap: 0px;
|
||||
.cursor-pointer {
|
||||
img {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
.icon-btn {
|
||||
margin-left: 0px;
|
||||
margin-bottom: 20px
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -365,6 +394,7 @@
|
|||
}
|
||||
.accordion-body{
|
||||
padding: 4px 0 4px 16px !important;
|
||||
border-bottom: 0px !important;
|
||||
}
|
||||
.accordion-header{
|
||||
height: auto !important;
|
||||
|
|
@ -429,11 +459,12 @@
|
|||
padding-top: 0px;
|
||||
overflow: hidden !important;
|
||||
justify-content: space-between;
|
||||
border-right: 0px !important;
|
||||
|
||||
.page-handler-wrapper {
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
gap: 1px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.page-dark-mode-btn-wrapper {
|
||||
|
|
@ -453,6 +484,36 @@
|
|||
.tj-list-item {
|
||||
padding-right: 0px !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 {
|
||||
outline: none !important;
|
||||
padding: 6px 10px;
|
||||
height: 32px;
|
||||
padding: 6px 10px !important;
|
||||
margin-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.page-name {
|
||||
|
|
@ -498,11 +560,23 @@
|
|||
|
||||
.page-handler-wrapper {
|
||||
display: flex;
|
||||
padding-bottom: unset !important;
|
||||
overflow: hidden;
|
||||
|
||||
.more-btn-pages {
|
||||
&.tj-list-item-selected {
|
||||
svg {
|
||||
path {
|
||||
fill: var(--icon-accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.right-sidebar-open {
|
||||
width: calc(100% + 299px) !important;
|
||||
width: calc(100% + 300px) !important;
|
||||
position: sticky !important;
|
||||
|
||||
}
|
||||
|
|
@ -514,7 +588,7 @@
|
|||
}
|
||||
|
||||
&.right-sidebar-open.left-sidebar-open {
|
||||
width: calc(100% + 646px) !important;
|
||||
width: calc(100% + 650px) !important;
|
||||
position: sticky !important;
|
||||
}
|
||||
}
|
||||
|
|
@ -526,7 +600,7 @@
|
|||
width: fit-content;
|
||||
|
||||
.tj-list-item{
|
||||
padding: 8px 12px;
|
||||
padding: 6px 12px;
|
||||
color: var(--text-placeholder);
|
||||
justify-content: flex-start;
|
||||
|
||||
|
|
@ -550,12 +624,9 @@
|
|||
.accordion-body {
|
||||
padding: 0px 12px !important;
|
||||
padding-left: 28px !important;
|
||||
border-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.accordion-body {
|
||||
|
||||
}
|
||||
|
||||
.page-group-collapse {
|
||||
// right: 4px;
|
||||
transform: rotate(30deg);
|
||||
|
|
@ -601,8 +672,19 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
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 {
|
||||
padding-right: 0px;
|
||||
padding: 8px 12px !important;
|
||||
padding-right: 0px !important;
|
||||
width: unset !important;
|
||||
}
|
||||
&.tj-list-item-selected {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
|
||||
div[data-radix-popper-content-wrapper]:has(.PopoverContent.drawer-height) {
|
||||
margin-top: 48px;
|
||||
margin-left: 47px !important;
|
||||
margin-left: 48px !important;
|
||||
transform: none !important;
|
||||
z-index: 2 !important;
|
||||
}
|
||||
|
|
@ -59,6 +59,6 @@ div[data-radix-popper-content-wrapper]:has(.PopoverContent.drawer-height) {
|
|||
@-moz-document url-prefix() {
|
||||
div[data-radix-popper-content-wrapper] {
|
||||
z-index: 100 !important;
|
||||
left: 1px !important;
|
||||
// left: 1px !important;
|
||||
}
|
||||
}
|
||||
|
|
@ -93,7 +93,7 @@ $border-radius: 4px;
|
|||
height: 400px;
|
||||
position: fixed;
|
||||
left: 48px;
|
||||
right: 348px;
|
||||
right: 48px;
|
||||
bottom: 0;
|
||||
overflow-x: hidden;
|
||||
flex: 1 1 auto;
|
||||
|
|
|
|||
|
|
@ -662,11 +662,13 @@ button {
|
|||
padding: 4px 12px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid var(--border-weak);
|
||||
|
||||
.header {
|
||||
color: var(--text-default);
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
padding: 7px 6px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -823,8 +825,13 @@ button {
|
|||
background: transparent !important;
|
||||
}
|
||||
|
||||
.canvas-container {
|
||||
scrollbar-width: none;
|
||||
:hover {
|
||||
.canvas-container {
|
||||
scrollbar-width: thin;
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.canvas-container {
|
||||
|
|
@ -839,6 +846,16 @@ button {
|
|||
justify-content: center;
|
||||
-webkit-box-align: 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 {
|
||||
outline: 1px dotted transparent;
|
||||
|
|
@ -5203,12 +5220,13 @@ input[type="text"] {
|
|||
}
|
||||
|
||||
.inspector-component-title-input-holder {
|
||||
padding: 2px 12px;
|
||||
padding: 4px 12px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
.icon-btn {
|
||||
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-pull.active {
|
||||
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
|
||||
fill-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}
|
||||
/>
|
||||
</svg>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import CheveronLeft from './CheveronLeft.jsx';
|
|||
import CheveronRight from './CheveronRight.jsx';
|
||||
import CheveronUp from './CheveronUp.jsx';
|
||||
import ClearRectangle from './ClearRectangle.jsx';
|
||||
import CaretDown from './CaretDown.jsx';
|
||||
import CaretUp from './CaretUp.jsx';
|
||||
import Clock from './Clock.jsx';
|
||||
import CursorClick from './CursorClick.jsx';
|
||||
import LockGradient from './LockGradient.jsx';
|
||||
|
|
@ -261,6 +263,7 @@ import Delete01 from './Delete01.jsx';
|
|||
import SourceControl from './SourceControl.jsx';
|
||||
import Push from './PushIcon.jsx';
|
||||
import Pull from './PullIcon.jsx';
|
||||
import PropertiesStyles from './PropertiesStyles.jsx';
|
||||
import RemoveFolder from './RemoveFolder.jsx';
|
||||
|
||||
const Icon = (props) => {
|
||||
|
|
@ -335,6 +338,10 @@ const Icon = (props) => {
|
|||
return <Debugger {...props} />;
|
||||
case 'calender':
|
||||
return <Calender {...props} />;
|
||||
case 'caretdown':
|
||||
return <CaretDown {...props} />;
|
||||
case 'caretup':
|
||||
return <CaretUp {...props} />;
|
||||
case 'checkrectangle':
|
||||
return <CheckRectangle {...props} />;
|
||||
case 'cheverondown':
|
||||
|
|
@ -535,6 +542,8 @@ const Icon = (props) => {
|
|||
return <Pin {...props} />;
|
||||
case 'unpin01':
|
||||
return <Unpin01 {...props} />;
|
||||
case 'propertiesstyles':
|
||||
return <PropertiesStyles {...props} />;
|
||||
case 'unpin':
|
||||
return <Unpin {...props} />;
|
||||
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);
|
||||
|
||||
const pages = await this.findPagesForVersion(appVersionId, organizationId, manager);
|
||||
const pages = await this.findPagesForVersion(appVersionId, organizationId, '', manager);
|
||||
const events = await this.eventHandlerService.findEventsForVersion(appVersionId, manager);
|
||||
|
||||
return { pages, events };
|
||||
}, appVersionId);
|
||||
}
|
||||
|
||||
async cloneGroup(groupPageId: string, appVersionId: string) {
|
||||
async cloneGroup(groupPageId: string, appVersionId: string, organizationId) {
|
||||
return dbTransactionForAppVersionAssociationsUpdate(async (manager) => {
|
||||
const groupToClone = await manager.findOne(Page, {
|
||||
where: { id: groupPageId, appVersionId, isPageGroup: true },
|
||||
|
|
@ -185,7 +185,7 @@ export class PageService implements IPageService {
|
|||
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);
|
||||
|
||||
return { pages, events };
|
||||
|
|
|
|||
Loading…
Reference in a new issue