mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 17:08:34 +00:00
commit
1442a11689
8 changed files with 338 additions and 30 deletions
|
|
@ -205,7 +205,6 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
setPreviewPanelExpanded,
|
||||
executeRunPycode,
|
||||
runTransformation,
|
||||
executeWorkflow,
|
||||
executeMultilineJS,
|
||||
} = queryPanel;
|
||||
const { onEvent } = eventsSlice;
|
||||
|
|
@ -297,14 +296,6 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
queryExecutionPromise = executeMultilineJS(query.options.code, query?.id, false, mode, parameters);
|
||||
} else if (query.kind === 'runpy') {
|
||||
queryExecutionPromise = executeRunPycode(query.options.code, query, false, mode, queryState);
|
||||
} else if (query.kind === 'workflows') {
|
||||
queryExecutionPromise = executeWorkflow(
|
||||
moduleId,
|
||||
query.options.workflowId,
|
||||
query.options.blocking,
|
||||
query.options?.params,
|
||||
(currentAppEnvironmentId ?? environmentId) || selectedEnvironment?.id //TODO: currentAppEnvironmentId may no longer required. Need to check
|
||||
);
|
||||
} else {
|
||||
queryExecutionPromise = dataqueryService.run(
|
||||
queryId,
|
||||
|
|
@ -465,7 +456,6 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
setPreviewPanelExpanded,
|
||||
executeRunPycode,
|
||||
runTransformation,
|
||||
executeWorkflow,
|
||||
executeMultilineJS,
|
||||
setIsPreviewQueryLoading,
|
||||
} = queryPanel;
|
||||
|
|
@ -514,14 +504,6 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
queryExecutionPromise = executeMultilineJS(query.options.code, query?.id, true, '', parameters);
|
||||
} else if (query.kind === 'runpy') {
|
||||
queryExecutionPromise = executeRunPycode(query.options.code, query, true, 'edit', queryState);
|
||||
} else if (query.kind === 'workflows') {
|
||||
queryExecutionPromise = executeWorkflow(
|
||||
moduleId,
|
||||
query.options.workflowId,
|
||||
query.options.blocking,
|
||||
query.options?.params,
|
||||
(currentAppEnvironmentId ?? environmentId) || selectedEnvironment?.id //TODO: currentAppEnvironmentId may no longer required. Need to check
|
||||
);
|
||||
} else {
|
||||
queryExecutionPromise = dataqueryService.preview(query, options, currentVersionId, currentAppEnvironmentId);
|
||||
}
|
||||
|
|
|
|||
22
frontend/src/_components/AccordionForm.jsx
Normal file
22
frontend/src/_components/AccordionForm.jsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import React from 'react';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import Accordion from '@/_ui/Accordion';
|
||||
|
||||
const AccordionForm = ({ formComponent, getLayout }) => {
|
||||
const sections = Object.keys(formComponent)
|
||||
.map((key) => ({
|
||||
title: formComponent[key].title,
|
||||
inputs: formComponent[key].inputs,
|
||||
}))
|
||||
.filter(({ inputs }) => inputs && !isEmpty(inputs));
|
||||
|
||||
const items = sections.map(({ title, inputs }) => ({
|
||||
title: title,
|
||||
isOpen: true,
|
||||
children: getLayout(inputs),
|
||||
}));
|
||||
|
||||
return <Accordion items={items} />;
|
||||
};
|
||||
|
||||
export default AccordionForm;
|
||||
|
|
@ -8,13 +8,13 @@ import OAuth from '@/_ui/OAuth';
|
|||
import Toggle from '@/_ui/Toggle';
|
||||
import OpenApi from '@/_ui/OpenAPI';
|
||||
import { Checkbox, CheckboxGroup } from '@/_ui/CheckBox';
|
||||
import CodeHinter from '@/Editor/CodeEditor';
|
||||
import CodeHinter from '@/AppBuilder/CodeEditor';
|
||||
import GoogleSheets from '@/_components/Googlesheets';
|
||||
import Slack from '@/_components/Slack';
|
||||
import Zendesk from '@/_components/Zendesk';
|
||||
import { ConditionFilter, CondtionSort, MultiColumn } from '@/_components/MultiConditions';
|
||||
import Salesforce from '@/_components/Salesforce';
|
||||
import ToolJetDbOperations from '@/Editor/QueryManager/QueryEditors/TooljetDatabase/ToolJetDbOperations';
|
||||
import ToolJetDbOperations from '@/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/ToolJetDbOperations';
|
||||
import { orgEnvironmentVariableService, orgEnvironmentConstantService } from '../_services';
|
||||
import { find, isEmpty } from 'lodash';
|
||||
import { ButtonSolid } from './AppButton';
|
||||
|
|
|
|||
|
|
@ -31,17 +31,18 @@ const AccordionItem = ({ open = true, index, title, children }) => {
|
|||
}
|
||||
return (
|
||||
<div className="accordion-item">
|
||||
<h2 onClick={() => setShow(!show)} className="accordion-header" id={`heading-${index}`}>
|
||||
<button
|
||||
className={cx('accordion-button', { collapsed: !show })}
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target={`collapse-${index}`}
|
||||
aria-expanded="false"
|
||||
data-cy={`widget-accordion-${title.toLowerCase()}`}
|
||||
>
|
||||
<h2 className="accordion-header" id={`heading-${index}`} data-cy={`widget-accordion-${title.toLowerCase()}`}>
|
||||
<div className={cx('accordion-button inspector')}>
|
||||
<span className="text-capitalize accordion-title-text">{title}</span>
|
||||
</button>
|
||||
<div
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target={`collapse-${index}`}
|
||||
aria-expanded="false"
|
||||
className={cx('accordion-item-trigger', { collapsed: !show })}
|
||||
onClick={() => setShow((prev) => !prev)}
|
||||
></div>
|
||||
</div>
|
||||
</h2>
|
||||
<div
|
||||
id={`collapse-${index}`}
|
||||
|
|
|
|||
74
frontend/src/_ui/Sort/QueryEditor.jsx
Normal file
74
frontend/src/_ui/Sort/QueryEditor.jsx
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import React from 'react';
|
||||
import { ButtonSolid } from '@/_ui/AppButton/AppButton';
|
||||
import AddRectangle from '@/_ui/Icon/bulkIcons/AddRectangle';
|
||||
import CodeHinter from '@/Editor/CodeEditor';
|
||||
import InfoIcon from '@assets/images/icons/info.svg';
|
||||
import Trash from '@/_ui/Icon/solidIcons/Trash';
|
||||
import Select from '@/_ui/Select';
|
||||
import Input from '@/_ui/Input';
|
||||
import '@/_ui/Sort/sortStyles.scss';
|
||||
|
||||
export default ({ options, addNewKeyValuePair, removeKeyValuePair, keyValuePairValueChanged, buttonText }) => {
|
||||
const darkMode = localStorage.getItem('darkMode') === 'true';
|
||||
const sortOptions = [
|
||||
{ value: 'asc', label: 'Ascending' },
|
||||
{ value: 'desc', label: 'Descending' },
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
{options.length === 0 && (
|
||||
<div className="empty-key-value">
|
||||
<InfoIcon style={{ width: '16px', marginRight: '5px' }} />
|
||||
<span>There are no key value pairs added</span>
|
||||
</div>
|
||||
)}
|
||||
{options.map((option, index) => {
|
||||
return (
|
||||
<div className="d-flex" key={index}>
|
||||
<div className="d-flex mb-2 justify-content-between w-100">
|
||||
<div className="w-100 sort-input">
|
||||
<Input
|
||||
value={option[0]}
|
||||
className="form-control"
|
||||
type="text"
|
||||
placeholder="Field"
|
||||
style={{ height: '32px' }}
|
||||
onChange={(e) => keyValuePairValueChanged(e.target.value, 0, index)}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-100 sort-input">
|
||||
<Select
|
||||
options={sortOptions}
|
||||
value={sortOptions.find((opt) => opt.value === option[1])}
|
||||
onChange={(value) => keyValuePairValueChanged(value, 1, index)}
|
||||
width={'100%'}
|
||||
placeholder="Select direction"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className={`d-flex justify-content-center align-items-center delete-field-option bg-transparent border-0 rounded-0 border-top border-bottom border-end border-start rounded-start rounded-end trash ${
|
||||
darkMode ? 'delete-field-option-dark' : ''
|
||||
}`}
|
||||
role="button"
|
||||
onClick={() => {
|
||||
removeKeyValuePair(index);
|
||||
}}
|
||||
>
|
||||
<Trash fill="var(--slate9)" style={{ height: '16px' }} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<ButtonSolid
|
||||
variant="ghostBlue"
|
||||
size="sm"
|
||||
onClick={() => addNewKeyValuePair(options)}
|
||||
style={{ gap: '0px', padding: '2px 8px' }}
|
||||
>
|
||||
<AddRectangle width="15" fill="#3E63DD" opacity="1" secondaryFill="#ffffff" />
|
||||
{buttonText}
|
||||
</ButtonSolid>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
80
frontend/src/_ui/Sort/SourceEditor.jsx
Normal file
80
frontend/src/_ui/Sort/SourceEditor.jsx
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import React from 'react';
|
||||
import Input from '../Input';
|
||||
import Trash from '@/_ui/Icon/solidIcons/Trash';
|
||||
import { ButtonSolid } from '@/_ui/AppButton/AppButton';
|
||||
import AddRectangle from '@/_ui/Icon/bulkIcons/AddRectangle';
|
||||
import InfoIcon from '@assets/images/icons/info.svg';
|
||||
import '@/_ui/Sort/sortStyles.scss';
|
||||
import Select from '@/_ui/Select';
|
||||
|
||||
export default ({
|
||||
options,
|
||||
addNewKeyValuePair,
|
||||
removeKeyValuePair,
|
||||
keyValuePairValueChanged,
|
||||
workspaceConstants,
|
||||
isDisabled,
|
||||
width,
|
||||
}) => {
|
||||
const darkMode = localStorage.getItem('darkMode') === 'true';
|
||||
const sortOptions = [
|
||||
{ value: 'asc', label: 'Ascending' },
|
||||
{ value: 'desc', label: 'Descending' },
|
||||
];
|
||||
return (
|
||||
<div className="table-content-wrapper">
|
||||
{options.length === 0 && (
|
||||
<div className="empty-key-value">
|
||||
<InfoIcon style={{ width: '16px', marginRight: '5px' }} />
|
||||
<span>There are no key value pairs added</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{options.map((option, index) => (
|
||||
<div className="d-flex align-items-top row-container query-manager-border-color" key={index}>
|
||||
<Input
|
||||
value={option[0]}
|
||||
className="form-control"
|
||||
type="text"
|
||||
placeholder="Field"
|
||||
style={{ width: width ? width : '300px', borderTopRightRadius: '0px', borderBottomRightRadius: '0px' }}
|
||||
onChange={(e) => keyValuePairValueChanged(e.target.value, 0, index)}
|
||||
/>
|
||||
<Select
|
||||
options={sortOptions}
|
||||
value={sortOptions.find((opt) => opt.value === option[1])}
|
||||
onChange={(value) => keyValuePairValueChanged(value, 1, index)}
|
||||
width={'316px'}
|
||||
height={'35px'}
|
||||
placeholder="Select direction"
|
||||
/>
|
||||
|
||||
<button
|
||||
className={`d-flex justify-content-center align-items-center delete-field-option bg-transparent border-0 rounded-0 border-top border-bottom border-end rounded-end ${
|
||||
darkMode ? 'delete-field-option-dark' : ''
|
||||
}`}
|
||||
style={{ height: '35px' }}
|
||||
role="button"
|
||||
disabled={isDisabled}
|
||||
onClick={() => removeKeyValuePair(index)}
|
||||
>
|
||||
<Trash fill="var(--slate9)" style={{ height: '16px' }} />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className="d-flex mb-2" style={{ height: '16px' }}>
|
||||
<ButtonSolid
|
||||
variant="ghostBlue"
|
||||
size="sm"
|
||||
onClick={() => addNewKeyValuePair(options)}
|
||||
style={{ gap: '0px', paddingTop: '2px', paddingRight: '8px', paddingBottom: '2px', paddingLeft: '8px' }}
|
||||
disabled={isDisabled}
|
||||
>
|
||||
<AddRectangle width="15" fill="#3E63DD" opacity="1" secondaryFill="#ffffff" />
|
||||
Add
|
||||
</ButtonSolid>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
53
frontend/src/_ui/Sort/index.js
Normal file
53
frontend/src/_ui/Sort/index.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import QueryEditor from './QueryEditor';
|
||||
import SourceEditor from './SourceEditor';
|
||||
import { deepClone } from '@/_helpers/utilities/utils.helpers';
|
||||
|
||||
export default ({
|
||||
getter,
|
||||
options = [['', '']],
|
||||
optionchanged,
|
||||
currentState,
|
||||
isRenderedAsQueryEditor,
|
||||
workspaceConstants,
|
||||
isDisabled,
|
||||
buttonText,
|
||||
width,
|
||||
}) => {
|
||||
function addNewKeyValuePair(options) {
|
||||
const newPairs = [...options, ['', '']];
|
||||
optionchanged(getter, newPairs);
|
||||
}
|
||||
|
||||
function removeKeyValuePair(index) {
|
||||
options.splice(index, 1);
|
||||
optionchanged(getter, options);
|
||||
}
|
||||
|
||||
function keyValuePairValueChanged(value, keyIndex, index) {
|
||||
if (!isRenderedAsQueryEditor) {
|
||||
const newOptions = deepClone(options);
|
||||
newOptions[index][keyIndex] = value;
|
||||
options.length - 1 === index ? addNewKeyValuePair(newOptions) : optionchanged(getter, newOptions);
|
||||
} else {
|
||||
options[index][keyIndex] = value;
|
||||
optionchanged(getter, options);
|
||||
}
|
||||
}
|
||||
|
||||
const commonProps = {
|
||||
options,
|
||||
addNewKeyValuePair,
|
||||
removeKeyValuePair,
|
||||
keyValuePairValueChanged,
|
||||
isDisabled,
|
||||
buttonText,
|
||||
};
|
||||
|
||||
return isRenderedAsQueryEditor ? (
|
||||
<QueryEditor {...commonProps} />
|
||||
) : (
|
||||
<SourceEditor {...commonProps} workspaceConstants={workspaceConstants} width={width} />
|
||||
);
|
||||
};
|
||||
96
frontend/src/_ui/Sort/sortStyles.scss
Normal file
96
frontend/src/_ui/Sort/sortStyles.scss
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
.query-manager-border-color {
|
||||
|
||||
input.form-control,
|
||||
textarea,
|
||||
.input-control {
|
||||
gap: 16px !important;
|
||||
background: var(--base) !important;
|
||||
border: 1px solid var(--slate7) !important;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 4px !important;
|
||||
color: var(--slate12) !important;
|
||||
transition: none;
|
||||
height: 35px;
|
||||
padding-left: 0.4375rem;
|
||||
padding-right: 0.4375rem;
|
||||
padding-top: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
overflow-x: 'auto';
|
||||
white-space: 'nowrap';
|
||||
|
||||
|
||||
&:hover {
|
||||
background: var(--slate1) !important;
|
||||
border: 1px solid var(--slate8) !important;
|
||||
-webkit-box-shadow: none !important;
|
||||
box-shadow: none !important;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
background: var(--indigo2) !important;
|
||||
border: 1px solid var(--indigo9) !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
&.input-error-border {
|
||||
border-color: #DB4324 !important;
|
||||
}
|
||||
|
||||
&:-webkit-autofill {
|
||||
box-shadow: 0 0 0 1000px var(--base) inset !important;
|
||||
-webkit-text-fill-color: var(--slate12) !important;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 0 1000px var(--slate1) inset !important;
|
||||
-webkit-text-fill-color: var(--slate12) !important;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
box-shadow: 0 0 0 1000px var(--indigo2) inset !important;
|
||||
-webkit-text-fill-color: var(--slate12) !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.empty-key-value {
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
width: 625px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 10px;
|
||||
color: #687076;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
border: 1px dashed #E6E8EB;
|
||||
}
|
||||
|
||||
.trash {
|
||||
height: 32px;
|
||||
display: flex;
|
||||
justify-content: 'center';
|
||||
align-items: 'center';
|
||||
}
|
||||
|
||||
.sort-input,
|
||||
.table-content-wrapper{
|
||||
.tj-app-input{
|
||||
.form-control{
|
||||
border-radius: 6px 0px 0px 6px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sort-input,
|
||||
.table-content-wrapper{
|
||||
.dark-theme.react-select__control{
|
||||
border-radius: 0px 6px 6px 0px !important;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in a new issue