mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 01:18:23 +00:00
Merge branch 'release/v1.6.0'
This commit is contained in:
commit
be50abc076
89 changed files with 6088 additions and 9157 deletions
2
.version
2
.version
|
|
@ -1 +1 @@
|
|||
1.5.1
|
||||
1.6.0
|
||||
|
|
|
|||
6
Aptfile
Normal file
6
Aptfile
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# you can list packages
|
||||
libaio1
|
||||
|
||||
# or include links to specific .deb files
|
||||
|
||||
# or add custom apt repos (only required if using packages outside of the standard Ubuntu APT repositories)
|
||||
6
app.json
6
app.json
|
|
@ -46,6 +46,12 @@
|
|||
"buildpacks": [
|
||||
{
|
||||
"url": "heroku/nodejs"
|
||||
},
|
||||
{
|
||||
"url": "heroku-community/apt"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/featurist/oracle-client-buildpack.git"
|
||||
}
|
||||
],
|
||||
"environments": {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ $ npm install -g @tooljet/cli
|
|||
$ tooljet COMMAND
|
||||
running command...
|
||||
$ tooljet (--version)
|
||||
@tooljet/cli/0.0.6 darwin-arm64 node-v16.13.1
|
||||
@tooljet/cli/0.0.7 darwin-arm64 node-v14.17.3
|
||||
$ tooljet --help [COMMAND]
|
||||
USAGE
|
||||
$ tooljet COMMAND
|
||||
|
|
|
|||
12747
cli/package-lock.json
generated
12747
cli/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"name": "@tooljet/cli",
|
||||
"description": "tooljet cli tool",
|
||||
"version": "0.0.6",
|
||||
"version": "0.0.7",
|
||||
"bin": {
|
||||
"tooljet": "./bin/run"
|
||||
},
|
||||
"bugs": "https://github.com/tooljet/tooljet/issues",
|
||||
"dependencies": {
|
||||
"@oclif/core": "^1",
|
||||
"@oclif/plugin-help": "^5",
|
||||
"@oclif/core": "^1.6.0",
|
||||
"@oclif/plugin-help": "^5.1.12",
|
||||
"@oclif/plugin-plugins": "^2.1.0",
|
||||
"@types/inquirer": "^8.1.3",
|
||||
"hygen": "^6.1.0",
|
||||
|
|
|
|||
|
|
@ -25,6 +25,19 @@ sudo luarocks install lua-resty-auto-ssl
|
|||
sudo mkdir /etc/resty-auto-ssl /var/log/openresty /etc/fallback-certs
|
||||
sudo chown -R www-data:www-data /etc/resty-auto-ssl
|
||||
|
||||
# Oracle db client library setup
|
||||
sudo apt install -y libaio1
|
||||
curl -o instantclient-basiclite.zip https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip -SL && \
|
||||
unzip instantclient-basiclite.zip && \
|
||||
sudo mv instantclient*/ /usr/lib/instantclient && \
|
||||
rm instantclient-basiclite.zip && \
|
||||
sudo ln -s /usr/lib/instantclient/libclntsh.so.19.1 /usr/lib/libclntsh.so && \
|
||||
sudo ln -s /usr/lib/instantclient/libocci.so.19.1 /usr/lib/libocci.so && \
|
||||
sudo ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2 && \
|
||||
sudo ln -s /lib64/ld-linux-x86-64.so.2 /usr/lib/ld-linux-x86-64.so.2
|
||||
export LD_LIBRARY_PATH="/usr/lib/instantclient"
|
||||
|
||||
|
||||
# Gen fallback certs
|
||||
sudo openssl rand -out /home/ubuntu/.rnd -hex 256
|
||||
sudo chown www-data:www-data /home/ubuntu/.rnd
|
||||
|
|
@ -52,6 +65,7 @@ mv /tmp/setup_app ~/app/setup_app
|
|||
sudo chmod +x ~/app/setup_app
|
||||
|
||||
sudo npm install -g npm@7.20.0
|
||||
sudo chown -R 1000:1000 "/home/ubuntu/.npm"
|
||||
|
||||
# Building ToolJet app
|
||||
sudo npm install -g @nestjs/cli
|
||||
|
|
|
|||
|
|
@ -37,6 +37,21 @@ FROM node:14.17.3-alpine
|
|||
ENV NODE_ENV=production
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
RUN apk add postgresql-client freetds
|
||||
|
||||
# Install Instantclient Basic Light Oracle and Dependencies
|
||||
RUN apk --no-cache add libaio libnsl libc6-compat curl && \
|
||||
cd /tmp && \
|
||||
curl -o instantclient-basiclite.zip https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip -SL && \
|
||||
unzip instantclient-basiclite.zip && \
|
||||
mv instantclient*/ /usr/lib/instantclient && \
|
||||
rm instantclient-basiclite.zip && \
|
||||
ln -s /usr/lib/instantclient/libclntsh.so.19.1 /usr/lib/libclntsh.so && \
|
||||
ln -s /usr/lib/instantclient/libocci.so.19.1 /usr/lib/libocci.so && \
|
||||
ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2 && \
|
||||
ln -s /lib64/ld-linux-x86-64.so.2 /usr/lib/ld-linux-x86-64.so.2
|
||||
|
||||
ENV LD_LIBRARY_PATH /usr/lib/instantclient
|
||||
|
||||
RUN mkdir -p /app
|
||||
|
||||
# copy npm scripts
|
||||
|
|
|
|||
|
|
@ -30,6 +30,20 @@ ENV NODE_ENV=production
|
|||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
RUN apk add postgresql-client freetds
|
||||
|
||||
# Install Instantclient Basic Light Oracle and Dependencies
|
||||
RUN apk --no-cache add libaio libnsl libc6-compat curl && \
|
||||
cd /tmp && \
|
||||
curl -o instantclient-basiclite.zip https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip -SL && \
|
||||
unzip instantclient-basiclite.zip && \
|
||||
mv instantclient*/ /usr/lib/instantclient && \
|
||||
rm instantclient-basiclite.zip && \
|
||||
ln -s /usr/lib/instantclient/libclntsh.so.19.1 /usr/lib/libclntsh.so && \
|
||||
ln -s /usr/lib/instantclient/libocci.so.19.1 /usr/lib/libocci.so && \
|
||||
ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2 && \
|
||||
ln -s /lib64/ld-linux-x86-64.so.2 /usr/lib/ld-linux-x86-64.so.2
|
||||
|
||||
ENV LD_LIBRARY_PATH /usr/lib/instantclient
|
||||
|
||||
RUN mkdir -p /app
|
||||
|
||||
# copy npm scripts
|
||||
|
|
|
|||
|
|
@ -1,6 +1,20 @@
|
|||
# pull official base image
|
||||
FROM node:14.17.3-alpine
|
||||
RUN apk add postgresql-client freetds
|
||||
RUN apk add postgresql-client
|
||||
|
||||
# Install Instantclient Basic Light Oracle and Dependencies
|
||||
RUN apk --no-cache add libaio libnsl libc6-compat curl && \
|
||||
cd /tmp && \
|
||||
curl -o instantclient-basiclite.zip https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip -SL && \
|
||||
unzip instantclient-basiclite.zip && \
|
||||
mv instantclient*/ /usr/lib/instantclient && \
|
||||
rm instantclient-basiclite.zip && \
|
||||
ln -s /usr/lib/instantclient/libclntsh.so.19.1 /usr/lib/libclntsh.so && \
|
||||
ln -s /usr/lib/instantclient/libocci.so.19.1 /usr/lib/libocci.so && \
|
||||
ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2 && \
|
||||
ln -s /lib64/ld-linux-x86-64.so.2 /usr/lib/ld-linux-x86-64.so.2
|
||||
|
||||
ENV LD_LIBRARY_PATH /usr/lib/instantclient
|
||||
|
||||
ENV NODE_ENV=development
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
|
|
|
|||
47
docs/docs/data-sources/oracledb.md
Normal file
47
docs/docs/data-sources/oracledb.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
# Oracle DB
|
||||
|
||||
ToolJet can connect to Oracle databases to read and write data.
|
||||
|
||||
## Connection
|
||||
|
||||
A Oracle DB can be connected with the following credentails:
|
||||
- **Host**
|
||||
- **Port**
|
||||
- **SID / Service Name** ( Database name must be a SID / Service Name )
|
||||
- **Database Name**
|
||||
- **SSL**
|
||||
- **Username**
|
||||
- **Password**
|
||||
- **Client Library Path** ( Only need for local setup )
|
||||
|
||||
:::info
|
||||
You can also test your connection before saving the configuration by clicking on `Test Connection` button.
|
||||
:::
|
||||
|
||||
Click on **Test connection** button to verify if the credentials are correct and that the database is accessible to ToolJet server. Click on **Save** button to save the data source.
|
||||
|
||||
## Querying Oracle DB
|
||||
|
||||
Once you have added a Oracle DB data source, click on `+` button of the query manager to create a new query. There are two modes by which you can query SQL:
|
||||
|
||||
1. **[SQL mode](/docs/data-sources/oracledb#sql-mode)**
|
||||
2. **[GUI mode](/docs/data-sources/oracledb#gui-mode)**
|
||||
|
||||
#### SQL mode
|
||||
|
||||
SQL mode can be used to write raw SQL queries. Select SQL mode from the dropdown and enter the SQL query in the editor. Click on the `run` button to run the query.
|
||||
|
||||
**NOTE**: Query should be saved before running.
|
||||
|
||||
#### GUI mode
|
||||
|
||||
GUI mode can be used to query Oracle database without writing queries. Select GUI mode from the dropdown and then choose the operation **Bulk update using primary key**. Enter the **Table** name and **Primary key column** name. Now, in the editor enter the records in the form of an array of objects.
|
||||
|
||||
**Example**: `{{ [ {id: 1, channel: 33}, {id:2, channel:24} ] }}`
|
||||
|
||||
Click on the **run** button to run the query. **NOTE**: Query should be saved before running.
|
||||
|
||||
:::tip
|
||||
Query results can be transformed using transformations. Read our transformations documentation to see how: **[link](/docs/tutorial/transformations)**
|
||||
:::
|
||||
|
|
@ -187,6 +187,15 @@ This is required when client is built separately.
|
|||
| TOOLJET_SERVER_URL | the URL of ToolJet server ( eg: https://server.tooljet.com ) |
|
||||
|
||||
|
||||
#### Server Port ( optional)
|
||||
|
||||
This could be used to for local development, it will set the server url like so: `http://localhost:<TOOLJET_SERVER_PORT>`
|
||||
|
||||
| variable | description |
|
||||
|---------------------|-----------------------------------------|
|
||||
| TOOLJET_SERVER_PORT | the port of ToolJet server ( eg: 3000 ) |
|
||||
|
||||
|
||||
#### Asset path ( optionally required )
|
||||
|
||||
This is required when the assets for the client are to be loaded from elsewhere (eg: CDN).
|
||||
|
|
|
|||
|
|
@ -156,5 +156,5 @@ strong {
|
|||
}
|
||||
|
||||
.menu:hover {
|
||||
overflow-y: overlay;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
|
|
|||
2
frontend/package-lock.json
generated
2
frontend/package-lock.json
generated
|
|
@ -124,6 +124,7 @@
|
|||
"@tooljet-plugins/mssql": "file:packages/mssql",
|
||||
"@tooljet-plugins/mysql": "file:packages/mysql",
|
||||
"@tooljet-plugins/n8n": "file:packages/n8n",
|
||||
"@tooljet-plugins/oracledb": "file:packages/oracledb",
|
||||
"@tooljet-plugins/postgresql": "file:packages/postgresql",
|
||||
"@tooljet-plugins/redis": "file:packages/redis",
|
||||
"@tooljet-plugins/restapi": "file:packages/restapi",
|
||||
|
|
@ -22627,6 +22628,7 @@
|
|||
"@tooljet-plugins/mssql": "file:packages/mssql",
|
||||
"@tooljet-plugins/mysql": "file:packages/mysql",
|
||||
"@tooljet-plugins/n8n": "file:packages/n8n",
|
||||
"@tooljet-plugins/oracledb": "file:packages/oracledb",
|
||||
"@tooljet-plugins/postgresql": "file:packages/postgresql",
|
||||
"@tooljet-plugins/redis": "file:packages/redis",
|
||||
"@tooljet-plugins/restapi": "file:packages/restapi",
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ export function CodeHinter({
|
|||
className={`row${height === '150px' || height === '300px' ? ' tablr-gutter-x-0' : ''}`}
|
||||
style={{ width: width, display: codeShow ? 'flex' : 'none' }}
|
||||
>
|
||||
<div className={`col`} style={{ marginBottom: '0.5rem' }}>
|
||||
<div className={`col code-hinter-col`} style={{ marginBottom: '0.5rem' }}>
|
||||
<div className="code-hinter-wrapper" style={{ width: '100%', backgroundColor: darkMode && '#272822' }}>
|
||||
<div
|
||||
className={`${defaultClassName} ${className || 'codehinter-default-input'}`}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@ import React from 'react';
|
|||
|
||||
export default function FxButton({ active, onPress }) {
|
||||
return (
|
||||
<div className={`fx-button ${active ? 'active' : ''} unselectable`} onClick={onPress}>
|
||||
<div
|
||||
title="Use fx for property to have a programmatically determined value instead of a fixed value"
|
||||
className={`fx-button ${active ? 'active' : ''} unselectable`}
|
||||
onClick={onPress}
|
||||
>
|
||||
Fx
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ export const Map = function Map({
|
|||
}
|
||||
|
||||
const addNewMarkersProp = component.definition.properties.addNewMarkers;
|
||||
const canAddNewMarkers = addNewMarkersProp ? addNewMarkersProp.value : false;
|
||||
const canAddNewMarkers = addNewMarkersProp ? resolveReferences(addNewMarkersProp.value, currentState) : false;
|
||||
|
||||
const canSearchProp = component.definition.properties.canSearch;
|
||||
const canSearch = canSearchProp ? canSearchProp.value : false;
|
||||
const canSearch = canSearchProp ? resolveReferences(canSearchProp.value, currentState) : false;
|
||||
const widgetVisibility = component.definition.styles?.visibility?.value ?? true;
|
||||
const disabledState = component.definition.styles?.disabledState?.value ?? false;
|
||||
|
||||
|
|
|
|||
|
|
@ -352,12 +352,13 @@ export function Table({
|
|||
Cell: function (cell) {
|
||||
const rowChangeSet = changeSet ? changeSet[cell.row.index] : null;
|
||||
const cellValue = rowChangeSet ? rowChangeSet[column.name] || cell.value : cell.value;
|
||||
const rowData = tableData[cell.row.index];
|
||||
|
||||
switch (columnType) {
|
||||
case 'string':
|
||||
case undefined:
|
||||
case 'default': {
|
||||
const textColor = resolveReferences(column.textColor, currentState, '', { cellValue });
|
||||
const textColor = resolveReferences(column.textColor, currentState, '', { cellValue, rowData });
|
||||
|
||||
const cellStyles = {
|
||||
color: textColor ?? '',
|
||||
|
|
|
|||
|
|
@ -666,7 +666,8 @@ export const componentTypes = [
|
|||
borderRadius: { type: 'code', displayName: 'Border radius' },
|
||||
},
|
||||
exposedVariables: {
|
||||
value: {},
|
||||
value:
|
||||
'ToolJet is an open-source low-code platform for building and deploying internal tools with minimal engineering efforts 🚀',
|
||||
},
|
||||
definition: {
|
||||
others: {
|
||||
|
|
|
|||
|
|
@ -189,7 +189,10 @@ export const DraggableBox = function DraggableBox({
|
|||
>
|
||||
{inCanvas ? (
|
||||
<div
|
||||
className={cx(`draggable-box widget-${id}`, { [className]: !!className })}
|
||||
className={cx(`draggable-box widget-${id}`, {
|
||||
[className]: !!className,
|
||||
'draggable-box-in-editor': mode === 'edit',
|
||||
})}
|
||||
onMouseEnter={(e) => {
|
||||
if (e.currentTarget.className.includes(`widget-${id}`)) {
|
||||
onComponentHover(id);
|
||||
|
|
|
|||
|
|
@ -1145,7 +1145,7 @@ class Editor extends React.Component {
|
|||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<h5 className="mb-0 common-sidebar-popover-margin">QUERIES</h5>
|
||||
<h5 className="mb-0">QUERIES</h5>
|
||||
<span onClick={this.toggleQueryEditor} className="cursor-pointer m-1" data-tip="Show query editor">
|
||||
<svg
|
||||
style={{ transform: 'rotate(180deg)' }}
|
||||
|
|
@ -1178,9 +1178,9 @@ class Editor extends React.Component {
|
|||
}}
|
||||
>
|
||||
<div className="row main-row">
|
||||
<div className="col-3 data-pane">
|
||||
<div className="data-pane">
|
||||
<div className="queries-container">
|
||||
<div className="queries-header row">
|
||||
<div className="queries-header row" style={{ marginLeft: '1.5px' }}>
|
||||
{showQuerySearchField && (
|
||||
<div className="col-12 p-1">
|
||||
<div className="queries-search px-1">
|
||||
|
|
@ -1197,7 +1197,7 @@ class Editor extends React.Component {
|
|||
<>
|
||||
<div className="col">
|
||||
<h5
|
||||
style={{ fontSize: '14px', marginLeft: ' 32px' }}
|
||||
style={{ fontSize: '14px', marginLeft: ' 6px' }}
|
||||
className="py-1 px-3 mt-2 text-muted"
|
||||
>
|
||||
Queries
|
||||
|
|
@ -1241,7 +1241,7 @@ class Editor extends React.Component {
|
|||
</center>
|
||||
</div>
|
||||
) : (
|
||||
<div className="query-list p-1 mt-1" style={{ marginLeft: '32px' }}>
|
||||
<div className="query-list p-1 mt-1">
|
||||
<div>{dataQueries.map((query) => this.renderDataQuery(query))}</div>
|
||||
{dataQueries.length === 0 && (
|
||||
<div className="mt-5">
|
||||
|
|
@ -1268,7 +1268,7 @@ class Editor extends React.Component {
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-9 query-definition-pane-wrapper">
|
||||
<div className="query-definition-pane-wrapper">
|
||||
{!loadingDataSources && (
|
||||
<div className="query-definition-pane">
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -40,10 +40,7 @@ export const LeftSidebarDataSources = ({ appId, editingVersionId, darkMode, data
|
|||
className={`left-sidebar-item sidebar-datasources left-sidebar-layout ${open && 'active'}`}
|
||||
text={'Sources'}
|
||||
/>
|
||||
<div
|
||||
{...content}
|
||||
className={`card popover common-sidebar-popover-margin datasources-popover ${open ? 'show' : 'hide'}`}
|
||||
>
|
||||
<div {...content} className={`card popover datasources-popover ${open ? 'show' : 'hide'}`}>
|
||||
<LeftSidebarDataSources.Container
|
||||
renderDataSource={renderDataSource}
|
||||
dataSources={dataSources}
|
||||
|
|
|
|||
|
|
@ -122,9 +122,7 @@ export const LeftSidebarDebugger = ({ darkMode, errors }) => {
|
|||
/>
|
||||
<div
|
||||
{...content}
|
||||
className={`card popover common-sidebar-popover-margin debugger-popover ${
|
||||
open || popoverPinned ? 'show' : 'hide'
|
||||
}`}
|
||||
className={`card popover debugger-popover ${open || popoverPinned ? 'show' : 'hide'}`}
|
||||
style={{ minWidth: '350px', minHeight: '108px', resize: 'horizontal', maxWidth: '50%' }}
|
||||
>
|
||||
<div className="row-header">
|
||||
|
|
|
|||
|
|
@ -24,10 +24,7 @@ export const LeftSidebarGlobalSettings = ({ globalSettings, globalSettingsChange
|
|||
className={`left-sidebar-item left-sidebar-layout ${open && 'active'}`}
|
||||
text={'Settings'}
|
||||
/>
|
||||
<div
|
||||
{...content}
|
||||
className={`card popover global-settings-popover common-sidebar-popover-margin ${open ? 'show' : 'hide'}`}
|
||||
>
|
||||
<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">
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export const LeftSidebarInspector = ({ darkMode, currentState }) => {
|
|||
/>
|
||||
<div
|
||||
{...content}
|
||||
className={`card popover common-sidebar-popover-margin ${open || popoverPinned ? 'show' : 'hide'}`}
|
||||
className={`card popover ${open || popoverPinned ? 'show' : 'hide'}`}
|
||||
style={{ resize: 'horizontal', maxWidth: '50%' }}
|
||||
>
|
||||
<SidebarPinnedButton
|
||||
|
|
|
|||
|
|
@ -1,16 +1,28 @@
|
|||
import React from 'react';
|
||||
|
||||
const GroupHeader = ({ darkMode }) => {
|
||||
const GroupHeader = ({ addNewKeyValuePair, paramType, descText }) => {
|
||||
return (
|
||||
<div className={`group-header row py-2 mb-1 mx-0 ${darkMode && 'bg-dark'}`}>
|
||||
<div className="col-5">
|
||||
<span className="text-uppercase small strong" style={{ fontSize: '10px' }}>
|
||||
Key
|
||||
</span>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<span className="text-uppercase small strong" style={{ fontSize: '10px' }}>
|
||||
Value
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<div className="content-title">{descText}</div>
|
||||
<div>
|
||||
<span onClick={() => addNewKeyValuePair(paramType)} role="button">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="icon icon-tabler icon-tabler-square-plus svg-plus"
|
||||
width="36"
|
||||
height="36"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="1.5"
|
||||
stroke="#737373"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<rect x="4" y="4" width="16" height="16" rx="2" />
|
||||
<line x1="9" y1="12" x2="15" y2="12" />
|
||||
<line x1="12" y1="9" x2="12" y2="15" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { CodeHinter } from '../../../CodeBuilder/CodeHinter';
|
||||
import GroupHeader from './GroupHeader';
|
||||
import TabContent from './TabContent';
|
||||
|
||||
export default ({
|
||||
options = [],
|
||||
|
|
@ -9,72 +9,22 @@ export default ({
|
|||
removeKeyValuePair,
|
||||
addNewKeyValuePair,
|
||||
onChange,
|
||||
darkMode,
|
||||
componentName,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col px-3">
|
||||
<GroupHeader darkMode={darkMode} />
|
||||
</div>
|
||||
<div className="col-auto px-2">
|
||||
<span onClick={() => addNewKeyValuePair('body')} className="btn-sm col-2 mt-1 color-primary" role="button">
|
||||
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13 0.75C9.76323 0.789051 6.67003 2.09221 4.38112 4.38112C2.09221 6.67003 0.789051 9.76323 0.75 13C0.789051 16.2368 2.09221 19.33 4.38112 21.6189C6.67003 23.9078 9.76323 25.2109 13 25.25C16.2368 25.2109 19.33 23.9078 21.6189 21.6189C23.9078 19.33 25.2109 16.2368 25.25 13C25.2109 9.76323 23.9078 6.67003 21.6189 4.38112C19.33 2.09221 16.2368 0.789051 13 0.75ZM20 13.875H13.875V20H12.125V13.875H6V12.125H12.125V6H13.875V12.125H20V13.875Z"
|
||||
fill="#4D72FA"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<GroupHeader addNewKeyValuePair={addNewKeyValuePair} paramType={'body'} descText={'Body Parameters'} />
|
||||
|
||||
<div className="row px-2 pb-3">
|
||||
{options.map((option, index) => {
|
||||
return (
|
||||
<div className="row input-group my-1" key={index}>
|
||||
<div className="col-5 field">
|
||||
<CodeHinter
|
||||
currentState={currentState}
|
||||
initialValue={option[0]}
|
||||
theme={theme}
|
||||
height={'32px'}
|
||||
width="80%"
|
||||
placeholder="key"
|
||||
onChange={onChange('body', 0, index)}
|
||||
componentName={`${componentName}/body::key::${index}`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-5 field tab-pane-body">
|
||||
<CodeHinter
|
||||
currentState={currentState}
|
||||
initialValue={option[1]}
|
||||
theme={theme}
|
||||
height={'32px'}
|
||||
width="80%"
|
||||
placeholder="value"
|
||||
onChange={onChange('body', 1, index)}
|
||||
componentName={`${componentName}/body::value::${index}`}
|
||||
/>
|
||||
</div>
|
||||
{index > 0 && (
|
||||
<span
|
||||
style={{ marginLeft: '-5%' }}
|
||||
className="btn-sm col-2 mt-1 color-primary"
|
||||
role="button"
|
||||
onClick={() => {
|
||||
removeKeyValuePair('body', index);
|
||||
}}
|
||||
>
|
||||
Remove
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<TabContent
|
||||
options={options}
|
||||
currentState={currentState}
|
||||
theme={theme}
|
||||
removeKeyValuePair={removeKeyValuePair}
|
||||
onChange={onChange}
|
||||
componentName={componentName}
|
||||
tabType={'body'}
|
||||
paramType={'body'}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
import React from 'react';
|
||||
import { CodeHinter } from '../../../CodeBuilder/CodeHinter';
|
||||
|
||||
export default ({
|
||||
options = [],
|
||||
currentState,
|
||||
theme,
|
||||
onChange,
|
||||
componentName,
|
||||
removeKeyValuePair,
|
||||
paramType,
|
||||
tabType,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="tab-content-wrapper">
|
||||
{options.map((option, index) => {
|
||||
return (
|
||||
<div className="mt-1 row-container" key={index}>
|
||||
<div className="fields-container">
|
||||
<div className="field" style={{ width: '100%' }}>
|
||||
<CodeHinter
|
||||
currentState={currentState}
|
||||
initialValue={option[0]}
|
||||
theme={theme}
|
||||
height={'32px'}
|
||||
placeholder="key"
|
||||
onChange={onChange(paramType, 0, index)}
|
||||
componentName={`${componentName}/${tabType}::key::${index}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="field" style={{ width: '100%' }}>
|
||||
<CodeHinter
|
||||
currentState={currentState}
|
||||
initialValue={option[1]}
|
||||
theme={theme}
|
||||
height={'32px'}
|
||||
placeholder="value"
|
||||
onChange={onChange(paramType, 1, index)}
|
||||
componentName={`${componentName}/${tabType}::value::${index}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
className="color-primary delete-btn-wrapper"
|
||||
role="button"
|
||||
onClick={() => {
|
||||
removeKeyValuePair(paramType, index);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="icon icon-tabler icon-tabler-trash"
|
||||
width="36"
|
||||
height="36"
|
||||
viewBox="0 0 25 25"
|
||||
strokeWidth="1.5"
|
||||
stroke="#ff2825"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<line x1="4" y1="7" x2="20" y2="7" />
|
||||
<line x1="10" y1="11" x2="10" y2="17" />
|
||||
<line x1="14" y1="11" x2="14" y2="17" />
|
||||
<path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12" />
|
||||
<path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { CodeHinter } from '../../../CodeBuilder/CodeHinter';
|
||||
import TabContent from './TabContent';
|
||||
import GroupHeader from './GroupHeader';
|
||||
|
||||
export default ({
|
||||
|
|
@ -9,72 +9,21 @@ export default ({
|
|||
removeKeyValuePair,
|
||||
addNewKeyValuePair,
|
||||
onChange,
|
||||
darkMode,
|
||||
componentName,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col px-3">
|
||||
<GroupHeader darkMode={darkMode} />
|
||||
</div>
|
||||
<div className="col-auto px-2">
|
||||
<span onClick={() => addNewKeyValuePair('headers')} className="btn-sm col-2 mt-1 color-primary" role="button">
|
||||
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13 0.75C9.76323 0.789051 6.67003 2.09221 4.38112 4.38112C2.09221 6.67003 0.789051 9.76323 0.75 13C0.789051 16.2368 2.09221 19.33 4.38112 21.6189C6.67003 23.9078 9.76323 25.2109 13 25.25C16.2368 25.2109 19.33 23.9078 21.6189 21.6189C23.9078 19.33 25.2109 16.2368 25.25 13C25.2109 9.76323 23.9078 6.67003 21.6189 4.38112C19.33 2.09221 16.2368 0.789051 13 0.75ZM20 13.875H13.875V20H12.125V13.875H6V12.125H12.125V6H13.875V12.125H20V13.875Z"
|
||||
fill="#4D72FA"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row px-2 pb-3">
|
||||
{options.map((option, index) => {
|
||||
return (
|
||||
<div className="row input-group my-1" key={index}>
|
||||
<div className="col-5 field">
|
||||
<CodeHinter
|
||||
currentState={currentState}
|
||||
initialValue={option[0]}
|
||||
theme={theme}
|
||||
height={'32px'}
|
||||
width="80%"
|
||||
placeholder="key"
|
||||
onChange={onChange('headers', 0, index)}
|
||||
componentName={`${componentName}/headers::key::${index}`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-5 field tab-pane-body">
|
||||
<CodeHinter
|
||||
currentState={currentState}
|
||||
initialValue={option[1]}
|
||||
theme={theme}
|
||||
height={'32px'}
|
||||
width="80%"
|
||||
placeholder="value"
|
||||
onChange={onChange('headers', 1, index)}
|
||||
componentName={`${componentName}/headers::value::${index}`}
|
||||
/>
|
||||
</div>
|
||||
{index > 0 && (
|
||||
<span
|
||||
style={{ marginLeft: '-5%' }}
|
||||
className="btn-sm col-auto mt-1 color-primary"
|
||||
role="button"
|
||||
onClick={() => {
|
||||
removeKeyValuePair('headers', index);
|
||||
}}
|
||||
>
|
||||
Remove
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<GroupHeader addNewKeyValuePair={addNewKeyValuePair} paramType={'headers'} descText="Request Headers" />
|
||||
<TabContent
|
||||
options={options}
|
||||
currentState={currentState}
|
||||
theme={theme}
|
||||
removeKeyValuePair={removeKeyValuePair}
|
||||
onChange={onChange}
|
||||
componentName={componentName}
|
||||
tabType={'headers'}
|
||||
paramType={'headers'}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { CodeHinter } from '../../../CodeBuilder/CodeHinter';
|
||||
import GroupHeader from './GroupHeader';
|
||||
import TabContent from './TabContent';
|
||||
|
||||
export default ({
|
||||
options = [],
|
||||
|
|
@ -9,76 +9,21 @@ export default ({
|
|||
removeKeyValuePair,
|
||||
addNewKeyValuePair,
|
||||
onChange,
|
||||
darkMode,
|
||||
componentName,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col px-3">
|
||||
<GroupHeader darkMode={darkMode} />
|
||||
</div>
|
||||
<div className="col-auto px-2">
|
||||
<span
|
||||
onClick={() => addNewKeyValuePair('url_params')}
|
||||
className="btn-sm col-2 mt-1 color-primary"
|
||||
role="button"
|
||||
>
|
||||
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M13 0.75C9.76323 0.789051 6.67003 2.09221 4.38112 4.38112C2.09221 6.67003 0.789051 9.76323 0.75 13C0.789051 16.2368 2.09221 19.33 4.38112 21.6189C6.67003 23.9078 9.76323 25.2109 13 25.25C16.2368 25.2109 19.33 23.9078 21.6189 21.6189C23.9078 19.33 25.2109 16.2368 25.25 13C25.2109 9.76323 23.9078 6.67003 21.6189 4.38112C19.33 2.09221 16.2368 0.789051 13 0.75ZM20 13.875H13.875V20H12.125V13.875H6V12.125H12.125V6H13.875V12.125H20V13.875Z"
|
||||
fill="#4D72FA"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row px-2 pb-3">
|
||||
{options.map((option, index) => {
|
||||
return (
|
||||
<div className="row input-group my-1" key={index}>
|
||||
<div className="col-5 field">
|
||||
<CodeHinter
|
||||
currentState={currentState}
|
||||
initialValue={option[0]}
|
||||
theme={theme}
|
||||
height={'32px'}
|
||||
width="80%"
|
||||
placeholder="key"
|
||||
onChange={onChange('url_params', 0, index)}
|
||||
componentName={`${componentName}/params::key::${index}`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-5 field tab-pane-body">
|
||||
<CodeHinter
|
||||
currentState={currentState}
|
||||
initialValue={option[1]}
|
||||
theme={theme}
|
||||
height={'32px'}
|
||||
width="80%"
|
||||
placeholder="value"
|
||||
onChange={onChange('url_params', 1, index)}
|
||||
componentName={`${componentName}/params::value::${index}`}
|
||||
/>
|
||||
</div>
|
||||
{index > 0 && (
|
||||
<span
|
||||
style={{ marginLeft: '-5%' }}
|
||||
className="btn-sm col-2 mt-1 color-primary"
|
||||
role="button"
|
||||
onClick={() => {
|
||||
removeKeyValuePair('url_params', index);
|
||||
}}
|
||||
>
|
||||
Remove
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<GroupHeader addNewKeyValuePair={addNewKeyValuePair} paramType={'url_params'} descText={'Query parameters'} />
|
||||
<TabContent
|
||||
options={options}
|
||||
currentState={currentState}
|
||||
theme={theme}
|
||||
removeKeyValuePair={removeKeyValuePair}
|
||||
onChange={onChange}
|
||||
componentName={componentName}
|
||||
tabType={'params'}
|
||||
paramType={'url_params'}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ function ControlledTabs({
|
|||
return (
|
||||
<Tab.Container activeKey={key} onSelect={(k) => setKey(k)} defaultActiveKey="headers">
|
||||
<Row>
|
||||
<div className={`col-auto keys ${darkMode ? 'dark' : ''}`}>
|
||||
<div className="keys">
|
||||
<ListGroup className="query-pane-rest-api-keys-list-group" variant="flush">
|
||||
{tabs.map((tab) => (
|
||||
<ListGroup.Item key={tab} eventKey={tab.toLowerCase()}>
|
||||
|
|
|
|||
|
|
@ -152,10 +152,11 @@ class Restapi extends React.Component {
|
|||
defaultValue={{ label: 'GET', value: 'get' }}
|
||||
placeholder="Method"
|
||||
styles={selectStyles}
|
||||
isSearchable={false}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col field mx-3 w-100" style={{ display: 'flex', maxWidth: '700px' }}>
|
||||
<div className="col field w-100" style={{ display: 'flex', marginLeft: 16 }}>
|
||||
{dataSourceURL && (
|
||||
<BaseUrl theme={this.props.darkMode ? 'monokai' : 'default'} dataSourceURL={dataSourceURL} />
|
||||
)}
|
||||
|
|
@ -177,7 +178,7 @@ class Restapi extends React.Component {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className={`query-pane-restapi-tabs mt-3 px-2 ${this.props.darkMode ? 'dark' : ''}`}>
|
||||
<div className={`query-pane-restapi-tabs mt-3 ${this.props.darkMode ? 'dark' : ''}`}>
|
||||
<Tabs
|
||||
theme={this.props.darkMode ? 'monokai' : 'default'}
|
||||
options={this.state.options}
|
||||
|
|
|
|||
|
|
@ -375,7 +375,7 @@ let QueryManager = class QueryManager extends React.Component {
|
|||
<ReactTooltip type="dark" effect="solid" delayShow={250} />
|
||||
<div className="row header">
|
||||
<div className="col">
|
||||
{(addingQuery || editingQuery) && (
|
||||
{(addingQuery || editingQuery) && selectedDataSource && (
|
||||
<div className="nav-header">
|
||||
<ul className="nav nav-tabs query-manager-header" data-bs-toggle="tabs">
|
||||
<li className="nav-item">
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ export const WidgetManager = function WidgetManager({ componentTypes, zoomLevel,
|
|||
const formSection = { title: 'forms', items: [] };
|
||||
const integrationSection = { title: 'integrations', items: [] };
|
||||
const otherSection = { title: 'others', items: [] };
|
||||
const allWidgets = [];
|
||||
|
||||
const commonItems = ['Table', 'Chart', 'Button', 'Text', 'Datepicker'];
|
||||
const formItems = [
|
||||
|
|
@ -96,6 +97,7 @@ export const WidgetManager = function WidgetManager({ componentTypes, zoomLevel,
|
|||
const layoutItems = ['Container', 'Listview', 'Tabs', 'Modal'];
|
||||
|
||||
filteredComponents.forEach((f) => {
|
||||
if (searchQuery) allWidgets.push(f);
|
||||
if (commonItems.includes(f.name)) commonSection.items.push(f);
|
||||
if (formItems.includes(f.name)) formSection.items.push(f);
|
||||
else if (integrationItems.includes(f.name)) integrationSection.items.push(f);
|
||||
|
|
@ -103,15 +105,19 @@ export const WidgetManager = function WidgetManager({ componentTypes, zoomLevel,
|
|||
else otherSection.items.push(f);
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderList(commonSection.title, commonSection.items)}
|
||||
{renderList(layoutsSection.title, layoutsSection.items)}
|
||||
{renderList(formSection.title, formSection.items)}
|
||||
{renderList(otherSection.title, otherSection.items)}
|
||||
{renderList(integrationSection.title, integrationSection.items)}
|
||||
</>
|
||||
);
|
||||
if (allWidgets.length > 0) {
|
||||
return <>{renderList(undefined, allWidgets)}</>;
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
{renderList(commonSection.title, commonSection.items)}
|
||||
{renderList(layoutsSection.title, layoutsSection.items)}
|
||||
{renderList(formSection.title, formSection.items)}
|
||||
{renderList(otherSection.title, otherSection.items)}
|
||||
{renderList(integrationSection.title, integrationSection.items)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
}
|
||||
.popover {
|
||||
position: fixed;
|
||||
left: 3%;
|
||||
left: 76px;
|
||||
top: 55px;
|
||||
overflow: auto;
|
||||
max-height: 60%;
|
||||
|
|
|
|||
|
|
@ -167,10 +167,6 @@ button {
|
|||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
.common-sidebar-popover-margin{
|
||||
margin-left: 33px;
|
||||
}
|
||||
|
||||
.left-sidebar {
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
|
@ -457,11 +453,10 @@ button {
|
|||
width: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.query-pane {
|
||||
height: 350px;
|
||||
position: fixed;
|
||||
left: 3%;
|
||||
left: 76px; //sidebar is 76px
|
||||
right: 300px;
|
||||
bottom: 0;
|
||||
overflow-x: hidden;
|
||||
|
|
@ -524,6 +519,7 @@ button {
|
|||
}
|
||||
|
||||
.query-definition-pane-wrapper {
|
||||
width: 72%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
height: 100%;
|
||||
|
|
@ -557,6 +553,7 @@ button {
|
|||
}
|
||||
|
||||
.data-pane {
|
||||
width: 28%;
|
||||
border: solid rgba(0, 0, 0, 0.125);
|
||||
border-width: 0px 1px 0px 0px;
|
||||
overflow-x: hidden;
|
||||
|
|
@ -2359,6 +2356,11 @@ hr {
|
|||
.CodeMirror {
|
||||
font-family: "Roboto", sans-serif;
|
||||
}
|
||||
.CodeMirror-placeholder {
|
||||
height: inherit !important;
|
||||
position: absolute !important;
|
||||
margin-top: 3px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.codehinter-query-editor-input {
|
||||
|
|
@ -2422,7 +2424,7 @@ hr {
|
|||
}
|
||||
}
|
||||
|
||||
.draggable-box:hover {
|
||||
.draggable-box-in-editor:hover {
|
||||
z-index: 3 !important;
|
||||
}
|
||||
|
||||
|
|
@ -3919,6 +3921,9 @@ input[type="text"] {
|
|||
width: 200px;
|
||||
border-radius: 5px !important;
|
||||
}
|
||||
input:focus {
|
||||
width: 300px;
|
||||
}
|
||||
.input-icon .input-icon-addon {
|
||||
display: flex;
|
||||
}
|
||||
|
|
@ -4202,13 +4207,11 @@ input[type="text"] {
|
|||
}
|
||||
|
||||
.query-pane-restapi-tabs.dark {
|
||||
background: $bg-dark !important;
|
||||
border-color: $border-grey-dark !important;
|
||||
|
||||
.list-group-item {
|
||||
color: $disabled !important;
|
||||
|
||||
&:hover {
|
||||
background-color: #262b33 !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
}
|
||||
.list-group-item.active {
|
||||
|
|
@ -4216,28 +4219,17 @@ input[type="text"] {
|
|||
}
|
||||
}
|
||||
.query-pane-restapi-tabs {
|
||||
background: #f7f9fc;
|
||||
border: 1px solid #d2ddec;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
margin: 0px;
|
||||
height: fit-content;
|
||||
min-height: 160px;
|
||||
width: 100%;
|
||||
.row {
|
||||
height: inherit;
|
||||
|
||||
.keys {
|
||||
border-right: 1px solid #d2ddec !important;
|
||||
min-height: 90px;
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
.keys.dark {
|
||||
border-color: $border-grey-dark !important;
|
||||
}
|
||||
.rest-api-tab-content {
|
||||
margin-top: 1rem;
|
||||
min-height: 160px;
|
||||
|
||||
.rest-api-tabpanes {
|
||||
display: none;
|
||||
|
|
@ -4246,40 +4238,92 @@ input[type="text"] {
|
|||
.rest-api-tabpanes.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.svg-plus {
|
||||
stroke: $primary;
|
||||
}
|
||||
|
||||
.delete-btn-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.code-hinter-col {
|
||||
margin-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.tab-content-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .3rem;
|
||||
}
|
||||
|
||||
.row-container{
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.fields-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.query-pane-rest-api-keys-list-group {
|
||||
margin-top: 1.25rem;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.list-group-item {
|
||||
border: none !important;
|
||||
cursor: pointer;
|
||||
margin-bottom: 11px;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
padding: 3px !important;
|
||||
padding: 0px !important;
|
||||
margin-right: 20px;
|
||||
height: 22px;
|
||||
width: 72px;
|
||||
color: #737373;
|
||||
|
||||
span {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-radius: 4px !important;
|
||||
background-color: $bg-light;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
.list-group-item.active {
|
||||
border-radius: 4px !important;
|
||||
background-color: $primary !important;
|
||||
z-index: inherit !important;
|
||||
.list-group-item + .list-group-item.active {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.list-group-item.active {
|
||||
background-color: transparent !important;
|
||||
color: #000;
|
||||
z-index: inherit !important;
|
||||
border-bottom: 2px solid $primary !important;
|
||||
}
|
||||
}
|
||||
|
||||
.query-pane-rest-api-keys-list-group.dark + .list-group-item {
|
||||
&:hover{
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.content-title {
|
||||
font-size: 12px;
|
||||
color: #a3a3a3;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
// ** Query Panel: REST API Tabs **
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ const environment = process.env.NODE_ENV === 'production' ? 'production' : 'deve
|
|||
|
||||
const API_URL = {
|
||||
production: process.env.TOOLJET_SERVER_URL || '',
|
||||
development: 'http://localhost:3000',
|
||||
development: `http://localhost:${process.env.TOOLJET_SERVER_PORT || 3000}`,
|
||||
};
|
||||
|
||||
const ASSET_PATH = process.env.ASSET_PATH || '/';
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ module.exports = {
|
|||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
'plugin:cypress/recommended',
|
||||
],
|
||||
ignorePatterns: ['.eslintrc.js'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
|
|
|
|||
99
plugins/package-lock.json
generated
99
plugins/package-lock.json
generated
|
|
@ -24,6 +24,7 @@
|
|||
"@tooljet-plugins/mssql": "file:packages/mssql",
|
||||
"@tooljet-plugins/mysql": "file:packages/mysql",
|
||||
"@tooljet-plugins/n8n": "file:packages/n8n",
|
||||
"@tooljet-plugins/oracledb": "file:packages/oracledb",
|
||||
"@tooljet-plugins/postgresql": "file:packages/postgresql",
|
||||
"@tooljet-plugins/redis": "file:packages/redis",
|
||||
"@tooljet-plugins/restapi": "file:packages/restapi",
|
||||
|
|
@ -42,7 +43,6 @@
|
|||
"@typescript-eslint/parser": "^4.31.1",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
"eslint-plugin-jest": "^24.4.2",
|
||||
"eslint-plugin-prettier": "^3.4.1",
|
||||
"jest": "^27.4.5",
|
||||
|
|
@ -4551,6 +4551,10 @@
|
|||
"resolved": "packages/n8n",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@tooljet-plugins/oracledb": {
|
||||
"resolved": "packages/oracledb",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@tooljet-plugins/postgresql": {
|
||||
"resolved": "packages/postgresql",
|
||||
"link": true
|
||||
|
|
@ -4746,6 +4750,16 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/oracledb": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/oracledb/-/oracledb-5.2.3.tgz",
|
||||
"integrity": "sha512-Mw1/LjO8WSCdVOIGopLwxoUi2pNb9NJ2NK06U/mpQhR738FNeVWXjNbla2LAZy3nTCqPHsg3phUQNqL3qhHj8w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"dotenv": "^8.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/parse-json": {
|
||||
"version": "4.0.0",
|
||||
"dev": true,
|
||||
|
|
@ -7376,6 +7390,15 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "8.6.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz",
|
||||
"integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/duplexer": {
|
||||
"version": "0.1.2",
|
||||
"dev": true,
|
||||
|
|
@ -7715,18 +7738,6 @@
|
|||
"eslint": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-cypress": {
|
||||
"version": "2.12.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.12.1.tgz",
|
||||
"integrity": "sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"globals": "^11.12.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">= 3.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jest": {
|
||||
"version": "24.7.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.7.0.tgz",
|
||||
|
|
@ -12812,6 +12823,15 @@
|
|||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/oracledb": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/oracledb/-/oracledb-5.3.0.tgz",
|
||||
"integrity": "sha512-HMJzQ6lCf287ztvvehTEmjCWA21FQ3RMvM+mgoqd4i8pkREuqFWO+y3ovsGR9moJUg4T0xjcwS8rl4mggWPxmg==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=10.16"
|
||||
}
|
||||
},
|
||||
"node_modules/os-homedir": {
|
||||
"version": "1.0.2",
|
||||
"dev": true,
|
||||
|
|
@ -16588,6 +16608,19 @@
|
|||
"react": "^17.0.2"
|
||||
}
|
||||
},
|
||||
"packages/oracledb": {
|
||||
"name": "@tooljet-plugins/oracledb",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@tooljet-plugins/common": "file:../common",
|
||||
"knex": "^0.95.14",
|
||||
"oracledb": "^5.3.0",
|
||||
"react": "^17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/oracledb": "^5.2.2"
|
||||
}
|
||||
},
|
||||
"packages/postgresql": {
|
||||
"name": "@tooljet-plugins/postgresql",
|
||||
"version": "1.0.0",
|
||||
|
|
@ -20291,6 +20324,16 @@
|
|||
"react": "^17.0.2"
|
||||
}
|
||||
},
|
||||
"@tooljet-plugins/oracledb": {
|
||||
"version": "file:packages/oracledb",
|
||||
"requires": {
|
||||
"@tooljet-plugins/common": "file:../common",
|
||||
"@types/oracledb": "^5.2.2",
|
||||
"knex": "^0.95.14",
|
||||
"oracledb": "^5.3.0",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
},
|
||||
"@tooljet-plugins/postgresql": {
|
||||
"version": "file:packages/postgresql",
|
||||
"requires": {
|
||||
|
|
@ -20523,6 +20566,16 @@
|
|||
"version": "2.4.1",
|
||||
"dev": true
|
||||
},
|
||||
"@types/oracledb": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/oracledb/-/oracledb-5.2.3.tgz",
|
||||
"integrity": "sha512-Mw1/LjO8WSCdVOIGopLwxoUi2pNb9NJ2NK06U/mpQhR738FNeVWXjNbla2LAZy3nTCqPHsg3phUQNqL3qhHj8w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"dotenv": "^8.2.0"
|
||||
}
|
||||
},
|
||||
"@types/parse-json": {
|
||||
"version": "4.0.0",
|
||||
"dev": true
|
||||
|
|
@ -22335,6 +22388,12 @@
|
|||
"is-obj": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"dotenv": {
|
||||
"version": "8.6.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz",
|
||||
"integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==",
|
||||
"dev": true
|
||||
},
|
||||
"duplexer": {
|
||||
"version": "0.1.2",
|
||||
"dev": true
|
||||
|
|
@ -22680,15 +22739,6 @@
|
|||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"eslint-plugin-cypress": {
|
||||
"version": "2.12.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.12.1.tgz",
|
||||
"integrity": "sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"globals": "^11.12.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-jest": {
|
||||
"version": "24.7.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.7.0.tgz",
|
||||
|
|
@ -26033,6 +26083,11 @@
|
|||
"word-wrap": "~1.2.3"
|
||||
}
|
||||
},
|
||||
"oracledb": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/oracledb/-/oracledb-5.3.0.tgz",
|
||||
"integrity": "sha512-HMJzQ6lCf287ztvvehTEmjCWA21FQ3RMvM+mgoqd4i8pkREuqFWO+y3ovsGR9moJUg4T0xjcwS8rl4mggWPxmg=="
|
||||
},
|
||||
"os-homedir": {
|
||||
"version": "1.0.2",
|
||||
"dev": true
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
"@tooljet-plugins/mssql": "file:packages/mssql",
|
||||
"@tooljet-plugins/mysql": "file:packages/mysql",
|
||||
"@tooljet-plugins/n8n": "file:packages/n8n",
|
||||
"@tooljet-plugins/oracledb": "file:packages/oracledb",
|
||||
"@tooljet-plugins/postgresql": "file:packages/postgresql",
|
||||
"@tooljet-plugins/redis": "file:packages/redis",
|
||||
"@tooljet-plugins/restapi": "file:packages/restapi",
|
||||
|
|
@ -52,7 +53,6 @@
|
|||
"@typescript-eslint/parser": "^4.31.1",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
"eslint-plugin-jest": "^24.4.2",
|
||||
"eslint-plugin-prettier": "^3.4.1",
|
||||
"jest": "^27.4.5",
|
||||
|
|
@ -62,4 +62,4 @@
|
|||
"ts-jest": "^27.1.2",
|
||||
"typescript": "^4.5.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,36 +4,38 @@ const airtable = require('../lib');
|
|||
const nock = require('nock');
|
||||
|
||||
describe('airtable', () => {
|
||||
const _airtable = new airtable.default()
|
||||
describe('airtable operations', () => {
|
||||
const sourceOptions = { api_key: '123456' };
|
||||
test('#list_records', async () => {
|
||||
nock(`https://api.airtable.com`).get('/v0/1/consumer/').query({ pageSize: '', offset: '' })
|
||||
const _airtable = new airtable.default();
|
||||
describe('airtable operations', () => {
|
||||
const sourceOptions = { api_key: '123456' };
|
||||
test('#list_records', async () => {
|
||||
nock(`https://api.airtable.com`)
|
||||
.get('/v0/1/consumer/')
|
||||
.query({ pageSize: '', offset: '' })
|
||||
.reply(200, { message: 'ok' });
|
||||
const queryOptions = { operation: 'list_records', base_id: 1, table_name: 'consumer' }
|
||||
const response = await _airtable.run(sourceOptions, queryOptions);
|
||||
expect(response.status).toEqual('ok');
|
||||
});
|
||||
|
||||
test('#retrieve_record', async () => {
|
||||
nock(`https://api.airtable.com`).get('/v0/1/consumer/1').reply(200, { message: 'ok' });
|
||||
const queryOptions = { operation: 'retrieve_record', base_id: 1, table_name: 'consumer', record_id: 1 }
|
||||
const response = await _airtable.run(sourceOptions, queryOptions);
|
||||
expect(response.status).toEqual('ok');
|
||||
});
|
||||
|
||||
test('#update_record', async () => {
|
||||
nock(`https://api.airtable.com`).intercept('/v0/1/consumer', 'patch').reply(200, { message: 'ok' });
|
||||
const queryOptions = { operation: 'update_record', base_id: 1, table_name: 'consumer', record_id: 1, body: "{}" }
|
||||
const response = await _airtable.run(sourceOptions, queryOptions);
|
||||
expect(response.status).toEqual('ok');
|
||||
});
|
||||
|
||||
test('#delete_record', async () => {
|
||||
nock(`https://api.airtable.com`).intercept('/v0/1/consumer/1', 'delete').reply(200, { message: 'ok' });
|
||||
const queryOptions = { operation: 'delete_record', base_id: 1, table_name: 'consumer', record_id: 1 }
|
||||
const response = await _airtable.run(sourceOptions, queryOptions);
|
||||
expect(response.status).toEqual('ok');
|
||||
});
|
||||
const queryOptions = { operation: 'list_records', base_id: 1, table_name: 'consumer' };
|
||||
const response = await _airtable.run(sourceOptions, queryOptions);
|
||||
expect(response.status).toEqual('ok');
|
||||
});
|
||||
|
||||
test('#retrieve_record', async () => {
|
||||
nock(`https://api.airtable.com`).get('/v0/1/consumer/1').reply(200, { message: 'ok' });
|
||||
const queryOptions = { operation: 'retrieve_record', base_id: 1, table_name: 'consumer', record_id: 1 };
|
||||
const response = await _airtable.run(sourceOptions, queryOptions);
|
||||
expect(response.status).toEqual('ok');
|
||||
});
|
||||
|
||||
test('#update_record', async () => {
|
||||
nock(`https://api.airtable.com`).intercept('/v0/1/consumer', 'patch').reply(200, { message: 'ok' });
|
||||
const queryOptions = { operation: 'update_record', base_id: 1, table_name: 'consumer', record_id: 1, body: '{}' };
|
||||
const response = await _airtable.run(sourceOptions, queryOptions);
|
||||
expect(response.status).toEqual('ok');
|
||||
});
|
||||
|
||||
test('#delete_record', async () => {
|
||||
nock(`https://api.airtable.com`).intercept('/v0/1/consumer/1', 'delete').reply(200, { message: 'ok' });
|
||||
const queryOptions = { operation: 'delete_record', base_id: 1, table_name: 'consumer', record_id: 1 };
|
||||
const response = await _airtable.run(sourceOptions, queryOptions);
|
||||
expect(response.status).toEqual('ok');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
const bigquery = require('../lib');
|
||||
// const bigquery = require('../lib');
|
||||
|
||||
describe('bigquery', () => {
|
||||
it.todo('needs tests');
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../lib/utils.helper');
|
||||
// const common = require('../lib/utils.helper');
|
||||
|
||||
describe('common', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const couchdb = require('../lib');
|
||||
// const couchdb = require('../lib');
|
||||
|
||||
describe('couchdb', () => {
|
||||
it.todo('needs tests');
|
||||
});
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,75 +1,50 @@
|
|||
import {
|
||||
QueryError,
|
||||
QueryResult,
|
||||
QueryService,
|
||||
ConnectionTestResult,
|
||||
} from "@tooljet-plugins/common";
|
||||
import { SourceOptions, QueryOptions } from "./types";
|
||||
import got from "got";
|
||||
const JSON5 = require("json5");
|
||||
import { QueryError, QueryResult, QueryService, ConnectionTestResult } from '@tooljet-plugins/common';
|
||||
import { SourceOptions, QueryOptions } from './types';
|
||||
import got from 'got';
|
||||
const JSON5 = require('json5');
|
||||
export default class Couchdb implements QueryService {
|
||||
async run(
|
||||
sourceOptions: SourceOptions,
|
||||
queryOptions: QueryOptions
|
||||
): Promise<QueryResult> {
|
||||
async run(sourceOptions: SourceOptions, queryOptions: QueryOptions): Promise<QueryResult> {
|
||||
let result = {};
|
||||
let response = null;
|
||||
const {
|
||||
operation,
|
||||
record_id,
|
||||
limit,
|
||||
view_url,
|
||||
start_key,
|
||||
end_key,
|
||||
skip,
|
||||
descending,
|
||||
include_docs
|
||||
} = queryOptions;
|
||||
const { username, password, port, host, database, protocol } =
|
||||
sourceOptions;
|
||||
const { operation, record_id, limit, view_url, start_key, end_key, skip, descending, include_docs } = queryOptions;
|
||||
const { username, password, port, host, database, protocol } = sourceOptions;
|
||||
const revision_id = queryOptions.rev_id;
|
||||
|
||||
const authHeader = () => {
|
||||
const combined = `${username}:${password}`;
|
||||
const key = Buffer.from(combined).toString("base64");
|
||||
const key = Buffer.from(combined).toString('base64');
|
||||
return { Authorization: `Basic ${key}` };
|
||||
};
|
||||
|
||||
try {
|
||||
switch (operation) {
|
||||
case "list_records": {
|
||||
response = await got(
|
||||
`${protocol}://${host}:${port}/${database}/_all_docs`,
|
||||
{
|
||||
method: "get",
|
||||
headers: authHeader(),
|
||||
searchParams: {
|
||||
...(limit?.length > 0 && { limit }),
|
||||
...(skip?.length > 0 && { skip }),
|
||||
...(descending && { descending }),
|
||||
...(include_docs && { include_docs }),
|
||||
},
|
||||
}
|
||||
);
|
||||
case 'list_records': {
|
||||
response = await got(`${protocol}://${host}:${port}/${database}/_all_docs`, {
|
||||
method: 'get',
|
||||
headers: authHeader(),
|
||||
searchParams: {
|
||||
...(limit?.length > 0 && { limit }),
|
||||
...(skip?.length > 0 && { skip }),
|
||||
...(descending && { descending }),
|
||||
...(include_docs && { include_docs }),
|
||||
},
|
||||
});
|
||||
result = this.parseJSON(response.body);
|
||||
break;
|
||||
}
|
||||
|
||||
case "retrieve_record": {
|
||||
response = await got(
|
||||
`${protocol}://${host}:${port}/${database}/${record_id}`,
|
||||
{
|
||||
headers: authHeader(),
|
||||
method: "get",
|
||||
}
|
||||
);
|
||||
case 'retrieve_record': {
|
||||
response = await got(`${protocol}://${host}:${port}/${database}/${record_id}`, {
|
||||
headers: authHeader(),
|
||||
method: 'get',
|
||||
});
|
||||
result = this.parseJSON(response.body);
|
||||
break;
|
||||
}
|
||||
|
||||
case "create_record": {
|
||||
case 'create_record': {
|
||||
response = await got(`${protocol}://${host}:${port}/${database}`, {
|
||||
method: "post",
|
||||
method: 'post',
|
||||
headers: authHeader(),
|
||||
json: {
|
||||
records: this.parseJSON(queryOptions.body),
|
||||
|
|
@ -79,53 +54,44 @@ export default class Couchdb implements QueryService {
|
|||
break;
|
||||
}
|
||||
|
||||
case "update_record": {
|
||||
response = await got(
|
||||
`${protocol}://${host}:${port}/${database}/${record_id}`,
|
||||
{
|
||||
method: "put",
|
||||
headers: authHeader(),
|
||||
json: {
|
||||
_rev: revision_id,
|
||||
records: this.parseJSON(queryOptions.body),
|
||||
},
|
||||
}
|
||||
);
|
||||
case 'update_record': {
|
||||
response = await got(`${protocol}://${host}:${port}/${database}/${record_id}`, {
|
||||
method: 'put',
|
||||
headers: authHeader(),
|
||||
json: {
|
||||
_rev: revision_id,
|
||||
records: this.parseJSON(queryOptions.body),
|
||||
},
|
||||
});
|
||||
result = this.parseJSON(response.body);
|
||||
break;
|
||||
}
|
||||
|
||||
case "delete_record": {
|
||||
response = await got(
|
||||
`${protocol}://${host}:${port}/${database}/${record_id}`,
|
||||
{
|
||||
method: "delete",
|
||||
headers: authHeader(),
|
||||
searchParams: {
|
||||
rev: revision_id,
|
||||
},
|
||||
}
|
||||
);
|
||||
case 'delete_record': {
|
||||
response = await got(`${protocol}://${host}:${port}/${database}/${record_id}`, {
|
||||
method: 'delete',
|
||||
headers: authHeader(),
|
||||
searchParams: {
|
||||
rev: revision_id,
|
||||
},
|
||||
});
|
||||
result = this.parseJSON(response.body);
|
||||
break;
|
||||
}
|
||||
|
||||
case "find": {
|
||||
response = await got(
|
||||
`${protocol}://${host}:${port}/${database}/_find`,
|
||||
{
|
||||
method: "post",
|
||||
headers: authHeader(),
|
||||
json: this.parseJSON(queryOptions.body),
|
||||
}
|
||||
);
|
||||
case 'find': {
|
||||
response = await got(`${protocol}://${host}:${port}/${database}/_find`, {
|
||||
method: 'post',
|
||||
headers: authHeader(),
|
||||
json: this.parseJSON(queryOptions.body),
|
||||
});
|
||||
result = this.parseJSON(response.body);
|
||||
break;
|
||||
}
|
||||
|
||||
case "get_view": {
|
||||
case 'get_view': {
|
||||
response = await got(`${view_url}`, {
|
||||
method: "get",
|
||||
method: 'get',
|
||||
headers: authHeader(),
|
||||
searchParams: {
|
||||
...(limit?.length > 0 && { limit }),
|
||||
|
|
@ -141,32 +107,30 @@ export default class Couchdb implements QueryService {
|
|||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw new QueryError("Query could not be completed", error.message, {});
|
||||
throw new QueryError('Query could not be completed', error.message, {});
|
||||
}
|
||||
|
||||
return {
|
||||
status: "ok",
|
||||
status: 'ok',
|
||||
data: result,
|
||||
};
|
||||
}
|
||||
|
||||
async testConnection(
|
||||
sourceOptions: SourceOptions
|
||||
): Promise<ConnectionTestResult> {
|
||||
const { username, password, port, host, database, protocol } =
|
||||
sourceOptions;
|
||||
async testConnection(sourceOptions: SourceOptions): Promise<ConnectionTestResult> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { username, password, port, host, database, protocol } = sourceOptions;
|
||||
const combined = `${username}:${password}`;
|
||||
const key = Buffer.from(combined).toString("base64");
|
||||
const key = Buffer.from(combined).toString('base64');
|
||||
const client = await got(`${protocol}://${host}:${port}/_all_dbs`, {
|
||||
method: "get",
|
||||
method: 'get',
|
||||
headers: { Authorization: `Basic ${key}` },
|
||||
});
|
||||
if (!client) {
|
||||
throw new Error("Error");
|
||||
throw new Error('Error');
|
||||
}
|
||||
|
||||
return {
|
||||
status: "ok",
|
||||
status: 'ok',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +1,21 @@
|
|||
export type SourceOptions = {
|
||||
username: string;
|
||||
password: string;
|
||||
database: string;
|
||||
database: string;
|
||||
port: string;
|
||||
host:string;
|
||||
protocol: string;
|
||||
host: string;
|
||||
protocol: string;
|
||||
};
|
||||
export type QueryOptions = {
|
||||
operation: string;
|
||||
record_id: string;
|
||||
body: string;
|
||||
rev_id:string;
|
||||
view_url:string;
|
||||
start_key?:string;
|
||||
end_key?:string;
|
||||
limit?:string;
|
||||
skip?:string;
|
||||
descending?:boolean;
|
||||
include_docs?:boolean;
|
||||
|
||||
rev_id: string;
|
||||
view_url: string;
|
||||
start_key?: string;
|
||||
end_key?: string;
|
||||
limit?: string;
|
||||
skip?: string;
|
||||
descending?: boolean;
|
||||
include_docs?: boolean;
|
||||
};
|
||||
|
|
|
|||
99
plugins/packages/couchdb/package-lock.json
generated
Normal file
99
plugins/packages/couchdb/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
{
|
||||
"name": "@tooljet-plugins/couchdb",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@tooljet-plugins/couchdb",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@tooljet-plugins/common": "file:../common",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
},
|
||||
"../common": {
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"react": "^17.0.2",
|
||||
"rimraf": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@tooljet-plugins/common": {
|
||||
"resolved": "../common",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@tooljet-plugins/common": {
|
||||
"version": "file:../common",
|
||||
"requires": {
|
||||
"react": "^17.0.2",
|
||||
"rimraf": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
},
|
||||
"react": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const dynamodb = require('../lib');
|
||||
// const dynamodb = require('../lib');
|
||||
|
||||
describe('dynamodb', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const elasticsearch = require('../lib');
|
||||
// const elasticsearch = require('../lib');
|
||||
|
||||
describe('elasticsearch', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const firestore = require('../lib');
|
||||
// const firestore = require('../lib');
|
||||
|
||||
describe('firestore', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const gcs = require('../lib');
|
||||
// const gcs = require('../lib');
|
||||
|
||||
describe('gcs', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,30 +1,74 @@
|
|||
'use strict';
|
||||
const { makeRequestBodyToBatchUpdate } =require('../lib/operations');
|
||||
const { makeRequestBodyToBatchUpdate } = require('../lib/operations');
|
||||
|
||||
describe('googlesheets', () => {
|
||||
it('should generate the request body for update operation' ,() => {
|
||||
const requestBody = {
|
||||
caseOne: { Gender: 'Female' },
|
||||
caseTwo: { extra: '0 points' },
|
||||
caseThree: { Gender: 'Female', extra: '0 points' }
|
||||
}
|
||||
const filterCondition = { key: 'Student Name', value: 'Anna' }
|
||||
const filterOperator = '==='
|
||||
const data = [
|
||||
[ 'ID', '1', '2' ],[ 'Student Name', 'John', 'Anna' ],[ 'Major', 'Science', 'English' ],[],[ 'Gender', 'Male', 'Female' ],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[ 'extra', 'extra-update', '0 points' ]
|
||||
]
|
||||
it('should generate the request body for update operation', () => {
|
||||
const requestBody = {
|
||||
caseOne: { Gender: 'Female' },
|
||||
caseTwo: { extra: '0 points' },
|
||||
caseThree: { Gender: 'Female', extra: '0 points' },
|
||||
};
|
||||
const filterCondition = { key: 'Student Name', value: 'Anna' };
|
||||
const filterOperator = '===';
|
||||
const data = [
|
||||
['ID', '1', '2'],
|
||||
['Student Name', 'John', 'Anna'],
|
||||
['Major', 'Science', 'English'],
|
||||
[],
|
||||
['Gender', 'Male', 'Female'],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
['extra', 'extra-update', '0 points'],
|
||||
];
|
||||
|
||||
const queryOptionsOne = { requestBody: requestBody.caseOne, filterCondition, filterOperator, data }
|
||||
const queryOptionsTwo = { requestBody: requestBody.caseTwo, filterCondition, filterOperator, data }
|
||||
const queryOptionsThree = { requestBody: requestBody.caseThree, filterCondition, filterOperator, data }
|
||||
const queryOptionsOne = { requestBody: requestBody.caseOne, filterCondition, filterOperator, data };
|
||||
const queryOptionsTwo = { requestBody: requestBody.caseTwo, filterCondition, filterOperator, data };
|
||||
const queryOptionsThree = { requestBody: requestBody.caseThree, filterCondition, filterOperator, data };
|
||||
|
||||
const expectedBodyForCaseOne = makeRequestBodyToBatchUpdate(queryOptionsOne.requestBody, queryOptionsOne.filterCondition, queryOptionsOne.filterOperator, queryOptionsOne.data)
|
||||
const expectedBodyForCaseTwo = makeRequestBodyToBatchUpdate(queryOptionsTwo.requestBody, queryOptionsOne.filterCondition, queryOptionsOne.filterOperator, queryOptionsOne.data)
|
||||
const expectedBodyForCaseThree = makeRequestBodyToBatchUpdate(queryOptionsThree.requestBody, queryOptionsOne.filterCondition, queryOptionsOne.filterOperator, queryOptionsOne.data)
|
||||
const expectedBodyForCaseOne = makeRequestBodyToBatchUpdate(
|
||||
queryOptionsOne.requestBody,
|
||||
queryOptionsOne.filterCondition,
|
||||
queryOptionsOne.filterOperator,
|
||||
queryOptionsOne.data
|
||||
);
|
||||
const expectedBodyForCaseTwo = makeRequestBodyToBatchUpdate(
|
||||
queryOptionsTwo.requestBody,
|
||||
queryOptionsOne.filterCondition,
|
||||
queryOptionsOne.filterOperator,
|
||||
queryOptionsOne.data
|
||||
);
|
||||
const expectedBodyForCaseThree = makeRequestBodyToBatchUpdate(
|
||||
queryOptionsThree.requestBody,
|
||||
queryOptionsOne.filterCondition,
|
||||
queryOptionsOne.filterOperator,
|
||||
queryOptionsOne.data
|
||||
);
|
||||
|
||||
|
||||
expect(expectedBodyForCaseOne).toEqual([{ cellValue: 'Female', cellIndex: 'E3' }]);
|
||||
expect(expectedBodyForCaseTwo).toEqual([{ cellValue: '0 points', cellIndex: 'AB3' }]);
|
||||
expect(expectedBodyForCaseThree).toEqual([{ cellValue: 'Female', cellIndex: 'E3' }, { cellValue: '0 points', cellIndex: 'AB3' }]);
|
||||
});
|
||||
expect(expectedBodyForCaseOne).toEqual([{ cellValue: 'Female', cellIndex: 'E3' }]);
|
||||
expect(expectedBodyForCaseTwo).toEqual([{ cellValue: '0 points', cellIndex: 'AB3' }]);
|
||||
expect(expectedBodyForCaseThree).toEqual([
|
||||
{ cellValue: 'Female', cellIndex: 'E3' },
|
||||
{ cellValue: '0 points', cellIndex: 'AB3' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,19 +3,19 @@
|
|||
const graphql = require('../lib');
|
||||
|
||||
describe('graphql', () => {
|
||||
it('should query graphql datasources', async () => {
|
||||
const sourceOptions = {
|
||||
url: 'https://api.spacex.land/graphql/',
|
||||
headers: [],
|
||||
url_params: [],
|
||||
};
|
||||
|
||||
const queryOptions = { query: '{ launchesPast(limit: 10) { mission_name } }' };
|
||||
it('should query graphql datasources', async () => {
|
||||
const sourceOptions = {
|
||||
url: 'https://api.spacex.land/graphql/',
|
||||
headers: [],
|
||||
url_params: [],
|
||||
};
|
||||
|
||||
const _graphql = new graphql.default()
|
||||
|
||||
const result = await _graphql.run(sourceOptions, queryOptions, 'no-datasource-id');
|
||||
|
||||
expect(result.data['data']['launchesPast'].length).toBe(10);
|
||||
});
|
||||
const queryOptions = { query: '{ launchesPast(limit: 10) { mission_name } }' };
|
||||
|
||||
const _graphql = new graphql.default();
|
||||
|
||||
const result = await _graphql.run(sourceOptions, queryOptions, 'no-datasource-id');
|
||||
|
||||
expect(result.data['data']['launchesPast'].length).toBe(10);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const mailgun = require('../lib');
|
||||
// const mailgun = require('../lib');
|
||||
|
||||
describe('mailgun', () => {
|
||||
it.todo('needs tests');
|
||||
});
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { QueryError, QueryResult, QueryService, ConnectionTestResult } from '@tooljet-plugins/common';
|
||||
import {SourceOptions, QueryOptions, EmailOptions} from "./types";
|
||||
import { QueryError, QueryResult, QueryService } from '@tooljet-plugins/common';
|
||||
import { SourceOptions, QueryOptions, EmailOptions } from './types';
|
||||
import MailgunSdk from 'mailgun.js';
|
||||
import FormData from 'form-data';
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ export default class Mailgun implements QueryService {
|
|||
}
|
||||
|
||||
const sdk = new MailgunSdk(FormData);
|
||||
const mailgunOptions = {username: 'api', key: sourceOptions.api_key, url: null}
|
||||
const mailgunOptions = { username: 'api', key: sourceOptions.api_key, url: null };
|
||||
if (sourceOptions.eu_hosted) {
|
||||
mailgunOptions.url = 'https://api.eu.mailgun.net';
|
||||
}
|
||||
|
|
@ -21,8 +21,8 @@ export default class Mailgun implements QueryService {
|
|||
to: queryOptions.send_mail_to,
|
||||
from: queryOptions.send_mail_from,
|
||||
subject: queryOptions.subject,
|
||||
text: queryOptions.text
|
||||
}
|
||||
text: queryOptions.text,
|
||||
};
|
||||
|
||||
if (queryOptions.html && queryOptions.html.length > 0) {
|
||||
emailOptions.html = queryOptions.html;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const minioapi = require('../lib');
|
||||
// const minioapi = require('../lib');
|
||||
|
||||
describe('minioapi', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"use strict";
|
||||
'use strict';
|
||||
|
||||
const mongodb = require("../lib");
|
||||
// const mongodb = require('../lib');
|
||||
|
||||
describe("mongodb", () => {
|
||||
it.todo("needs tests");
|
||||
describe('mongodb', () => {
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const mssql = require('../lib');
|
||||
// const mssql = require('../lib');
|
||||
|
||||
describe('mssql', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -60,9 +60,9 @@ export default class MssqlQueryService implements QueryService {
|
|||
database: sourceOptions.database,
|
||||
port: +sourceOptions.port,
|
||||
options: {
|
||||
encrypt: sourceOptions.azure ?? false
|
||||
}
|
||||
}
|
||||
encrypt: sourceOptions.azure ?? false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return knex(config);
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ describe('mysql', () => {
|
|||
],
|
||||
};
|
||||
|
||||
const _mysql = new mysql.default()
|
||||
|
||||
const _mysql = new mysql.default();
|
||||
|
||||
const builtQuery = await _mysql.buildBulkUpdateQuery(queryOptions);
|
||||
const expectedQuery =
|
||||
"UPDATE customers SET name = 'sam', email = 'sam@example.com' WHERE id = 1; UPDATE customers SET name = 'jon', email = 'jon@example.com' WHERE id = 2;";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const n8n = require('../lib');
|
||||
// const n8n = require('../lib');
|
||||
|
||||
describe('n8n', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
4
plugins/packages/oracledb/.gitignore
vendored
Normal file
4
plugins/packages/oracledb/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
node_modules
|
||||
lib/*.d.*
|
||||
lib/*.js
|
||||
lib/*.js.map
|
||||
4
plugins/packages/oracledb/README.md
Normal file
4
plugins/packages/oracledb/README.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
# Oracle DB
|
||||
|
||||
Documentation on: https://docs.tooljet.com/docs/data-sources/oracledb
|
||||
7
plugins/packages/oracledb/__tests_/index.js
Normal file
7
plugins/packages/oracledb/__tests_/index.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
// const oracledb = require('../lib');
|
||||
|
||||
describe('oracledb', () => {
|
||||
it.todo('needs tests');
|
||||
});
|
||||
1
plugins/packages/oracledb/lib/icon.svg
Normal file
1
plugins/packages/oracledb/lib/icon.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 231 30' preserveAspectRatio='xMinYMid'><path d='M99.61,19.52h15.24l-8.05-13L92,30H85.27l18-28.17a4.29,4.29,0,0,1,7-.05L128.32,30h-6.73l-3.17-5.25H103l-3.36-5.23m69.93,5.23V0.28h-5.72V27.16a2.76,2.76,0,0,0,.85,2,2.89,2.89,0,0,0,2.08.87h26l3.39-5.25H169.54M75,20.38A10,10,0,0,0,75,.28H50V30h5.71V5.54H74.65a4.81,4.81,0,0,1,0,9.62H58.54L75.6,30h8.29L72.43,20.38H75M14.88,30H32.15a14.86,14.86,0,0,0,0-29.71H14.88a14.86,14.86,0,1,0,0,29.71m16.88-5.23H15.26a9.62,9.62,0,0,1,0-19.23h16.5a9.62,9.62,0,1,1,0,19.23M140.25,30h17.63l3.34-5.23H140.64a9.62,9.62,0,1,1,0-19.23h16.75l3.38-5.25H140.25a14.86,14.86,0,1,0,0,29.71m69.87-5.23a9.62,9.62,0,0,1-9.26-7h24.42l3.36-5.24H200.86a9.61,9.61,0,0,1,9.26-7h16.76l3.35-5.25h-20.5a14.86,14.86,0,0,0,0,29.71h17.63l3.35-5.23h-20.6' transform='translate(-0.02 0)' style='fill:#C74634'/></svg>
|
||||
|
After Width: | Height: | Size: 874 B |
154
plugins/packages/oracledb/lib/index.ts
Normal file
154
plugins/packages/oracledb/lib/index.ts
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
import { Knex, knex } from 'knex';
|
||||
import oracledb from 'oracledb';
|
||||
import {
|
||||
cacheConnection,
|
||||
getCachedConnection,
|
||||
ConnectionTestResult,
|
||||
QueryService,
|
||||
QueryResult,
|
||||
} from '@tooljet-plugins/common';
|
||||
import { SourceOptions, QueryOptions } from './types';
|
||||
|
||||
export default class OracledbQueryService implements QueryService {
|
||||
private static _instance: OracledbQueryService;
|
||||
|
||||
constructor() {
|
||||
if (OracledbQueryService._instance) {
|
||||
return OracledbQueryService._instance;
|
||||
}
|
||||
|
||||
OracledbQueryService._instance = this;
|
||||
return OracledbQueryService._instance;
|
||||
}
|
||||
|
||||
async run(
|
||||
sourceOptions: SourceOptions,
|
||||
queryOptions: QueryOptions,
|
||||
dataSourceId: string,
|
||||
dataSourceUpdatedAt: string
|
||||
): Promise<QueryResult> {
|
||||
let result = {
|
||||
rows: [],
|
||||
};
|
||||
let query = '';
|
||||
|
||||
if (queryOptions.mode === 'gui') {
|
||||
if (queryOptions.operation === 'bulk_update_pkey') {
|
||||
query = await this.buildBulkUpdateQuery(queryOptions);
|
||||
}
|
||||
} else {
|
||||
query = queryOptions.query;
|
||||
}
|
||||
|
||||
const knexInstance = await this.getConnection(sourceOptions, {}, true, dataSourceId, dataSourceUpdatedAt);
|
||||
|
||||
// eslint-disable-next-line no-useless-catch
|
||||
try {
|
||||
result = await knexInstance.raw(query);
|
||||
|
||||
return {
|
||||
status: 'ok',
|
||||
data: result,
|
||||
};
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async testConnection(sourceOptions: SourceOptions): Promise<ConnectionTestResult> {
|
||||
const knexInstance = await this.getConnection(sourceOptions, {}, false);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const result = await knexInstance.raw('SELECT * FROM v$version');
|
||||
|
||||
return {
|
||||
status: 'ok',
|
||||
};
|
||||
}
|
||||
|
||||
initOracleClient(clientPathType: string, customPath: string) {
|
||||
try {
|
||||
if (clientPathType === 'custom') {
|
||||
if (process.platform === 'darwin') {
|
||||
oracledb.initOracleClient({ libDir: process.env.HOME + customPath });
|
||||
} else if (process.platform === 'win32') {
|
||||
oracledb.initOracleClient({
|
||||
libDir: customPath,
|
||||
}); // note the double backslashes
|
||||
}
|
||||
} else {
|
||||
oracledb.initOracleClient();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async buildConnection(sourceOptions: SourceOptions) {
|
||||
// we should add this to our datasource documentation
|
||||
try {
|
||||
oracledb.oracleClientVersion;
|
||||
} catch (err) {
|
||||
console.log('Oracle client is not initailized');
|
||||
this.initOracleClient(sourceOptions.client_path_type, sourceOptions.path);
|
||||
}
|
||||
|
||||
const config: Knex.Config = {
|
||||
client: 'oracledb',
|
||||
connection: {
|
||||
user: sourceOptions.username,
|
||||
password: sourceOptions.password,
|
||||
connectString: `(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=${sourceOptions.host})(PORT=${sourceOptions.port}))(CONNECT_DATA=(SERVER=DEDICATED)(${sourceOptions.database_type}=${sourceOptions.database})))`,
|
||||
multipleStatements: true,
|
||||
ssl: sourceOptions.ssl_enabled, // Disabling by default for backward compatibility
|
||||
},
|
||||
};
|
||||
|
||||
return knex(config);
|
||||
}
|
||||
|
||||
async getConnection(
|
||||
sourceOptions: SourceOptions,
|
||||
options: any,
|
||||
checkCache: boolean,
|
||||
dataSourceId?: string,
|
||||
dataSourceUpdatedAt?: string
|
||||
): Promise<any> {
|
||||
if (checkCache) {
|
||||
let connection = await getCachedConnection(dataSourceId, dataSourceUpdatedAt);
|
||||
|
||||
if (connection) {
|
||||
return connection;
|
||||
} else {
|
||||
connection = await this.buildConnection(sourceOptions);
|
||||
dataSourceId && cacheConnection(dataSourceId, connection);
|
||||
return connection;
|
||||
}
|
||||
} else {
|
||||
return await this.buildConnection(sourceOptions);
|
||||
}
|
||||
}
|
||||
|
||||
async buildBulkUpdateQuery(queryOptions: any): Promise<string> {
|
||||
let queryText = '';
|
||||
|
||||
const tableName = queryOptions['table'];
|
||||
const primaryKey = queryOptions['primary_key_column'];
|
||||
const records = queryOptions['records'];
|
||||
|
||||
for (const record of records) {
|
||||
queryText = `${queryText} UPDATE ${tableName} SET`;
|
||||
|
||||
for (const key of Object.keys(record)) {
|
||||
if (key !== primaryKey) {
|
||||
queryText = ` ${queryText} ${key} = '${record[key]}',`;
|
||||
}
|
||||
}
|
||||
|
||||
queryText = queryText.slice(0, -1);
|
||||
queryText = `begin ${queryText} WHERE ${primaryKey} = ${record[primaryKey]}; end;`;
|
||||
}
|
||||
|
||||
return queryText.trim();
|
||||
}
|
||||
}
|
||||
133
plugins/packages/oracledb/lib/manifest.json
Normal file
133
plugins/packages/oracledb/lib/manifest.json
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/ToolJet/ToolJet/develop/plugins/schemas/manifest.schema.json",
|
||||
"title": "Oracle DB datasource",
|
||||
"description": "A schema defining Oracle DB datasource",
|
||||
"type": "database",
|
||||
"source": {
|
||||
"name": "Oracle DB",
|
||||
"kind": "oracledb",
|
||||
"exposedVariables": {
|
||||
"isLoading": false,
|
||||
"data": {},
|
||||
"rawData": {}
|
||||
},
|
||||
"options": {
|
||||
"password": {
|
||||
"encrypted": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"host": {
|
||||
"value": "localhost"
|
||||
},
|
||||
"port": {
|
||||
"value": 1521
|
||||
},
|
||||
"database": {
|
||||
"value": ""
|
||||
},
|
||||
"database_type": {
|
||||
"value": "SID"
|
||||
},
|
||||
"username": {
|
||||
"value": ""
|
||||
},
|
||||
"password": {
|
||||
"value": ""
|
||||
},
|
||||
"ssl_enabled": {
|
||||
"value": true
|
||||
},
|
||||
"client_path_type":{
|
||||
"value": "default"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"client_path_type": {
|
||||
"label": "Client Library Location",
|
||||
"key": "client_path_type",
|
||||
"type": "dropdown-component-flip",
|
||||
"description": "Single select dropdown for client library",
|
||||
"list": [
|
||||
{
|
||||
"value": "default",
|
||||
"name": "Default"
|
||||
},
|
||||
{
|
||||
"value": "custom",
|
||||
"name": "Custom"
|
||||
}
|
||||
],
|
||||
"commonFields":{
|
||||
"host": {
|
||||
"label": "Host",
|
||||
"key": "host",
|
||||
"type": "text",
|
||||
"description": "Enter host"
|
||||
},
|
||||
"port": {
|
||||
"label": "Port",
|
||||
"key": "port",
|
||||
"type": "text",
|
||||
"description": "Enter port"
|
||||
},
|
||||
"database_type": {
|
||||
"label": "SID / Service Name",
|
||||
"key": "database_type",
|
||||
"type": "dropdown",
|
||||
"description": "Type of the database",
|
||||
"list": [
|
||||
{
|
||||
"name": "SID",
|
||||
"value": "SID"
|
||||
},
|
||||
{
|
||||
"name": "Service name",
|
||||
"value": "SERVICE_NAME"
|
||||
}
|
||||
]
|
||||
},
|
||||
"database": {
|
||||
"label": "Database Name",
|
||||
"key": "database",
|
||||
"type": "text",
|
||||
"description": "Name of the database"
|
||||
},
|
||||
"ssl_enabled": {
|
||||
"label": "SSL",
|
||||
"key": "ssl_enabled",
|
||||
"type": "toggle",
|
||||
"description": "Toggle for ssl_enabled"
|
||||
},
|
||||
"username": {
|
||||
"label": "Username",
|
||||
"key": "username",
|
||||
"type": "text",
|
||||
"description": "Enter username"
|
||||
},
|
||||
"password": {
|
||||
"label": "Password",
|
||||
"key": "password",
|
||||
"type": "password",
|
||||
"description": "Enter password"
|
||||
}
|
||||
}
|
||||
},
|
||||
"custom":{
|
||||
"path": {
|
||||
"label": "Path",
|
||||
"key": "path",
|
||||
"type": "text",
|
||||
"description": "Enter path"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"host",
|
||||
"port",
|
||||
"username",
|
||||
"password"
|
||||
]
|
||||
}
|
||||
81
plugins/packages/oracledb/lib/operations.json
Normal file
81
plugins/packages/oracledb/lib/operations.json
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/ToolJet/ToolJet/develop/plugins/schemas/operations.schema.json",
|
||||
"title": "Oracle DB datasource",
|
||||
"description": "A schema defining Oracle DB datasource",
|
||||
"type": "database",
|
||||
"defaults": {},
|
||||
"properties": {
|
||||
"mode": {
|
||||
"label": "",
|
||||
"key": "mode",
|
||||
"type": "dropdown-component-flip",
|
||||
"description": "Single select dropdown for mode",
|
||||
"list": [
|
||||
{
|
||||
"name": "SQL mode",
|
||||
"value": "sql"
|
||||
},
|
||||
{
|
||||
"name": "GUI mode",
|
||||
"value": "gui"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sql": {
|
||||
"query": {
|
||||
"key": "query",
|
||||
"type": "codehinter",
|
||||
"description": "Enter query",
|
||||
"placeholder": "SELECT * FROM customers",
|
||||
"height": "150px"
|
||||
}
|
||||
},
|
||||
"gui": {
|
||||
"operation": {
|
||||
"label": "Operation",
|
||||
"key": "operation",
|
||||
"type": "dropdown-component-flip",
|
||||
"description": "Single select dropdown for mode",
|
||||
"list": [
|
||||
{
|
||||
"name": "Bulk update using primary key",
|
||||
"value": "bulk_update_pkey"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bulk_update_pkey": {
|
||||
"table": {
|
||||
"label": "Table",
|
||||
"key": "table",
|
||||
"type": "codehinter",
|
||||
"lineNumbers": false,
|
||||
"description": "Enter table",
|
||||
"width": "320px",
|
||||
"height": "36px",
|
||||
"className": "codehinter-plugins",
|
||||
"placeholder": "Enter table"
|
||||
|
||||
},
|
||||
"primary_key_column": {
|
||||
"label": "Primary key column",
|
||||
"key": "primary_key_column",
|
||||
"type": "codehinter",
|
||||
"lineNumbers": false,
|
||||
"description": "Enter primary key column",
|
||||
"width": "320px",
|
||||
"height": "36px",
|
||||
"className": "codehinter-plugins",
|
||||
"placeholder": "Enter primary key column"
|
||||
},
|
||||
"records": {
|
||||
"label": "Records",
|
||||
"key": "records",
|
||||
"type": "codehinter",
|
||||
"description": "Enter records",
|
||||
"height": "150px"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
plugins/packages/oracledb/lib/types.ts
Normal file
16
plugins/packages/oracledb/lib/types.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
export type SourceOptions = {
|
||||
database: string;
|
||||
database_type: string;
|
||||
host: string;
|
||||
port: string;
|
||||
username: string;
|
||||
password: string;
|
||||
ssl_enabled: boolean;
|
||||
client_path_type: string;
|
||||
path: string;
|
||||
};
|
||||
export type QueryOptions = {
|
||||
operation: string;
|
||||
query: string;
|
||||
mode: string;
|
||||
};
|
||||
516
plugins/packages/oracledb/package-lock.json
generated
Normal file
516
plugins/packages/oracledb/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,516 @@
|
|||
{
|
||||
"name": "@tooljet-plugins/oracledb",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@tooljet-plugins/oracledb",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@tooljet-plugins/common": "file:../common",
|
||||
"knex": "^0.95.14",
|
||||
"oracledb": "^5.3.0",
|
||||
"react": "^17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/oracledb": "^5.2.2"
|
||||
}
|
||||
},
|
||||
"../common": {
|
||||
"name": "@tooljet-plugins/common",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"react": "^17.0.2",
|
||||
"rimraf": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@tooljet-plugins/common": {
|
||||
"resolved": "../common",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "17.0.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz",
|
||||
"integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/oracledb": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/oracledb/-/oracledb-5.2.2.tgz",
|
||||
"integrity": "sha512-aYb2DdZOQVIgSCSXjXNikQuyiHAY09SkRA4cjwoj+F/mhLJDahdjNeBmvQvfFojyChCKLuupSJHqoAXPExgV5w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"dotenv": "^8.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/colorette": {
|
||||
"version": "2.0.16",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz",
|
||||
"integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g=="
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
|
||||
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "8.6.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz",
|
||||
"integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/esm": {
|
||||
"version": "3.2.25",
|
||||
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
|
||||
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"node_modules/getopts": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz",
|
||||
"integrity": "sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA=="
|
||||
},
|
||||
"node_modules/has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/interpret": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
|
||||
"integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz",
|
||||
"integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==",
|
||||
"dependencies": {
|
||||
"has": "^1.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"node_modules/knex": {
|
||||
"version": "0.95.15",
|
||||
"resolved": "https://registry.npmjs.org/knex/-/knex-0.95.15.tgz",
|
||||
"integrity": "sha512-Loq6WgHaWlmL2bfZGWPsy4l8xw4pOE+tmLGkPG0auBppxpI0UcK+GYCycJcqz9W54f2LiGewkCVLBm3Wq4ur/w==",
|
||||
"dependencies": {
|
||||
"colorette": "2.0.16",
|
||||
"commander": "^7.1.0",
|
||||
"debug": "4.3.2",
|
||||
"escalade": "^3.1.1",
|
||||
"esm": "^3.2.25",
|
||||
"getopts": "2.2.5",
|
||||
"interpret": "^2.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"pg-connection-string": "2.5.0",
|
||||
"rechoir": "0.7.0",
|
||||
"resolve-from": "^5.0.0",
|
||||
"tarn": "^3.0.1",
|
||||
"tildify": "2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"knex": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"mysql": {
|
||||
"optional": true
|
||||
},
|
||||
"mysql2": {
|
||||
"optional": true
|
||||
},
|
||||
"pg": {
|
||||
"optional": true
|
||||
},
|
||||
"pg-native": {
|
||||
"optional": true
|
||||
},
|
||||
"sqlite3": {
|
||||
"optional": true
|
||||
},
|
||||
"tedious": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/oracledb": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/oracledb/-/oracledb-5.3.0.tgz",
|
||||
"integrity": "sha512-HMJzQ6lCf287ztvvehTEmjCWA21FQ3RMvM+mgoqd4i8pkREuqFWO+y3ovsGR9moJUg4T0xjcwS8rl4mggWPxmg==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=10.16"
|
||||
}
|
||||
},
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
||||
},
|
||||
"node_modules/pg-connection-string": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
|
||||
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ=="
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rechoir": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz",
|
||||
"integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==",
|
||||
"dependencies": {
|
||||
"resolve": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
|
||||
"integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.8.1",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"resolve": "bin/resolve"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-from": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
|
||||
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/tarn": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz",
|
||||
"integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tildify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz",
|
||||
"integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@tooljet-plugins/common": {
|
||||
"version": "file:../common",
|
||||
"requires": {
|
||||
"react": "^17.0.2",
|
||||
"rimraf": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "17.0.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz",
|
||||
"integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/oracledb": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/oracledb/-/oracledb-5.2.2.tgz",
|
||||
"integrity": "sha512-aYb2DdZOQVIgSCSXjXNikQuyiHAY09SkRA4cjwoj+F/mhLJDahdjNeBmvQvfFojyChCKLuupSJHqoAXPExgV5w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"dotenv": "^8.2.0"
|
||||
}
|
||||
},
|
||||
"colorette": {
|
||||
"version": "2.0.16",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz",
|
||||
"integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g=="
|
||||
},
|
||||
"commander": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
|
||||
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"dotenv": {
|
||||
"version": "8.6.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz",
|
||||
"integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==",
|
||||
"dev": true
|
||||
},
|
||||
"escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
|
||||
},
|
||||
"esm": {
|
||||
"version": "3.2.25",
|
||||
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
|
||||
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA=="
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"getopts": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz",
|
||||
"integrity": "sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA=="
|
||||
},
|
||||
"has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"interpret": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
|
||||
"integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw=="
|
||||
},
|
||||
"is-core-module": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz",
|
||||
"integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==",
|
||||
"requires": {
|
||||
"has": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"knex": {
|
||||
"version": "0.95.15",
|
||||
"resolved": "https://registry.npmjs.org/knex/-/knex-0.95.15.tgz",
|
||||
"integrity": "sha512-Loq6WgHaWlmL2bfZGWPsy4l8xw4pOE+tmLGkPG0auBppxpI0UcK+GYCycJcqz9W54f2LiGewkCVLBm3Wq4ur/w==",
|
||||
"requires": {
|
||||
"colorette": "2.0.16",
|
||||
"commander": "^7.1.0",
|
||||
"debug": "4.3.2",
|
||||
"escalade": "^3.1.1",
|
||||
"esm": "^3.2.25",
|
||||
"getopts": "2.2.5",
|
||||
"interpret": "^2.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"pg-connection-string": "2.5.0",
|
||||
"rechoir": "0.7.0",
|
||||
"resolve-from": "^5.0.0",
|
||||
"tarn": "^3.0.1",
|
||||
"tildify": "2.0.0"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
},
|
||||
"oracledb": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/oracledb/-/oracledb-5.3.0.tgz",
|
||||
"integrity": "sha512-HMJzQ6lCf287ztvvehTEmjCWA21FQ3RMvM+mgoqd4i8pkREuqFWO+y3ovsGR9moJUg4T0xjcwS8rl4mggWPxmg=="
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
||||
},
|
||||
"pg-connection-string": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
|
||||
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ=="
|
||||
},
|
||||
"react": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"rechoir": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz",
|
||||
"integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==",
|
||||
"requires": {
|
||||
"resolve": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.22.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
|
||||
"integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
|
||||
"requires": {
|
||||
"is-core-module": "^2.8.1",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"resolve-from": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
|
||||
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="
|
||||
},
|
||||
"supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
|
||||
},
|
||||
"tarn": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz",
|
||||
"integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ=="
|
||||
},
|
||||
"tildify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz",
|
||||
"integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw=="
|
||||
}
|
||||
}
|
||||
}
|
||||
28
plugins/packages/oracledb/package.json
Normal file
28
plugins/packages/oracledb/package.json
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "@tooljet-plugins/oracledb",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"directories": {
|
||||
"lib": "lib",
|
||||
"test": "__tests__"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "echo \"Error: run tests from root\" && exit 1",
|
||||
"build": "tsc -b",
|
||||
"clean": "rimraf ./dist && rimraf tsconfig.tsbuildinfo"
|
||||
},
|
||||
"homepage": "https://github.com/tooljet/tooljet#readme",
|
||||
"dependencies": {
|
||||
"@tooljet-plugins/common": "file:../common",
|
||||
"knex": "^0.95.14",
|
||||
"oracledb": "^5.3.0",
|
||||
"react": "^17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/oracledb": "^5.2.2"
|
||||
}
|
||||
}
|
||||
11
plugins/packages/oracledb/tsconfig.json
Normal file
11
plugins/packages/oracledb/tsconfig.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "lib"
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
|
|
@ -3,30 +3,30 @@
|
|||
const postgresql = require('../lib');
|
||||
|
||||
describe('postgresql', () => {
|
||||
it('should generate the query for bulk update operation', async () => {
|
||||
const queryOptions = {
|
||||
table: 'customers',
|
||||
primary_key_column: 'id',
|
||||
records: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'sam',
|
||||
email: 'sam@example.com',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'jon',
|
||||
email: 'jon@example.com',
|
||||
},
|
||||
],
|
||||
};
|
||||
it('should generate the query for bulk update operation', async () => {
|
||||
const queryOptions = {
|
||||
table: 'customers',
|
||||
primary_key_column: 'id',
|
||||
records: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'sam',
|
||||
email: 'sam@example.com',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'jon',
|
||||
email: 'jon@example.com',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const _postgresql = new postgresql.default()
|
||||
|
||||
const builtQuery = await _postgresql.buildBulkUpdateQuery(queryOptions);
|
||||
const expectedQuery =
|
||||
"UPDATE customers SET name = 'sam', email = 'sam@example.com' WHERE id = 1; UPDATE customers SET name = 'jon', email = 'jon@example.com' WHERE id = 2;";
|
||||
|
||||
expect(builtQuery).toBe(expectedQuery);
|
||||
});
|
||||
const _postgresql = new postgresql.default();
|
||||
|
||||
const builtQuery = await _postgresql.buildBulkUpdateQuery(queryOptions);
|
||||
const expectedQuery =
|
||||
"UPDATE customers SET name = 'sam', email = 'sam@example.com' WHERE id = 1; UPDATE customers SET name = 'jon', email = 'jon@example.com' WHERE id = 2;";
|
||||
|
||||
expect(builtQuery).toBe(expectedQuery);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const redis = require('../lib');
|
||||
// const redis = require('../lib');
|
||||
|
||||
describe('redis', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const restapi = require('../lib');
|
||||
// const restapi = require('../lib');
|
||||
|
||||
describe('restapi', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const s3 = require('../lib');
|
||||
// const s3 = require('../lib');
|
||||
|
||||
describe('s3', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const sendgrid = require('../lib');
|
||||
// const sendgrid = require('../lib');
|
||||
|
||||
describe('sendgrid', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const slack = require('../lib');
|
||||
// const slack = require('../lib');
|
||||
|
||||
describe('slack', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
const smtp = require('../lib');
|
||||
// const smtp = require('../lib');
|
||||
|
||||
describe('smtp', () => {
|
||||
it.todo('needs tests');
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
const snowflake = require('../lib');
|
||||
// const snowflake = require('../lib');
|
||||
|
||||
describe('snowflake', () => {
|
||||
it.todo('needs tests');
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const stripe = require('../lib');
|
||||
// const stripe = require('../lib');
|
||||
|
||||
describe('stripe', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const twilioapi = require('../lib');
|
||||
// const twilioapi = require('../lib');
|
||||
|
||||
describe('twilioapi', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const typesenseapi = require('../lib');
|
||||
// const typesenseapi = require('../lib');
|
||||
|
||||
describe('typesenseapi', () => {
|
||||
it.todo('needs tests');
|
||||
it.todo('needs tests');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
1.5.1
|
||||
1.6.0
|
||||
|
|
|
|||
2
server/package-lock.json
generated
2
server/package-lock.json
generated
|
|
@ -105,6 +105,7 @@
|
|||
"@tooljet-plugins/mssql": "file:packages/mssql",
|
||||
"@tooljet-plugins/mysql": "file:packages/mysql",
|
||||
"@tooljet-plugins/n8n": "file:packages/n8n",
|
||||
"@tooljet-plugins/oracledb": "file:packages/oracledb",
|
||||
"@tooljet-plugins/postgresql": "file:packages/postgresql",
|
||||
"@tooljet-plugins/redis": "file:packages/redis",
|
||||
"@tooljet-plugins/restapi": "file:packages/restapi",
|
||||
|
|
@ -14313,6 +14314,7 @@
|
|||
"@tooljet-plugins/mssql": "file:packages/mssql",
|
||||
"@tooljet-plugins/mysql": "file:packages/mysql",
|
||||
"@tooljet-plugins/n8n": "file:packages/n8n",
|
||||
"@tooljet-plugins/oracledb": "file:packages/oracledb",
|
||||
"@tooljet-plugins/postgresql": "file:packages/postgresql",
|
||||
"@tooljet-plugins/redis": "file:packages/redis",
|
||||
"@tooljet-plugins/restapi": "file:packages/restapi",
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ export class AppsService {
|
|||
}
|
||||
|
||||
async createVersion(user: User, app: App, versionName: string, versionFromId: string): Promise<AppVersion> {
|
||||
const lastVersion = await this.appVersionsRepository.findOne({
|
||||
const versionFrom = await this.appVersionsRepository.findOne({
|
||||
where: { id: versionFromId },
|
||||
});
|
||||
|
||||
|
|
@ -299,12 +299,12 @@ export class AppsService {
|
|||
manager.create(AppVersion, {
|
||||
name: versionName,
|
||||
app,
|
||||
definition: lastVersion?.definition,
|
||||
definition: versionFrom?.definition,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
);
|
||||
await this.setupDataSourcesAndQueriesForVersion(manager, appVersion, lastVersion);
|
||||
await this.setupDataSourcesAndQueriesForVersion(manager, appVersion, versionFrom);
|
||||
});
|
||||
|
||||
return appVersion;
|
||||
|
|
@ -320,24 +320,34 @@ export class AppsService {
|
|||
await getManager().transaction(async (manager) => {
|
||||
await manager.delete(DataSource, { appVersionId: version.id });
|
||||
await manager.delete(DataQuery, { appVersionId: version.id });
|
||||
result = await manager.delete(AppVersion, { id: version.id, appId: app.id });
|
||||
result = await manager.delete(AppVersion, {
|
||||
id: version.id,
|
||||
appId: app.id,
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async setupDataSourcesAndQueriesForVersion(manager: EntityManager, appVersion: AppVersion, lastVersion: AppVersion) {
|
||||
if (lastVersion) {
|
||||
await this.createNewDataSourcesAndQueriesForVersion(manager, appVersion, lastVersion);
|
||||
async setupDataSourcesAndQueriesForVersion(manager: EntityManager, appVersion: AppVersion, versionFrom: AppVersion) {
|
||||
if (versionFrom) {
|
||||
await this.createNewDataSourcesAndQueriesForVersion(manager, appVersion, versionFrom);
|
||||
} else {
|
||||
// TODO: Remove this when default version will be create when app creation is done
|
||||
const totalVersions = await manager.count(AppVersion, {
|
||||
where: { appId: appVersion.appId },
|
||||
});
|
||||
|
||||
if (totalVersions > 1) {
|
||||
throw new BadRequestException('More than one version found. Version to create from not specified.');
|
||||
}
|
||||
await this.associateExistingDataSourceAndQueriesToVersion(manager, appVersion);
|
||||
}
|
||||
}
|
||||
|
||||
async associateExistingDataSourceAndQueriesToVersion(manager: EntityManager, appVersion: AppVersion) {
|
||||
const dataSources = await manager.find(DataSource, {
|
||||
where: { appId: appVersion.appId },
|
||||
where: { appId: appVersion.appId, appVersionId: null },
|
||||
});
|
||||
for await (const dataSource of dataSources) {
|
||||
await manager.update(DataSource, dataSource.id, {
|
||||
|
|
@ -346,7 +356,7 @@ export class AppsService {
|
|||
}
|
||||
|
||||
const dataQueries = await manager.find(DataQuery, {
|
||||
where: { appId: appVersion.appId },
|
||||
where: { appId: appVersion.appId, appVersionId: null },
|
||||
});
|
||||
for await (const dataQuery of dataQueries) {
|
||||
await manager.update(DataQuery, dataQuery.id, {
|
||||
|
|
@ -358,13 +368,13 @@ export class AppsService {
|
|||
async createNewDataSourcesAndQueriesForVersion(
|
||||
manager: EntityManager,
|
||||
appVersion: AppVersion,
|
||||
lastVersion: AppVersion
|
||||
versionFrom: AppVersion
|
||||
) {
|
||||
const oldDataSourceToNewMapping = {};
|
||||
const oldDataQueryToNewMapping = {};
|
||||
|
||||
const dataSources = await manager.find(DataSource, {
|
||||
where: { appVersionId: lastVersion.id },
|
||||
where: { appVersionId: versionFrom.id },
|
||||
});
|
||||
|
||||
for await (const dataSource of dataSources) {
|
||||
|
|
@ -384,7 +394,7 @@ export class AppsService {
|
|||
}
|
||||
|
||||
const dataQueries = await manager.find(DataQuery, {
|
||||
where: { appVersionId: lastVersion.id },
|
||||
where: { appVersionId: versionFrom.id },
|
||||
});
|
||||
const newDataQueries = [];
|
||||
for await (const dataQuery of dataQueries) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { DataQuery } from '../../src/entities/data_query.entity';
|
|||
import { CredentialsService } from './credentials.service';
|
||||
import { DataSource } from 'src/entities/data_source.entity';
|
||||
import { DataSourcesService } from './data_sources.service';
|
||||
const got = require('got');
|
||||
import got from 'got';
|
||||
|
||||
@Injectable()
|
||||
export class DataQueriesService {
|
||||
|
|
@ -115,24 +115,37 @@ export class DataQueriesService {
|
|||
return result;
|
||||
}
|
||||
|
||||
checkIfContentTypeIsURLenc(headers: []) {
|
||||
const objectHeaders = Object.fromEntries(headers);
|
||||
const contentType = objectHeaders['content-type'] ?? objectHeaders['Content-Type'];
|
||||
return contentType === 'application/x-www-form-urlencoded';
|
||||
}
|
||||
|
||||
/* This function fetches the access token from the token url set in REST API (oauth) datasource */
|
||||
async fetchOAuthToken(sourceOptions: any, code: string): Promise<any> {
|
||||
const tooljetHost = process.env.TOOLJET_HOST;
|
||||
const isUrlEncoded = this.checkIfContentTypeIsURLenc(sourceOptions['headers']);
|
||||
const accessTokenUrl = sourceOptions['access_token_url'];
|
||||
|
||||
const customParams = Object.fromEntries(sourceOptions['custom_auth_params']);
|
||||
Object.keys(customParams).forEach((key) => (customParams[key] === '' ? delete customParams[key] : {}));
|
||||
|
||||
const bodyData = {
|
||||
code,
|
||||
client_id: sourceOptions['client_id'],
|
||||
client_secret: sourceOptions['client_secret'],
|
||||
grant_type: sourceOptions['grant_type'],
|
||||
redirect_uri: `${tooljetHost}/oauth2/authorize`,
|
||||
...customParams,
|
||||
};
|
||||
|
||||
const response = await got(accessTokenUrl, {
|
||||
method: 'post',
|
||||
json: {
|
||||
code,
|
||||
client_id: sourceOptions['client_id'],
|
||||
client_secret: sourceOptions['client_secret'],
|
||||
grant_type: sourceOptions['grant_type'],
|
||||
redirect_uri: `${tooljetHost}/oauth2/authorize`,
|
||||
...customParams,
|
||||
headers: isUrlEncoded && {
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
form: isUrlEncoded ? bodyData : undefined,
|
||||
json: !isUrlEncoded ? bodyData : undefined,
|
||||
});
|
||||
|
||||
const result = JSON.parse(response.body);
|
||||
|
|
|
|||
|
|
@ -121,7 +121,10 @@ describe('apps controller', () => {
|
|||
});
|
||||
const organization = adminUserData.organization;
|
||||
const allUserGroup = await getManager().findOne(GroupPermission, {
|
||||
where: { group: 'all_users', organization: adminUserData.organization },
|
||||
where: {
|
||||
group: 'all_users',
|
||||
organization: adminUserData.organization,
|
||||
},
|
||||
});
|
||||
const developerUserData = await createUser(app, {
|
||||
email: 'developer@tooljet.io',
|
||||
|
|
@ -765,7 +768,7 @@ describe('apps controller', () => {
|
|||
const application = await createApplication(app, {
|
||||
user: adminUserData.user,
|
||||
});
|
||||
|
||||
const version = await createApplicationVersion(app, application);
|
||||
// setup app permissions for developer
|
||||
const developerUserGroup = await getRepository(GroupPermission).findOne({
|
||||
where: {
|
||||
|
|
@ -784,6 +787,7 @@ describe('apps controller', () => {
|
|||
.set('Authorization', authHeaderForUser(userData.user))
|
||||
.send({
|
||||
versionName: 'v1',
|
||||
versionFromId: version.id,
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(201);
|
||||
|
|
@ -812,7 +816,9 @@ describe('apps controller', () => {
|
|||
|
||||
expect(response.statusCode).toBe(201);
|
||||
|
||||
const v2 = await getManager().findOne(AppVersion, { where: { name: 'v2' } });
|
||||
const v2 = await getManager().findOne(AppVersion, {
|
||||
where: { name: 'v2' },
|
||||
});
|
||||
expect(v2.definition).toEqual(v1.definition);
|
||||
});
|
||||
|
||||
|
|
@ -947,6 +953,31 @@ describe('apps controller', () => {
|
|||
expect(dataQueries).toHaveLength(3);
|
||||
expect(dataSources.map((s) => s.appVersionId).includes(response.body.id)).toBeTruthy();
|
||||
expect(dataQueries.map((q) => q.appVersionId).includes(response.body.id)).toBeTruthy();
|
||||
|
||||
// creating a new version from a non existing version id will throw error when more than 1 versions exist
|
||||
await createDataSource(app, {
|
||||
name: 'name',
|
||||
kind: 'postgres',
|
||||
application: application,
|
||||
user: adminUserData.user,
|
||||
});
|
||||
await createDataQuery(app, {
|
||||
application,
|
||||
dataSource,
|
||||
kind: 'restapi',
|
||||
options: { method: 'get' },
|
||||
});
|
||||
|
||||
response = await request(app.getHttpServer())
|
||||
.post(`/api/apps/${application.id}/versions`)
|
||||
.set('Authorization', authHeaderForUser(adminUserData.user))
|
||||
.send({
|
||||
versionName: 'v3',
|
||||
versionFromId: 'a77b051a-dd48-4633-a01f-089a845d5f88',
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(400);
|
||||
expect(response.body.message).toBe('More than one version found. Version to create from not specified.');
|
||||
});
|
||||
|
||||
it('creates new credentials and copies cipher text on data source', async () => {
|
||||
|
|
@ -954,33 +985,54 @@ describe('apps controller', () => {
|
|||
email: 'admin@tooljet.io',
|
||||
});
|
||||
const application = await importAppFromTemplates(app, adminUserData.user, 'customer-dashboard');
|
||||
const dataSource = await getManager().findOne(DataSource, { where: { appId: application } });
|
||||
const dataSource = await getManager().findOne(DataSource, {
|
||||
where: { appId: application },
|
||||
});
|
||||
|
||||
let dataSources = await getManager().find(DataSource);
|
||||
let dataQueries = await getManager().find(DataQuery);
|
||||
const credential = await getManager().findOne(Credential, {
|
||||
where: { id: dataSource.options['password']['credential_id'] },
|
||||
});
|
||||
credential.valueCiphertext = 'strongPassword';
|
||||
await getManager().save(credential);
|
||||
|
||||
const response = await request(app.getHttpServer())
|
||||
let response = await request(app.getHttpServer())
|
||||
.post(`/api/apps/${application.id}/versions`)
|
||||
.set('Authorization', authHeaderForUser(adminUserData.user))
|
||||
.send({
|
||||
versionName: 'v1',
|
||||
});
|
||||
|
||||
await request(app.getHttpServer())
|
||||
expect(response.statusCode).toBe(400);
|
||||
expect(response.body.message).toBe('More than one version found. Version to create from not specified.');
|
||||
|
||||
const initialVersion = await getManager().findOne(AppVersion, {
|
||||
where: { appId: application.id, name: 'v0' },
|
||||
});
|
||||
|
||||
response = await request(app.getHttpServer())
|
||||
.post(`/api/apps/${application.id}/versions`)
|
||||
.set('Authorization', authHeaderForUser(adminUserData.user))
|
||||
.send({
|
||||
versionName: 'v1',
|
||||
versionFromId: initialVersion.id,
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(201);
|
||||
|
||||
response = await request(app.getHttpServer())
|
||||
.post(`/api/apps/${application.id}/versions`)
|
||||
.set('Authorization', authHeaderForUser(adminUserData.user))
|
||||
.send({
|
||||
versionName: 'v2',
|
||||
versionFromId: response.body.id,
|
||||
});
|
||||
dataSources = await getManager().find(DataSource);
|
||||
dataQueries = await getManager().find(DataQuery);
|
||||
|
||||
const dataSources = await getManager().find(DataSource);
|
||||
const dataQueries = await getManager().find(DataQuery);
|
||||
|
||||
expect(dataSources).toHaveLength(2);
|
||||
expect(dataQueries).toHaveLength(4);
|
||||
expect(dataSources).toHaveLength(3);
|
||||
expect(dataQueries).toHaveLength(6);
|
||||
|
||||
const credentials = await getManager().find(Credential);
|
||||
expect([...new Set(credentials.map((c) => c.valueCiphertext))]).toEqual(['strongPassword']);
|
||||
|
|
|
|||
Loading…
Reference in a new issue