mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
* global store init * Moved query data to new component * Removed unwanted code * Removed data queries prop drilling * Moved query state out of editor * Added unsafe to componentWillReceiveProps * Selected first query when the version is changed * Fixed bug on renaming query * Fixed issue on dark theme * Fixed running query on page load in viewer * Query manager refactor init * Added global data source in store * Disabled devtools on production * Fixed bug on selecting query after deletion * Reset store when editor is loaded * Moved query manager to functional component * Fixed conflict issues * Fixed infinite loop on tooljetDB * Set the store name and updated devtools logic * Fixed issue on displaying draft query from data sources * Updated comments on the store * Fixed bug on changing data source and creating query from data source * Fixed bug on showing unsaved changes popup * Fixed issue on showing confirmation modal everytime without any changes * feat: autosave data query functionality * feat: show publish button only when the status in draft state * Fixed issues on query renaming * feat: removed discard popup for data query create/edit widget * stye: reduced autosave api call timeout and added draft tag * feat: added minor style changes * feat: fixed issues with restapi plugin, removed unused api calls * fix: fixed issue that breaks restapi creation * fix: reload selected query details after update query * perf: reduced debounce time for data query update apis * feat: removed full reloading of query list on query renaming * feat: duplicate data query feature added * Fixed issue on creating restAPI query * fix: fixed issue in transforming response from update queyr api * fix: refresh selected query details when the selected query is updated * fix: rename query on click enter * fix: full refresh of query list on update * fix: style changes * fix: subscribing to state to autsave * feat: updated the query manager styles to new design * feat: revamped the querypane header buttons * fix: fixed the padding for query panel maximize button * feat: updated search box style * refactor: moved function to render data source icon to its own component * fix: fixed querymanager widget breaking issue * merged with feat/query-manager-autosave * refactor: removed unused consoles * refactor: removed unused consoles * refactor: removed unused consoles * fix: removed commented code * fix: removed unused code * refactor: removed unused comments * fix: show change datasource select only if valid ds available * Update frontend/src/Editor/Inspector/EventManager.jsx Co-authored-by: Kavin Venkatachalam <50441969+kavinvenkatachalam@users.noreply.github.com> * Update frontend/src/Editor/QueryManager/Components/DataSourceLister.jsx Co-authored-by: Kavin Venkatachalam <50441969+kavinvenkatachalam@users.noreply.github.com> * Update frontend/src/Editor/QueryManager/Components/DataSourceLister.jsx Co-authored-by: Kavin Venkatachalam <50441969+kavinvenkatachalam@users.noreply.github.com> * Update frontend/src/Editor/QueryManager/Components/QueryManagerBody.jsx Co-authored-by: Kavin Venkatachalam <50441969+kavinvenkatachalam@users.noreply.github.com> * feat: modify behaviour of search icon in query panel * fix: fixed theme color mismatch in query manager * refactor: remove dead code * refactor: updated theme for data source listner * fix: theming in filter and sort popup * refactor: remove unused variables * fix: removed draftQuery logic from query manager * refactor: removed unused varibales * Update frontend/src/Editor/QueryManager/QueryEditors/Restapi/TabParams.jsx Co-authored-by: Kavin Venkatachalam <50441969+kavinvenkatachalam@users.noreply.github.com> * Update frontend/src/Editor/QueryPanel/QueryCard.jsx Co-authored-by: Kavin Venkatachalam <50441969+kavinvenkatachalam@users.noreply.github.com> * feat: diable preview for draft queries * fix: added tooltip for query panel button * fix: fixed issues in saving query manager events * fix: moved query save subscriber to QuerPanel component * feat: converted query run api to save and run * fix: made varibale an optional param in updateDataQuery dto * refactor: cleanup update dataquery status api response * refactor: moved query status to constants file * feat: prompt for queryname when creating new query * fix: store new queryname in state on create query pageload * fix: fixed alignment of Tooljet db component form * fix: correct translation and format file * refactor: removed consoles * merge: merge appbuilder-1.2 * style: updated rename input/button UX * style: revamped dataquery create widget styles * style: revamped data source selector styles * fix: removed code added for debugging * style: updated data query filter design * style: Add prop to control visibility of clear button in search box * style: implement new style for query filter * merge appbuilder-1.2 to feat/query-manager-sort-filter * refactor: remove unintended file change * fix: set default value for method in respapi * style: updated copilot info popup style * style: updated quer panel header icons * style: updated button styles * style: fixed query manager button styles * style: smoothened query preview modal view * fix: correct import for some funs * fix: fixed minor UX bugs * style: fixed styling of REST api GDS * style: fixed styleing of sort and filter popup * style: improved data queries sort filter UI/UX * fix: remove click listner when overlay is closed * fix: moved component declaration out of parent component * fix: set selected datasource for default sources * fix: filter DS based on saerch in create dropdown * fix: restrict draft query running to preview mode * fix: query renamed on input change in create screen * fix: set name to state as soon as user renames query * fix: make query notification message consistent * style: correct s3 bucket plugin layout config * fix: fixed issues with cloning of Static DS queries * fix: made change so that newly created query is reflected immediatly * style: updated spacing for query manager components * fix: hide rename input when no query selected * fix: check bothe selected query and DS before rendering query manager * fix: set isSaving to true only for api calls in querymanager * fix: added success message form in qm * fix: filter out draft queries from viewer on running * fix: fixed inconsistent gutter for runpy and runjs editors * fix: reload dataqueris on LDS deletion * fix: redesigned filter/sort popup * fix: fixed issue that resets filter on search * fix: fixed query manager breaking on plugin select * fix: diable json preview for text output * fix: reset to filter and sort main menu on close filter popup * refactor: rename varibales * stye: redesigned query create panel * feat: revert data query status column from backend * style: redesign query picker section * refactor: removed dead code * style: querypanel expand/collapse btn style * style: add query select and query filter popup style redesign * style: updated filter popup style * feat: removed draft query checks everywhere * style: empty dataqueries style changed * style: updated query selector popup and rest options styles * style: removed 100% height to query option remove btn * feat: added the query runnable status check * style: updated query manager footer style * feat: changed DS filter from kind to DS ID * style: minor ui tweaks in filter popup * style: disable DS filter if no DQs created * style: minor ui change * fix: rerender filter popup post DS api call. fixed rest api copy feature * fix: add local DS to filter popup * refactor: removed dead code/comments * add new row is crashing when no data is fed to table (#7102) * fix: fixed condition that blocked GDS run on load * fix: revert name back to og name if update fails in rename query * feat: added tooltip for show query btn * fix: added click interaction for pill btn as well * fix: minor UI tweaks to make UX better * style: fixed the styling of filter popup * style: minor UI tweaks in query filter popup * fix: fixed minor css issue in ds picker * style: wrap overflowing text in queryname * fix: update updated_at after query update api call success * fix: update remove the caller query from event query dropdown * style: minor ui spacing tweaks * fix: fix issue that cuased app crash when tjdb opened * fix: fixed update row styles * fix: fixed info popup dark theme bg * fix: fixed headers styling according to general QM styles * style: fixed stripe QM UI * fix: added tooltip for quernames * feat: add tooltip for select ds options * added consoles to debug debugger issue * fix: fixed :active style of ds select dropdown in QM * fix: fixed DS kind name in data source selector in QM * fix: fixed border color mismatch for ds select dd * fix: change tooltip msg for maximize/minize QM * Fix automation for query manager revamp. (#7223) * Add data-cy to support modified specs * Fix event handler * Fix RunPy and RunJS specs * Fix event handler label * Fix basic components spec * Fix basic components failure * Fix tabel spec failure. * Fix runjs and runpy actions * Fix table column options * Add data-cy * version: version updated to 2.13.0 * Version bump --------- Co-authored-by: Kavin Venkatachalam <kavin.saratha@gmail.com> Co-authored-by: Kavin Venkatachalam <50441969+kavinvenkatachalam@users.noreply.github.com> Co-authored-by: Manish Kushare <37823141+manishkushare@users.noreply.github.com> Co-authored-by: Midhun Kumar E <midhun752@gmail.com>
293 lines
9.4 KiB
TypeScript
293 lines
9.4 KiB
TypeScript
import {
|
|
Controller,
|
|
Get,
|
|
Param,
|
|
Body,
|
|
Post,
|
|
Patch,
|
|
Delete,
|
|
Query,
|
|
UseGuards,
|
|
ForbiddenException,
|
|
BadRequestException,
|
|
Put,
|
|
} from '@nestjs/common';
|
|
import { JwtAuthGuard } from '../../src/modules/auth/jwt-auth.guard';
|
|
import { decamelizeKeys } from 'humps';
|
|
import { DataQueriesService } from '../../src/services/data_queries.service';
|
|
import { DataSourcesService } from '../../src/services/data_sources.service';
|
|
import { QueryAuthGuard } from 'src/modules/auth/query-auth.guard';
|
|
import { AppsAbilityFactory } from 'src/modules/casl/abilities/apps-ability.factory';
|
|
import { AppsService } from '@services/apps.service';
|
|
import { CreateDataQueryDto, UpdateDataQueryDto } from '@dto/data-query.dto';
|
|
import { User } from 'src/decorators/user.decorator';
|
|
import { decode } from 'js-base64';
|
|
import { dbTransactionWrap } from 'src/helpers/utils.helper';
|
|
import { EntityManager } from 'typeorm';
|
|
import { DataSource } from 'src/entities/data_source.entity';
|
|
import { DataSourceScopes, DataSourceTypes } from 'src/helpers/data_source.constants';
|
|
import { App } from 'src/entities/app.entity';
|
|
import { isEmpty } from 'class-validator';
|
|
|
|
@Controller('data_queries')
|
|
export class DataQueriesController {
|
|
constructor(
|
|
private appsService: AppsService,
|
|
private dataQueriesService: DataQueriesService,
|
|
private dataSourcesService: DataSourcesService,
|
|
private appsAbilityFactory: AppsAbilityFactory
|
|
) {}
|
|
|
|
@UseGuards(JwtAuthGuard)
|
|
@Get()
|
|
async index(@User() user, @Query() query) {
|
|
const app = await this.appsService.findAppFromVersion(query.app_version_id);
|
|
const ability = await this.appsAbilityFactory.appsActions(user, app.id);
|
|
|
|
if (!ability.can('getQueries', app)) {
|
|
throw new ForbiddenException('you do not have permissions to perform this action');
|
|
}
|
|
|
|
const queries = await this.dataQueriesService.all(query);
|
|
const seralizedQueries = [];
|
|
|
|
// serialize
|
|
for (const query of queries) {
|
|
if (query.dataSource.type === DataSourceTypes.STATIC) {
|
|
delete query['dataSourceId'];
|
|
}
|
|
delete query['dataSource'];
|
|
|
|
const decamelizedQuery = decamelizeKeys(query);
|
|
|
|
decamelizedQuery['options'] = query.options;
|
|
|
|
if (query.plugin) {
|
|
decamelizedQuery['plugin'].manifest_file.data = JSON.parse(
|
|
decode(query.plugin.manifestFile.data.toString('utf8'))
|
|
);
|
|
decamelizedQuery['plugin'].icon_file.data = query.plugin.iconFile.data.toString('utf8');
|
|
}
|
|
|
|
seralizedQueries.push(decamelizedQuery);
|
|
}
|
|
|
|
const response = { data_queries: seralizedQueries };
|
|
|
|
return response;
|
|
}
|
|
|
|
@UseGuards(JwtAuthGuard)
|
|
@Post()
|
|
async create(@User() user, @Body() dataQueryDto: CreateDataQueryDto): Promise<object> {
|
|
const {
|
|
kind,
|
|
name,
|
|
options,
|
|
data_source_id: dataSourceId,
|
|
plugin_id: pluginId,
|
|
app_version_id: appVersionId,
|
|
} = dataQueryDto;
|
|
|
|
let dataSource: DataSource;
|
|
let app: App;
|
|
|
|
if (!dataSourceId && !(kind === 'restapi' || kind === 'runjs' || kind === 'tooljetdb' || kind === 'runpy')) {
|
|
throw new BadRequestException();
|
|
}
|
|
|
|
return dbTransactionWrap(async (manager: EntityManager) => {
|
|
if (!dataSourceId && (kind === 'restapi' || kind === 'runjs' || kind === 'tooljetdb' || kind === 'runpy')) {
|
|
dataSource = await this.dataSourcesService.findDefaultDataSource(
|
|
kind,
|
|
appVersionId,
|
|
pluginId,
|
|
user.organizationId,
|
|
manager
|
|
);
|
|
}
|
|
dataSource = await this.dataSourcesService.findOne(dataSource?.id || dataSourceId, manager);
|
|
|
|
if (dataSource.scope === DataSourceScopes.GLOBAL) {
|
|
app = await this.appsService.findAppFromVersion(appVersionId);
|
|
} else {
|
|
app = await this.dataSourcesService.findApp(dataSource?.id || dataSourceId, manager);
|
|
}
|
|
|
|
const ability = await this.appsAbilityFactory.appsActions(user, app.id);
|
|
|
|
if (!ability.can('createQuery', app)) {
|
|
throw new ForbiddenException('you do not have permissions to perform this action');
|
|
}
|
|
|
|
// todo: pass the whole dto instead of indv. values
|
|
const dataQuery = await this.dataQueriesService.create(
|
|
name,
|
|
options,
|
|
dataSource?.id || dataSourceId,
|
|
appVersionId,
|
|
manager
|
|
);
|
|
|
|
const decamelizedQuery = decamelizeKeys({ ...dataQuery, kind });
|
|
|
|
decamelizedQuery['options'] = dataQuery.options;
|
|
|
|
return decamelizedQuery;
|
|
});
|
|
}
|
|
|
|
@UseGuards(JwtAuthGuard)
|
|
@Patch(':id')
|
|
async update(@User() user, @Param('id') dataQueryId, @Body() updateDataQueryDto: UpdateDataQueryDto) {
|
|
const { name, options } = updateDataQueryDto;
|
|
|
|
const dataQuery = await this.dataQueriesService.findOne(dataQueryId);
|
|
const ability = await this.appsAbilityFactory.appsActions(user, dataQuery.app.id);
|
|
|
|
if (!ability.can('updateQuery', dataQuery.app)) {
|
|
throw new ForbiddenException('you do not have permissions to perform this action');
|
|
}
|
|
|
|
const result = await this.dataQueriesService.update(dataQueryId, name, options);
|
|
const decamelizedQuery = decamelizeKeys({ ...dataQuery, ...result });
|
|
decamelizedQuery['options'] = result.options;
|
|
return decamelizedQuery;
|
|
}
|
|
|
|
@UseGuards(JwtAuthGuard)
|
|
@Delete(':id')
|
|
async delete(@User() user, @Param('id') dataQueryId) {
|
|
const dataQuery = await this.dataQueriesService.findOne(dataQueryId);
|
|
const ability = await this.appsAbilityFactory.appsActions(user, dataQuery.app.id);
|
|
|
|
if (!ability.can('deleteQuery', dataQuery.app)) {
|
|
throw new ForbiddenException('you do not have permissions to perform this action');
|
|
}
|
|
|
|
const result = await this.dataQueriesService.delete(dataQueryId);
|
|
return decamelizeKeys(result);
|
|
}
|
|
|
|
@UseGuards(QueryAuthGuard)
|
|
@Post([':id/run/:environmentId', ':id/run'])
|
|
async runQuery(
|
|
@User() user,
|
|
@Param('id') dataQueryId,
|
|
@Param('environmentId') environmentId,
|
|
@Body() updateDataQueryDto: UpdateDataQueryDto
|
|
) {
|
|
const { options, resolvedOptions } = updateDataQueryDto;
|
|
|
|
const dataQuery = await this.dataQueriesService.findOne(dataQueryId);
|
|
|
|
if (user) {
|
|
const ability = await this.appsAbilityFactory.appsActions(user, dataQuery.app.id);
|
|
|
|
if (!ability.can('runQuery', dataQuery.app)) {
|
|
throw new ForbiddenException('you do not have permissions to perform this action');
|
|
}
|
|
|
|
if (ability.can('updateQuery', dataQuery.app) && !isEmpty(options)) {
|
|
await this.dataQueriesService.update(dataQueryId, dataQuery.name, options);
|
|
dataQuery['options'] = options;
|
|
}
|
|
}
|
|
|
|
let result = {};
|
|
|
|
try {
|
|
result = await this.dataQueriesService.runQuery(user, dataQuery, resolvedOptions, environmentId);
|
|
} catch (error) {
|
|
if (error.constructor.name === 'QueryError') {
|
|
result = {
|
|
status: 'failed',
|
|
message: error.message,
|
|
description: error.description,
|
|
data: error.data,
|
|
};
|
|
} else {
|
|
console.log(error);
|
|
result = {
|
|
status: 'failed',
|
|
message: 'Internal server error',
|
|
description: error.message,
|
|
data: {},
|
|
};
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
@UseGuards(JwtAuthGuard)
|
|
@Post(['/preview/:environmentId', '/preview'])
|
|
async previewQuery(
|
|
@User() user,
|
|
@Body() updateDataQueryDto: UpdateDataQueryDto,
|
|
@Param('environmentId') environmentId
|
|
) {
|
|
const { options, query, app_version_id: appVersionId } = updateDataQueryDto;
|
|
|
|
const app = await this.appsService.findAppFromVersion(appVersionId);
|
|
|
|
if (!(query['data_source_id'] || appVersionId || environmentId)) {
|
|
throw new BadRequestException('Data source id or app version id or environment id is mandatory');
|
|
}
|
|
|
|
const kind = query ? query['kind'] : null;
|
|
const dataQueryEntity = {
|
|
...query,
|
|
app,
|
|
dataSource: query['data_source_id']
|
|
? await this.dataSourcesService.findOne(query['data_source_id'])
|
|
: await this.dataSourcesService.findDefaultDataSourceByKind(kind, appVersionId),
|
|
};
|
|
|
|
const ability = await this.appsAbilityFactory.appsActions(user, app.id);
|
|
|
|
if (!ability.can('previewQuery', app)) {
|
|
throw new ForbiddenException('you do not have permissions to perform this action');
|
|
}
|
|
|
|
let result = {};
|
|
|
|
try {
|
|
result = await this.dataQueriesService.runQuery(user, dataQueryEntity, options, environmentId);
|
|
} catch (error) {
|
|
if (error.constructor.name === 'QueryError') {
|
|
result = {
|
|
status: 'failed',
|
|
message: error.message,
|
|
description: error.description,
|
|
data: error.data,
|
|
};
|
|
} else {
|
|
console.log(error);
|
|
result = {
|
|
status: 'failed',
|
|
message: 'Internal server error',
|
|
description: error.message,
|
|
data: {},
|
|
};
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
@UseGuards(JwtAuthGuard)
|
|
@Put(':id/data_source')
|
|
async changeQueryDataSource(@User() user, @Param('id') queryId, @Body() updateDataQueryDto: UpdateDataQueryDto) {
|
|
const { data_source_id: dataSourceId } = updateDataQueryDto;
|
|
|
|
const dataQuery = await this.dataQueriesService.findOne(queryId);
|
|
const ability = await this.appsAbilityFactory.appsActions(user, dataQuery.app.id);
|
|
|
|
if (!ability.can('updateQuery', dataQuery.app)) {
|
|
throw new ForbiddenException('you do not have permissions to perform this action');
|
|
}
|
|
await this.dataQueriesService.changeQueryDataSource(queryId, dataSourceId);
|
|
return;
|
|
}
|
|
}
|