Skip to content

Commit

Permalink
CB-4634 result set panel saves presentation info into the context (#2412
Browse files Browse the repository at this point in the history
)

* CB-4634 result set panel saves presentation info into the context

* CB-4634 adds license to SqlResultSetPanel styles

* Revert "CB-4634 result set panel saves presentation info into the context"

This reverts commit 5bf0d22.

* CB-4634 adds to result set tab cache for value/grouping actions so divider behave alright

* CB-4634 fix: throw an error if result group was not found

* CB-4634 adds zod validation to tab restore in SqlEditor

* CB-4634 adds license to zod.scheme

* CB-4634 adds SqlEditorTabState uses interface generated with Zod

* CB-4634 chore: shceme -> schema

---------

Co-authored-by: s.teleshev <[email protected]>
Co-authored-by: Evgenia Bezborodova <[email protected]>
  • Loading branch information
3 people authored Feb 27, 2024
1 parent 9bc6647 commit b7a4cfa
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/
import { computed, makeObservable, observable, untracked } from 'mobx';

import { ConfirmationDialog } from '@cloudbeaver/core-blocks';
import { ConfirmationDialog, importLazyComponent } from '@cloudbeaver/core-blocks';
import {
ConnectionExecutionContextResource,
ConnectionExecutionContextService,
Expand Down Expand Up @@ -40,16 +40,18 @@ import {
ESqlDataSourceFeatures,
ISQLDatasourceUpdateData,
ISqlEditorTabState,
SQL_EDITOR_TAB_STATE_SCHEMA,
SqlDataSourceService,
SqlEditorService,
SqlResultTabsService,
} from '@cloudbeaver/plugin-sql-editor';

import { isSQLEditorTab } from './isSQLEditorTab';
import { SqlEditorPanel } from './SqlEditorPanel';
import { SqlEditorTab } from './SqlEditorTab';
import { sqlEditorTabHandlerKey } from './sqlEditorTabHandlerKey';

const SqlEditorPanel = importLazyComponent(() => import('./SqlEditorPanel').then(m => m.SqlEditorPanel));
const SqlEditorTab = importLazyComponent(() => import('./SqlEditorTab').then(m => m.SqlEditorTab));

@injectable()
export class SqlEditorTabService extends Bootstrap {
get sqlEditorTabs(): ITab<ISqlEditorTabState>[] {
Expand Down Expand Up @@ -273,20 +275,7 @@ export class SqlEditorTabService extends Bootstrap {
}

private async handleTabRestore(tab: ITab<ISqlEditorTabState>): Promise<boolean> {
if (
typeof tab.handlerState.editorId !== 'string' ||
typeof tab.handlerState.editorId !== 'string' ||
typeof tab.handlerState.order !== 'number' ||
!['string', 'undefined'].includes(typeof tab.handlerState.currentTabId) ||
!['string', 'undefined'].includes(typeof tab.handlerState.source) ||
!['string', 'undefined'].includes(typeof tab.handlerState.currentModeId) ||
!Array.isArray(tab.handlerState.modeState) ||
!Array.isArray(tab.handlerState.tabs) ||
!Array.isArray(tab.handlerState.executionPlanTabs) ||
!Array.isArray(tab.handlerState.resultGroups) ||
!Array.isArray(tab.handlerState.resultTabs) ||
!Array.isArray(tab.handlerState.statisticsTabs)
) {
if (!SQL_EDITOR_TAB_STATE_SCHEMA.safeParse(tab.handlerState).success) {
await this.sqlDataSourceService.destroy(tab.handlerState.editorId);
return false;
}
Expand Down
112 changes: 62 additions & 50 deletions webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,75 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import type { IOutputLogType } from './SqlResultTabs/OutputLogs/IOutputLogTypes';
import { schema } from '@cloudbeaver/core-utils';

export interface IResultTab {
tabId: string;
// when query return several results they all have one groupId
// new group id generates every time you execute query in new tab
groupId: string;
indexInResultSet: number;
}
import { OUTPUT_LOG_TYPES } from './SqlResultTabs/OutputLogs/IOutputLogTypes';

export interface IStatisticsTab {
tabId: string;
order: number;
}
export const RESULT_TAB_SCHEMA = schema.object({
tabId: schema.string(),
groupId: schema.string(),
indexInResultSet: schema.number(),
presentationId: schema.string(),
valuePresentationId: schema.nullable(schema.string()),
});

export interface IResultGroup {
groupId: string;
modelId: string;
order: number;
nameOrder: number;
query: string;
}
export type IResultTab = schema.infer<typeof RESULT_TAB_SCHEMA>;

export interface ISqlEditorResultTab {
id: string;
order: number;
name: string;
icon: string;
}
export const STATISTIC_TAB_SCHEMA = schema.object({
tabId: schema.string(),
order: schema.number(),
});

export interface IExecutionPlanTab {
tabId: string;
order: number;
query: string;
options?: Record<string, any>;
}
export type IStatisticsTab = schema.infer<typeof STATISTIC_TAB_SCHEMA>;

export interface IOutputLogsTab extends ISqlEditorResultTab {
selectedLogTypes: IOutputLogType[];
}
export const RESULT_GROUP_SCHEMA = schema.object({
groupId: schema.string(),
modelId: schema.string(),
order: schema.number(),
nameOrder: schema.number(),
query: schema.string(),
});

export interface ISqlEditorTabState {
editorId: string;
datasourceKey: string;
export type IResultGroup = schema.infer<typeof RESULT_GROUP_SCHEMA>;

source?: string;
order: number;
export const SQL_EDITOR_RESULT_TAB_SCHEMA = schema.object({
id: schema.string(),
order: schema.number(),
name: schema.string(),
icon: schema.string(),
});

currentTabId?: string;
tabs: ISqlEditorResultTab[];
resultGroups: IResultGroup[];
resultTabs: IResultTab[];
statisticsTabs: IStatisticsTab[];
executionPlanTabs: IExecutionPlanTab[];
outputLogsTab?: IOutputLogsTab;
export type ISqlEditorResultTab = schema.infer<typeof SQL_EDITOR_RESULT_TAB_SCHEMA>;

// mode
currentModeId?: string;
modeState: Array<[string, any]>;
}
export const EXECUTION_PLAN_TAB_SCHEMA = schema.object({
tabId: schema.string(),
order: schema.number(),
query: schema.string(),
options: schema.record(schema.any()).optional(),
});

export type IExecutionPlanTab = schema.infer<typeof EXECUTION_PLAN_TAB_SCHEMA>;

const OUTPUT_LOGS_TAB_SCHEMA = SQL_EDITOR_RESULT_TAB_SCHEMA.extend({
selectedLogTypes: schema.array(schema.enum(OUTPUT_LOG_TYPES)),
});

export type IOutputLogsTab = schema.infer<typeof OUTPUT_LOGS_TAB_SCHEMA>;

export const SQL_EDITOR_TAB_STATE_SCHEMA = schema.object({
editorId: schema.string(),
datasourceKey: schema.string(),
source: schema.string().optional(),
order: schema.number(),
currentTabId: schema.string().optional(),
tabs: schema.array(SQL_EDITOR_RESULT_TAB_SCHEMA),
resultGroups: schema.array(RESULT_GROUP_SCHEMA),
resultTabs: schema.array(RESULT_TAB_SCHEMA),
statisticsTabs: schema.array(STATISTIC_TAB_SCHEMA),
executionPlanTabs: schema.array(EXECUTION_PLAN_TAB_SCHEMA),
outputLogsTab: OUTPUT_LOGS_TAB_SCHEMA.optional(),
currentModeId: schema.string().optional(),
modeState: schema.array(schema.tuple([schema.string(), schema.any()])),
});

export type ISqlEditorTabState = schema.infer<typeof SQL_EDITOR_TAB_STATE_SCHEMA>;
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { injectable } from '@cloudbeaver/core-di';
import { uuid } from '@cloudbeaver/core-utils';
import { IDatabaseDataModel, IDatabaseResultSet, TableViewerStorageService } from '@cloudbeaver/plugin-data-viewer';

import type { IResultGroup, ISqlEditorTabState, IStatisticsTab } from '../ISqlEditorTabState';
import type { IResultGroup, IResultTab, ISqlEditorTabState, IStatisticsTab } from '../ISqlEditorTabState';
import type { IDataQueryOptions } from '../QueryDataSource';

@injectable()
Expand Down Expand Up @@ -199,14 +199,14 @@ export class SqlQueryResultService {
model: IDatabaseDataModel<IDataQueryOptions, IDatabaseResultSet>,
resultCount?: number,
) {
this.updateResultTab(state, group, model, 0, resultCount);
this.createResultTabForGroup(state, group, model, 0, resultCount);

for (let i = 1; i < model.source.results.length; i++) {
this.updateResultTab(state, group, model, i, resultCount);
this.createResultTabForGroup(state, group, model, i, resultCount);
}
}

private updateResultTab(
private createResultTabForGroup(
state: ISqlEditorTabState,
group: IResultGroup,
model: IDatabaseDataModel<IDataQueryOptions, IDatabaseResultSet>,
Expand All @@ -226,13 +226,25 @@ export class SqlQueryResultService {
}
}

updateResultTab(state: ISqlEditorTabState, id: string, resultTab: Partial<IResultTab>) {
const index = state.resultTabs.findIndex(tab => tab.tabId === id);

if (index === -1) {
return;
}

state.resultTabs[index] = { ...state.resultTabs[index], ...resultTab };
}

private createResultTab(state: ISqlEditorTabState, group: IResultGroup, indexInResultSet: number, results: number, resultCount?: number) {
const id = uuid();

state.resultTabs.push({
tabId: id,
groupId: group.groupId,
indexInResultSet,
presentationId: '',
valuePresentationId: null,
});

state.tabs.push({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,9 @@ export const SqlResultPanel = observer<Props>(function SqlResultPanel({ state, i
const resultTab = state.resultTabs.find(tab => tab.tabId === id);

if (resultTab) {
const group = state.resultGroups.find(group => group.groupId === resultTab.groupId)!;

return styled(style)(
<result-panel>
<SqlResultSetPanel resultTab={resultTab} group={group} />
<SqlResultSetPanel resultTab={resultTab} state={state} />
</result-panel>,
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/

.tableViewerLoader {
padding: 8px;
padding-bottom: 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,48 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import { useState } from 'react';
import styled, { css } from 'reshadow';

import { useService } from '@cloudbeaver/core-di';
import { TableViewerLoader } from '@cloudbeaver/plugin-data-viewer';

import type { IResultGroup, IResultTab } from '../ISqlEditorTabState';

const styles = css`
TableViewerLoader {
padding: 8px;
padding-bottom: 0;
}
`;
import type { IResultTab, ISqlEditorTabState } from '../ISqlEditorTabState';
import { SqlQueryResultService } from './SqlQueryResultService';
import style from './SqlResultSetPanel.m.css';

interface Props {
group: IResultGroup;
state: ISqlEditorTabState;
resultTab: IResultTab;
}

export const SqlResultSetPanel = observer<Props>(function SqlResultSetPanel({ group, resultTab }) {
const [presentationId, setPresentation] = useState('');
const [valuePresentationId, setValuePresentation] = useState<string | null>(null);
export const SqlResultSetPanel = observer<Props>(function SqlResultSetPanel({ state, resultTab }) {
const sqlQueryResultService = useService(SqlQueryResultService);
const group = state.resultGroups.find(group => group.groupId === resultTab.groupId);

function onPresentationChange(presentationId: string) {
sqlQueryResultService.updateResultTab(state, resultTab.tabId, {
presentationId,
});
}

function onValuePresentationChange(valuePresentationId: string | null) {
sqlQueryResultService.updateResultTab(state, resultTab.tabId, {
valuePresentationId,
});
}

if (!group) {
throw new Error('Result group not found');
}

return styled(styles)(
return (
<TableViewerLoader
className={style.tableViewerLoader}
tableId={group.modelId}
resultIndex={resultTab.indexInResultSet}
presentationId={presentationId}
valuePresentationId={valuePresentationId}
onPresentationChange={setPresentation}
onValuePresentationChange={setValuePresentation}
/>,
presentationId={resultTab.presentationId}
valuePresentationId={resultTab.valuePresentationId}
onPresentationChange={onPresentationChange}
onValuePresentationChange={onValuePresentationChange}
/>
);
});

0 comments on commit b7a4cfa

Please sign in to comment.