ToolJet/frontend/src/Editor/LeftSidebar/SidebarGlobalSettings.jsx
Sherfin Shamsudeen 642c5caa71
Feature/multi page applications (Task ID - CU-2h1bfvw) (#4729)
* Add routes for multi-page apps

* Modify Editor, Viewer and Inspector to accept new app structure

* Show a page selector on left side bar

* Align component deletion logic with new app schema

* Make subcontainer work with multi-page apps

* Load components state properly in viewer

* Use UUID instead of handle for pages

* Display sidebar on viewer to switch pages

* Add proper URL suffixing for pages in viewer

* Add action to switch page

* Revert translation file back to its pre-existing linting

* Fix bug that caused modal to not open/close

* Add support for query params in page switch

* Fix the issue that caused navigation to fail while accessed via slug

* Add missing SwitchPage file

* Add support for page level variables

* Add migration to convert existing apps to new schema

* Add rollback for converting multi-page definitions back to single-page

* Fix migration for multi-page apps

* Adapt import/export service for multi-pages

* [improvements] Multi-page applications (#4755)

* UI updates for page selector popup card

* delete page

* delete page check: if only one page exits

* switch to home page if the selected page is removed

* adds and switch to new page

* updating page name

* updates to home page and starting page

* handle updating the home page when home page is deleted

* search box for filtering pages and minor style updates for the page handler card

* header search box style fixes

* for creating a new page, page handle needs to be unique

* seperating into smaller components

* updated pinned icon for page selector styles and settinf styles

* Leftsidebar header ui component

* handle dark theme

* page handle ui and dark theme fixes for page menu

* page handler edit modal

* pinned state and update pinned state for menu options triggered

* dark theme fixes for edit modal

* handle on update should not be empty or prev

* page handler updater

* added loading state for saving

* handles cancels

* fixes slug ui

* fixes crash for older app versions

* updates the query params when handle gets an update

* update homePage to homePageId

* removes console.log

* go back to the popover for modal close

* fixes: Difficult to select page

* fixes: Difficult to select the three-dot menu

* fixes: on visiting the root url, navigate to homepage on viewer

* adds tooltip for url

* updates the page selector sidebar with sync with query manager

* refactor and cleanup

* refactor and cleanup

* Compute component state when page is switched

* modal should not close on click outside

* disable save button if there is not change in the page handle input

* should show/hide page menu when hovered

* page icon

* updates delete icon for disabled state

* query manager should always be on top of page selector

* checks if homePage key exists in pages def

* updates page handler menu

* updates the clear icon

* page handler menu position

* page handler menu position

* handle icon

* alert msg

* global settings handler for updating viewer page navigation

* show/hode page navigation for viewer

* info text for toggle

* Multipages:with sortable list [DnD] (#4783)

* applied sortable list

* on sort updates the definitions

* fixies: app crash for dnd

* viwer: canvas width should be 100% when navigation drawer is disbaled

* fixes: homepage/startpage  reload

* clean up

Co-authored-by: Sherfin Shamsudeen <sherfin94@gmail.com>

* Multipage UI viewer (#4801)

* new ui changes for viewer pages

* fixes postions for debugger and datasources popover

* removes console.log

* Multipage : hide page and unhide page feature (#4803)

* adds: ability to hide pages

* hides pages in viewer

* unhide page

* hide icon

* allow accessing hidden pages from url

* add: duplicate page (#4802)

* add: duplicate page

* do not copy the  same references from the original page

* page name and page handler should be unique for duplicate pages too

* Add support for on-page-load events

* Add icon from page settings menu item

* Convert existing templates to multi-page schema

* error logs for page level and app level errors (#4842)

* Adapt comments feature for multi-pages

* [Bugfix] multipage - page menu interactions (#4844)

* fixes: menu popup interaction

* fixes: on modal input focus, we switch the page

* Adapt multi-player to multi-pages

* Add editingPageId to ymap

* Log self, others and editor props in real-time avatar generation

* Save editing page id to appDef

* Add editingPageId to presence in RealtimeCursors

* adds no results ui for empty search results (#4869)

* page icon updated (#4870)

* fixes:Version switching crashes if the target version does not contain the current page (#4868)

* Remove unnecessary setting of editingPageId on ymap

* Remove unnecessary console.log

* [Bugfix] Multipages: widget inspector event popover unmounts (#4887)

* introduced a local state for events

* cleaned up inspector.jsx

* fixes: table widget inspector event accordion

* Do not run switchPage twice when viewer is loaded

* Preview should open the currently editing page

* Properly place navigation and canvas in viewer

* Update app definition whenever event manager changes are made

* Add support for browser back and forward button in multi-pages

* Rename handleBackButton to handlePageSwitchingBasedOnURLparam

* Add support for cut/copy/paste and clone

* Fix the crash caused by boxShadow

* Add support for background colors in viewer in multi-pages

* Run queries to be run on load on viewer, in multi-pages

* Fix issue that caused inspector popovers to collapse

* resolves workspace vars in viewer mode (#4892)

* Multipage : Navigation for Mobile-ui (#4814)

* refactored to components

* burger menu for mobile ui

* merge conflict fix for hidden pages

* hamburger menu positioned in the header

* viewer header reafctored

* viewer mobile page manu styles

* handles dark theme

* mobile menu with dark mode toggle in the footer

* components are moved to page level, handle for mobile layout

* style fixes

* removing unwanted code block

* dark theme fixes

* style fixes

* fixes: events are sortable (#4895)

* fixes: events are sortable

* Remove uneccesarily repeated call of setEvents in EventManager

Co-authored-by: Sherfin Shamsudeen <sherfin94@gmail.com>

* renamed settings to Event handlers (#4898)

* updates the page setting title to Page Events

* temp commit

* Add support for setting max width in percentage

* fixes: paramUpdates for boxes: 🙌🏻

* [Bugfix] Multipage - viewer canvas dark theme (#4897)

* fixes: darktheme bg for viewer canvas

* reverts canvas size

* Fix for inspector bouncing back to previous values

* resolves pages variables in pythong and js transformation (#4905)

* csa support to event manager for pages (#4907)

* Add support for setting canvas width in percentages

* Persist page level variables across page switches

* latest definitions is merged with the current appdef (#4914)

* latest definitions is merged with the current appdef

* mutating the local obj

* cleanup

* iterate through pages for new versions are created

Co-authored-by: Arpit <arpitnath42@gmail.com>
2022-12-08 17:51:09 +05:30

225 lines
9.4 KiB
JavaScript

import React from 'react';
import usePopover from '@/_hooks/use-popover';
import { SketchPicker } from 'react-color';
import { Confirm } from '../Viewer/Confirm';
import { LeftSidebarItem } from './SidebarItem';
import FxButton from '../CodeBuilder/Elements/FxButton';
import { CodeHinter } from '../CodeBuilder/CodeHinter';
import { resolveReferences } from '@/_helpers/utils';
import { useTranslation } from 'react-i18next';
import _ from 'lodash';
export const LeftSidebarGlobalSettings = ({
globalSettings,
globalSettingsChanged,
darkMode,
toggleAppMaintenance,
is_maintenance_on,
currentState,
}) => {
const { t } = useTranslation();
const [open, trigger, content] = usePopover(false);
const { hideHeader, canvasMaxWidth, canvasMaxWidthType, canvasMaxHeight, canvasBackgroundColor, backgroundFxQuery } =
globalSettings;
const [showPicker, setShowPicker] = React.useState(false);
const [forceCodeBox, setForceCodeBox] = React.useState(true);
const [realState, setRealState] = React.useState(currentState);
const [showConfirmation, setConfirmationShow] = React.useState(false);
const coverStyles = {
position: 'fixed',
top: '0px',
right: '0px',
bottom: '0px',
left: '0px',
};
React.useEffect(() => {
setRealState(currentState);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentState.components]);
React.useEffect(() => {
backgroundFxQuery &&
globalSettingsChanged('canvasBackgroundColor', resolveReferences(backgroundFxQuery, realState));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(resolveReferences(backgroundFxQuery, realState))]);
return (
<>
<Confirm
show={showConfirmation}
message={
is_maintenance_on
? 'Users will now be able to launch the released version of this app, do you wish to continue?'
: 'Users will not be able to launch the app until maintenance mode is turned off, do you wish to continue?'
}
onConfirm={() => toggleAppMaintenance()}
onCancel={() => setConfirmationShow(false)}
darkMode={darkMode}
/>
<LeftSidebarItem
tip="Global settings"
{...trigger}
icon="settings"
className={`left-sidebar-item left-sidebar-layout ${open && 'active'}`}
text={'Settings'}
/>
<div {...content} className={`card popover global-settings-popover ${open ? 'show' : 'hide'}`}>
<div style={{ marginTop: '1rem' }} className="card-body">
<div>
<div className="d-flex mb-3">
<span>{t('leftSidebar.Settings.hideHeader', 'Hide header for launched apps')}</span>
<div className="ms-auto form-check form-switch position-relative">
<input
className="form-check-input"
type="checkbox"
checked={hideHeader}
onChange={(e) => globalSettingsChanged('hideHeader', e.target.checked)}
/>
</div>
</div>
<div className="d-flex mb-3">
<span>{t('leftSidebar.Settings.maintenanceMode', 'Maintenance mode')}</span>
<div className="ms-auto form-check form-switch position-relative">
<input
className="form-check-input"
type="checkbox"
checked={is_maintenance_on}
onChange={() => setConfirmationShow(true)}
/>
</div>
</div>
<div className="d-flex mb-3">
<span className="w-full m-auto">{t('leftSidebar.Settings.maxWidthOfCanvas', 'Max width of canvas')}</span>
<div className="position-relative">
<div className="input-with-icon">
<input
data-cy="maximum-canvas-width-input-field"
type="text"
className={`form-control form-control-sm`}
placeholder={'0'}
onChange={(e) => {
const width = e.target.value;
if (!Number.isNaN(width) && width >= 0) globalSettingsChanged('canvasMaxWidth', width);
}}
value={canvasMaxWidth}
/>
<select
className="form-select"
aria-label="Select canvas width type"
onChange={(event) => {
const newCanvasMaxWidthType = event.currentTarget.value;
globalSettingsChanged('canvasMaxWidthType', newCanvasMaxWidthType);
if (newCanvasMaxWidthType === '%') {
globalSettingsChanged('canvasMaxWidth', 100);
} else if (newCanvasMaxWidthType === 'px') {
globalSettingsChanged('canvasMaxWidth', 1292);
}
}}
>
<option value="%" selected={canvasMaxWidthType === '%'}>
%
</option>
<option value="px" selected={canvasMaxWidthType === 'px' || _.isUndefined(canvasMaxWidthType)}>
px
</option>
</select>
</div>
</div>
</div>
<div className="d-flex mb-3">
<span className="w-full m-auto">
{t('leftSidebar.Settings.maxHeightOfCanvas', 'Max height of canvas')}
</span>
<div className="position-relative">
<div className="input-with-icon">
<input
data-cy="maximum-canvas-height-input-field"
type="text"
className={`form-control form-control-sm maximum-canvas-height-input-field`}
placeholder={'0'}
onChange={(e) => {
const height = e.target.value;
if (!Number.isNaN(height) && height <= 2400) globalSettingsChanged('canvasMaxHeight', height);
}}
value={canvasMaxHeight}
/>
<span className="input-group-text">px</span>
</div>
</div>
</div>
<div className="d-flex">
<span className="w-full">
{t('leftSidebar.Settings.backgroundColorOfCanvas', 'Background color of canvas')}
</span>
<div className="canvas-codehinter-container">
{showPicker && (
<div>
<div style={coverStyles} onClick={() => setShowPicker(false)} />
<SketchPicker
className="canvas-background-picker"
onFocus={() => setShowPicker(true)}
color={canvasBackgroundColor}
onChangeComplete={(color) => {
globalSettingsChanged('canvasBackgroundColor', [color.hex, color.rgb]);
globalSettingsChanged('backgroundFxQuery', color.hex);
}}
/>
</div>
)}
{forceCodeBox && (
<div
className="row mx-0 form-control form-control-sm canvas-background-holder"
onClick={() => setShowPicker(true)}
>
<div
className="col-auto"
style={{
float: 'right',
width: '20px',
height: '20px',
backgroundColor: canvasBackgroundColor,
border: `0.25px solid ${
['#ffffff', '#fff', '#1f2936'].includes(canvasBackgroundColor) && '#c5c8c9'
}`,
}}
></div>
<div className="col">{canvasBackgroundColor}</div>
</div>
)}
<div
className={`${!forceCodeBox && 'hinter-canvas-input'} ${!darkMode && 'hinter-canvas-input-light'} `}
>
{!forceCodeBox && (
<CodeHinter
currentState={realState}
initialValue={backgroundFxQuery ? backgroundFxQuery : canvasBackgroundColor}
value={backgroundFxQuery ? backgroundFxQuery : canvasBackgroundColor}
theme={darkMode ? 'monokai' : 'duotone-light'}
mode="javascript"
className="canvas-hinter-wrap"
lineNumbers={false}
onChange={(color) => {
globalSettingsChanged('canvasBackgroundColor', resolveReferences(color, realState));
globalSettingsChanged('backgroundFxQuery', color);
}}
/>
)}
<div className={`fx-canvas ${!darkMode && 'fx-canvas-light'} `}>
<FxButton
active={!forceCodeBox ? true : false}
onPress={() => {
setForceCodeBox(!forceCodeBox);
}}
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</>
);
};