ydb-embedded-ui 1.13.2 → 1.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/dist/assets/icons/flask.svg +3 -0
- package/dist/components/InfoViewer/formatters/common.ts +15 -0
- package/dist/components/InfoViewer/formatters/index.ts +2 -0
- package/dist/components/InfoViewer/formatters/schema.ts +43 -0
- package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +44 -0
- package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +34 -0
- package/dist/components/{IndexInfoViewer/IndexInfoViewer.tsx → InfoViewer/schemaInfo/TableIndexInfo.tsx} +7 -18
- package/dist/components/InfoViewer/schemaInfo/index.ts +3 -0
- package/dist/components/InfoViewer/schemaOverview/CDCStreamOverview.tsx +44 -0
- package/dist/components/InfoViewer/schemaOverview/PersQueueGroupOverview.tsx +35 -0
- package/dist/components/InfoViewer/schemaOverview/index.ts +2 -0
- package/dist/components/QueryResultTable/Cell/Cell.tsx +33 -0
- package/dist/components/QueryResultTable/Cell/index.ts +1 -0
- package/dist/components/QueryResultTable/QueryResultTable.scss +11 -0
- package/dist/components/QueryResultTable/QueryResultTable.tsx +115 -0
- package/dist/components/QueryResultTable/i18n/en.json +3 -0
- package/dist/components/QueryResultTable/i18n/index.ts +11 -0
- package/dist/components/QueryResultTable/i18n/ru.json +3 -0
- package/dist/components/QueryResultTable/index.ts +1 -0
- package/dist/containers/App/App.scss +1 -0
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +39 -14
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +18 -7
- package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +4 -3
- package/dist/containers/Storage/Vdisk/__tests__/colors.tsx +7 -7
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +6 -2
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +1 -1
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +8 -3
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.js +1 -1
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +1 -1
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +36 -10
- package/dist/containers/Tenant/Preview/Preview.js +15 -57
- package/dist/containers/Tenant/Preview/Preview.scss +4 -8
- package/dist/containers/Tenant/QueryEditor/QueryEditor.js +12 -41
- package/dist/containers/Tenant/QueryEditor/QueryEditor.scss +0 -4
- package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.scss +1 -2
- package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +2 -2
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +1 -1
- package/dist/containers/Tenant/utils/schema.ts +3 -0
- package/dist/containers/Tenant/utils/schemaActions.ts +1 -2
- package/dist/containers/Tenants/Tenants.js +12 -2
- package/dist/containers/UserSettings/UserSettings.tsx +26 -3
- package/dist/services/api.d.ts +19 -2
- package/dist/services/api.js +2 -2
- package/dist/setupTests.js +4 -0
- package/dist/store/reducers/executeQuery.js +4 -9
- package/dist/store/reducers/{preview.js → preview.ts} +22 -18
- package/dist/store/reducers/settings.js +3 -1
- package/dist/store/utils.ts +88 -0
- package/dist/types/api/query.ts +147 -0
- package/dist/types/api/schema.ts +235 -2
- package/dist/types/index.ts +33 -0
- package/dist/types/store/query.ts +9 -0
- package/dist/utils/{constants.js → constants.ts} +11 -6
- package/dist/utils/index.js +0 -24
- package/dist/utils/query.test.ts +189 -0
- package/dist/utils/query.ts +156 -0
- package/dist/utils/tests/providers.tsx +29 -0
- package/package.json +2 -2
- package/dist/store/utils.js +0 -51
| @@ -20,9 +20,8 @@ const alterTableTemplate = (path: string) => { | |
| 20 20 | 
             
                ADD COLUMN is_deleted Bool;`;
         | 
| 21 21 | 
             
            };
         | 
| 22 22 | 
             
            const selectQueryTemplate = (path: string) => {
         | 
| 23 | 
            -
                return `SELECT  | 
| 23 | 
            +
                return `SELECT *
         | 
| 24 24 | 
             
                FROM \`${path}\`
         | 
| 25 | 
            -
                ORDER BY \`id\`
         | 
| 26 25 | 
             
                LIMIT 10;`;
         | 
| 27 26 | 
             
            };
         | 
| 28 27 | 
             
            const upsertQueryTemplate = (path: string) => {
         | 
| @@ -14,7 +14,7 @@ import ProblemFilter, {problemFilterType} from '../../components/ProblemFilter/P | |
| 14 14 | 
             
            import {AutoFetcher} from '../../utils/autofetcher';
         | 
| 15 15 |  | 
| 16 16 | 
             
            import routes, {CLUSTER_PAGES, createHref} from '../../routes';
         | 
| 17 | 
            -
            import {formatCPU, formatBytesToGigabyte} from '../../utils';
         | 
| 17 | 
            +
            import {formatCPU, formatBytesToGigabyte, formatNumber} from '../../utils';
         | 
| 18 18 | 
             
            import {hideTooltip, showTooltip} from '../../store/reducers/tooltip';
         | 
| 19 19 | 
             
            import {withSearch} from '../../HOCS';
         | 
| 20 20 | 
             
            import {ALL, DEFAULT_TABLE_SETTINGS, TENANT_INITIAL_TAB_KEY} from '../../utils/constants';
         | 
| @@ -257,13 +257,23 @@ class Tenants extends React.Component { | |
| 257 257 | 
             
                            align: DataTable.RIGHT,
         | 
| 258 258 | 
             
                            defaultOrder: DataTable.DESCENDING,
         | 
| 259 259 | 
             
                        },
         | 
| 260 | 
            +
                        {
         | 
| 261 | 
            +
                            name: 'NodeIds',
         | 
| 262 | 
            +
                            header: 'Nodes',
         | 
| 263 | 
            +
                            width: 100,
         | 
| 264 | 
            +
                            accessor: ({NodeIds}) => NodeIds?.length || 0,
         | 
| 265 | 
            +
                            sortAccessor: ({NodeIds}) => NodeIds?.length || 0,
         | 
| 266 | 
            +
                            render: ({value}) => formatNumber(value),
         | 
| 267 | 
            +
                            align: DataTable.RIGHT,
         | 
| 268 | 
            +
                            defaultOrder: DataTable.DESCENDING,
         | 
| 269 | 
            +
                        },
         | 
| 260 270 | 
             
                        {
         | 
| 261 271 | 
             
                            name: 'StorageGroups',
         | 
| 262 272 | 
             
                            header: 'Groups',
         | 
| 263 273 | 
             
                            width: 100,
         | 
| 264 274 | 
             
                            sortAccessor: ({StorageGroups}) =>
         | 
| 265 275 | 
             
                                isNaN(Number(StorageGroups)) ? 0 : Number(StorageGroups),
         | 
| 266 | 
            -
                            render: ({value}) => value  | 
| 276 | 
            +
                            render: ({value}) => formatNumber(value) || '—',
         | 
| 267 277 | 
             
                            align: DataTable.RIGHT,
         | 
| 268 278 | 
             
                            defaultOrder: DataTable.DESCENDING,
         | 
| 269 279 | 
             
                        },
         | 
| @@ -1,10 +1,11 @@ | |
| 1 1 | 
             
            import {connect} from 'react-redux';
         | 
| 2 2 |  | 
| 3 | 
            -
            import {RadioButton} from '@yandex-cloud/uikit';
         | 
| 3 | 
            +
            import {RadioButton, Switch} from '@yandex-cloud/uikit';
         | 
| 4 4 | 
             
            import {Settings} from '../../components/AsideNavigation/Settings';
         | 
| 5 5 | 
             
            import favoriteFilledIcon from '../../assets/icons/star.svg';
         | 
| 6 | 
            +
            import flaskIcon from '../../assets/icons/flask.svg';
         | 
| 6 7 | 
             
            //@ts-ignore
         | 
| 7 | 
            -
            import {THEME_KEY} from '../../utils/constants';
         | 
| 8 | 
            +
            import {INVERTED_DISKS_KEY, THEME_KEY} from '../../utils/constants';
         | 
| 8 9 | 
             
            //@ts-ignore
         | 
| 9 10 | 
             
            import {setSettingValue} from '../../store/reducers/settings';
         | 
| 10 11 |  | 
| @@ -19,6 +20,10 @@ function UserSettings(props: any) { | |
| 19 20 | 
             
                    props.setSettingValue(THEME_KEY, value);
         | 
| 20 21 | 
             
                };
         | 
| 21 22 |  | 
| 23 | 
            +
                const _onInvertedDisksChangeHandler = (value: boolean) => {
         | 
| 24 | 
            +
                    props.setSettingValue(INVERTED_DISKS_KEY, value);
         | 
| 25 | 
            +
                };
         | 
| 26 | 
            +
             | 
| 22 27 | 
             
                return (
         | 
| 23 28 | 
             
                    <Settings>
         | 
| 24 29 | 
             
                        <Settings.Page
         | 
| @@ -36,15 +41,33 @@ function UserSettings(props: any) { | |
| 36 41 | 
             
                                </Settings.Item>
         | 
| 37 42 | 
             
                            </Settings.Section>
         | 
| 38 43 | 
             
                        </Settings.Page>
         | 
| 44 | 
            +
                        <Settings.Page
         | 
| 45 | 
            +
                            id="experiments"
         | 
| 46 | 
            +
                            title="Experiments"
         | 
| 47 | 
            +
                            icon={{data: flaskIcon}}
         | 
| 48 | 
            +
                        >
         | 
| 49 | 
            +
                            <Settings.Section title="Experiments">
         | 
| 50 | 
            +
                                <Settings.Item title="Inverted disks space indicators">
         | 
| 51 | 
            +
                                    <Switch
         | 
| 52 | 
            +
                                        checked={props.invertedDisks}
         | 
| 53 | 
            +
                                        onUpdate={_onInvertedDisksChangeHandler}
         | 
| 54 | 
            +
                                    />
         | 
| 55 | 
            +
                                </Settings.Item>
         | 
| 56 | 
            +
                            </Settings.Section>
         | 
| 57 | 
            +
                        </Settings.Page>
         | 
| 39 58 | 
             
                    </Settings>
         | 
| 40 59 | 
             
                );
         | 
| 41 60 | 
             
            }
         | 
| 42 61 |  | 
| 43 62 | 
             
            const mapStateToProps = (state: any) => {
         | 
| 44 | 
            -
                const { | 
| 63 | 
            +
                const {
         | 
| 64 | 
            +
                    theme,
         | 
| 65 | 
            +
                    invertedDisks,
         | 
| 66 | 
            +
                } = state.settings.userSettings;
         | 
| 45 67 |  | 
| 46 68 | 
             
                return {
         | 
| 47 69 | 
             
                    theme,
         | 
| 70 | 
            +
                    invertedDisks,
         | 
| 48 71 | 
             
                };
         | 
| 49 72 | 
             
            };
         | 
| 50 73 |  | 
    
        package/dist/services/api.d.ts
    CHANGED
    
    | @@ -1,8 +1,12 @@ | |
| 1 | 
            +
            type AxiosOptions = {
         | 
| 2 | 
            +
                concurrentId?: string;
         | 
| 3 | 
            +
            };
         | 
| 4 | 
            +
             | 
| 1 5 | 
             
            interface Window {
         | 
| 2 6 | 
             
                api: {
         | 
| 3 7 | 
             
                    getSchema: (
         | 
| 4 8 | 
             
                        params: {path: string},
         | 
| 5 | 
            -
                        axiosOptions?:  | 
| 9 | 
            +
                        axiosOptions?: AxiosOptions,
         | 
| 6 10 | 
             
                    ) => Promise<import('../types/api/schema').TEvDescribeSchemeResult>;
         | 
| 7 11 | 
             
                    getStorageInfo: (
         | 
| 8 12 | 
             
                        params: {
         | 
| @@ -11,8 +15,21 @@ interface Window { | |
| 11 15 | 
             
                            nodeId: string,
         | 
| 12 16 | 
             
                            type: 'Groups' | 'Nodes',
         | 
| 13 17 | 
             
                        },
         | 
| 14 | 
            -
                        axiosOptions?:  | 
| 18 | 
            +
                        axiosOptions?: AxiosOptions,
         | 
| 15 19 | 
             
                    ) => Promise<import('../types/api/storage').TStorageInfo>;
         | 
| 20 | 
            +
                    sendQuery: <
         | 
| 21 | 
            +
                        Action extends import('../types/api/query').Actions,
         | 
| 22 | 
            +
                        Schema extends import('../types/api/query').Schemas = undefined
         | 
| 23 | 
            +
                    >(
         | 
| 24 | 
            +
                        params: {
         | 
| 25 | 
            +
                            query?: string,
         | 
| 26 | 
            +
                            database?: string,
         | 
| 27 | 
            +
                            action?: Action,
         | 
| 28 | 
            +
                            stats?: string,
         | 
| 29 | 
            +
                            schema?: Schema,
         | 
| 30 | 
            +
                        },
         | 
| 31 | 
            +
                        axiosOptions?: AxiosOptions,
         | 
| 32 | 
            +
                    ) => Promise<import('../types/api/query').QueryAPIResponse<Action, Schema>>;
         | 
| 16 33 | 
             
                    [method: string]: Function;
         | 
| 17 34 | 
             
                };
         | 
| 18 35 | 
             
            }
         | 
    
        package/dist/services/api.js
    CHANGED
    
    | @@ -146,9 +146,9 @@ export class YdbEmbeddedAPI extends AxiosWrapper { | |
| 146 146 | 
             
                        state: 0,
         | 
| 147 147 | 
             
                    });
         | 
| 148 148 | 
             
                }
         | 
| 149 | 
            -
                sendQuery({query, database, action, stats}, {concurrentId} = {}) {
         | 
| 149 | 
            +
                sendQuery({query, database, action, stats, schema}, {concurrentId} = {}) {
         | 
| 150 150 | 
             
                    return this.post(
         | 
| 151 | 
            -
                        this.getPath( | 
| 151 | 
            +
                        this.getPath(`/viewer/json/query${schema ? `?schema=${schema}` : ''}`),
         | 
| 152 152 | 
             
                        {
         | 
| 153 153 | 
             
                            query,
         | 
| 154 154 | 
             
                            database,
         | 
    
        package/dist/setupTests.js
    CHANGED
    
    | @@ -11,3 +11,7 @@ import {i18n, Lang} from '../src/utils/i18n'; | |
| 11 11 | 
             
            i18n.setLang(Lang.En);
         | 
| 12 12 | 
             
            configureYdbUiComponents({lang: Lang.En});
         | 
| 13 13 | 
             
            configureUiKit({lang: Lang.En});
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            // only to prevent warnings from history lib
         | 
| 16 | 
            +
            // all api calls in tests should be mocked
         | 
| 17 | 
            +
            window.custom_backend = '/';
         | 
| @@ -2,6 +2,7 @@ import {createRequestActionTypes, createApiRequest} from '../utils'; | |
| 2 2 | 
             
            import '../../services/api';
         | 
| 3 3 | 
             
            import {getValueFromLS, parseJson} from '../../utils/utils';
         | 
| 4 4 | 
             
            import {QUERIES_HISTORY_KEY, QUERY_INITIAL_RUN_ACTION_KEY} from '../../utils/constants';
         | 
| 5 | 
            +
            import {parseQueryAPIExecuteResponse} from '../../utils/query';
         | 
| 5 6 | 
             
            import {readSavedSettingsValue} from './settings';
         | 
| 6 7 |  | 
| 7 8 | 
             
            const MAXIMUM_QUERIES_IN_HISTORY = 20;
         | 
| @@ -57,7 +58,7 @@ const executeQuery = (state = initialState, action) => { | |
| 57 58 | 
             
                    case SEND_QUERY.SUCCESS: {
         | 
| 58 59 | 
             
                        return {
         | 
| 59 60 | 
             
                            ...state,
         | 
| 60 | 
            -
                            data: action.data | 
| 61 | 
            +
                            data: action.data,
         | 
| 61 62 | 
             
                            stats: action.data.stats,
         | 
| 62 63 | 
             
                            loading: false,
         | 
| 63 64 | 
             
                            error: undefined,
         | 
| @@ -142,15 +143,9 @@ const executeQuery = (state = initialState, action) => { | |
| 142 143 |  | 
| 143 144 | 
             
            export const sendQuery = ({query, database, action}) => {
         | 
| 144 145 | 
             
                return createApiRequest({
         | 
| 145 | 
            -
                    request: window.api.sendQuery({query, database, action, stats: 'profile'}),
         | 
| 146 | 
            +
                    request: window.api.sendQuery({schema: 'modern', query, database, action, stats: 'profile'}),
         | 
| 146 147 | 
             
                    actions: SEND_QUERY,
         | 
| 147 | 
            -
                    dataHandler:  | 
| 148 | 
            -
                        const resultData = result.result ?? result;
         | 
| 149 | 
            -
                        if (resultData && typeof resultData === 'string') {
         | 
| 150 | 
            -
                            throw 'Unexpected token in JSON.';
         | 
| 151 | 
            -
                        }
         | 
| 152 | 
            -
                        return result;
         | 
| 153 | 
            -
                    },
         | 
| 148 | 
            +
                    dataHandler: parseQueryAPIExecuteResponse,
         | 
| 154 149 | 
             
                });
         | 
| 155 150 | 
             
            };
         | 
| 156 151 |  | 
| @@ -1,15 +1,23 @@ | |
| 1 | 
            -
            import {createRequestActionTypes, createApiRequest} from '../utils';
         | 
| 2 1 | 
             
            import '../../services/api';
         | 
| 3 2 |  | 
| 3 | 
            +
            import type {ErrorRepsonse, ExecuteActions} from '../../types/api/query';
         | 
| 4 | 
            +
            import type {IQueryResult} from '../../types/store/query';
         | 
| 5 | 
            +
            import {parseQueryAPIExecuteResponse} from '../../utils/query';
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            import {createRequestActionTypes, createApiRequest, ApiRequestAction} from '../utils';
         | 
| 8 | 
            +
             | 
| 4 9 | 
             
            const SEND_QUERY = createRequestActionTypes('preview', 'SEND_QUERY');
         | 
| 5 | 
            -
            const SET_QUERY_OPTIONS =  | 
| 10 | 
            +
            const SET_QUERY_OPTIONS = 'preview/SET_QUERY_OPTIONS';
         | 
| 6 11 |  | 
| 7 12 | 
             
            const initialState = {
         | 
| 8 13 | 
             
                loading: false,
         | 
| 9 14 | 
             
                wasLoaded: false,
         | 
| 10 15 | 
             
            };
         | 
| 11 16 |  | 
| 12 | 
            -
            const preview = ( | 
| 17 | 
            +
            const preview = (
         | 
| 18 | 
            +
                state = initialState,
         | 
| 19 | 
            +
                action: ApiRequestAction<typeof SEND_QUERY, IQueryResult, ErrorRepsonse> | ReturnType<typeof setQueryOptions>,
         | 
| 20 | 
            +
            ) => {
         | 
| 13 21 | 
             
                switch (action.type) {
         | 
| 14 22 | 
             
                    case SEND_QUERY.REQUEST: {
         | 
| 15 23 | 
             
                        return {
         | 
| @@ -45,29 +53,25 @@ const preview = (state = initialState, action) => { | |
| 45 53 | 
             
                }
         | 
| 46 54 | 
             
            };
         | 
| 47 55 |  | 
| 48 | 
            -
             | 
| 56 | 
            +
            interface SendQueryParams {
         | 
| 57 | 
            +
                query?: string;
         | 
| 58 | 
            +
                database?: string;
         | 
| 59 | 
            +
                action?: ExecuteActions;
         | 
| 60 | 
            +
            };
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            export const sendQuery = ({query, database, action}: SendQueryParams) => {
         | 
| 49 63 | 
             
                return createApiRequest({
         | 
| 50 | 
            -
                    request: window.api.sendQuery({query, database, action}),
         | 
| 64 | 
            +
                    request: window.api.sendQuery({schema: 'modern', query, database, action}),
         | 
| 51 65 | 
             
                    actions: SEND_QUERY,
         | 
| 52 | 
            -
                    dataHandler:  | 
| 53 | 
            -
                        if (!Array.isArray(data)) {
         | 
| 54 | 
            -
                            try {
         | 
| 55 | 
            -
                                return JSON.parse(data);
         | 
| 56 | 
            -
                            } catch (e) {
         | 
| 57 | 
            -
                                return [];
         | 
| 58 | 
            -
                            }
         | 
| 59 | 
            -
                        }
         | 
| 60 | 
            -
             | 
| 61 | 
            -
                        return data;
         | 
| 62 | 
            -
                    },
         | 
| 66 | 
            +
                    dataHandler: parseQueryAPIExecuteResponse,
         | 
| 63 67 | 
             
                });
         | 
| 64 68 | 
             
            };
         | 
| 65 69 |  | 
| 66 | 
            -
            export function setQueryOptions(options) {
         | 
| 70 | 
            +
            export function setQueryOptions(options: any) {
         | 
| 67 71 | 
             
                return {
         | 
| 68 72 | 
             
                    type: SET_QUERY_OPTIONS,
         | 
| 69 73 | 
             
                    data: options,
         | 
| 70 | 
            -
                };
         | 
| 74 | 
            +
                } as const;
         | 
| 71 75 | 
             
            }
         | 
| 72 76 |  | 
| 73 77 | 
             
            export default preview;
         | 
| @@ -5,6 +5,7 @@ import { | |
| 5 5 | 
             
                THEME_KEY,
         | 
| 6 6 | 
             
                TENANT_INITIAL_TAB_KEY,
         | 
| 7 7 | 
             
                QUERY_INITIAL_RUN_ACTION_KEY,
         | 
| 8 | 
            +
                INVERTED_DISKS_KEY,
         | 
| 8 9 | 
             
            } from '../../utils/constants';
         | 
| 9 10 | 
             
            import '../../services/api';
         | 
| 10 11 | 
             
            import {getValueFromLS} from '../../utils/utils';
         | 
| @@ -28,7 +29,8 @@ export const initialState = { | |
| 28 29 | 
             
                userSettings: {
         | 
| 29 30 | 
             
                    ...defaultUserSettings,
         | 
| 30 31 | 
             
                    ...userSettings,
         | 
| 31 | 
            -
                     | 
| 32 | 
            +
                    [THEME_KEY]: readSavedSettingsValue(THEME_KEY, 'light'),
         | 
| 33 | 
            +
                    [INVERTED_DISKS_KEY]: readSavedSettingsValue(INVERTED_DISKS_KEY) === 'true',
         | 
| 32 34 | 
             
                    [SAVED_QUERIES_KEY]: readSavedSettingsValue(SAVED_QUERIES_KEY, '[]'),
         | 
| 33 35 | 
             
                    [TENANT_INITIAL_TAB_KEY]: readSavedSettingsValue(TENANT_INITIAL_TAB_KEY),
         | 
| 34 36 | 
             
                    [QUERY_INITIAL_RUN_ACTION_KEY]: readSavedSettingsValue(QUERY_INITIAL_RUN_ACTION_KEY),
         | 
| @@ -0,0 +1,88 @@ | |
| 1 | 
            +
            import type {Dispatch} from 'redux';
         | 
| 2 | 
            +
            import {AxiosResponse} from 'axios';
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            import createToast from '../utils/createToast';
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            import {SET_UNAUTHENTICATED} from './reducers/authentication';
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            export const nop = (result: any) => result;
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            export function createRequestActionTypes<Prefix extends string, Type extends string>(prefix: Prefix, type: Type) {
         | 
| 11 | 
            +
                return {
         | 
| 12 | 
            +
                    REQUEST: `${prefix}/${type}_REQUEST`,
         | 
| 13 | 
            +
                    SUCCESS: `${prefix}/${type}_SUCCESS`,
         | 
| 14 | 
            +
                    FAILURE: `${prefix}/${type}_FAILURE`,
         | 
| 15 | 
            +
                } as const;
         | 
| 16 | 
            +
            }
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            const isAxiosResponse = (response: any): response is AxiosResponse => response && 'status' in response;
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            type CreateApiRequestParams<Actions, Response, HandledResponse> = {
         | 
| 21 | 
            +
                actions: Actions;
         | 
| 22 | 
            +
                request: Promise<Response>;
         | 
| 23 | 
            +
                dataHandler: (data: Response, getState?: () => any) => HandledResponse;
         | 
| 24 | 
            +
            };
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            export function createApiRequest<
         | 
| 27 | 
            +
                Actions extends ReturnType<typeof createRequestActionTypes>,
         | 
| 28 | 
            +
                Response,
         | 
| 29 | 
            +
                HandledResponse,
         | 
| 30 | 
            +
            >({actions, request, dataHandler = nop}: CreateApiRequestParams<Actions, Response, HandledResponse>) {
         | 
| 31 | 
            +
                const doRequest = async function (dispatch: Dispatch, getState: () => any) {
         | 
| 32 | 
            +
                    dispatch({
         | 
| 33 | 
            +
                        type: actions.REQUEST,
         | 
| 34 | 
            +
                    });
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                    try {
         | 
| 37 | 
            +
                        const result = await request;
         | 
| 38 | 
            +
                        const data = dataHandler(result, getState);
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                        dispatch({
         | 
| 41 | 
            +
                            type: actions.SUCCESS,
         | 
| 42 | 
            +
                            data,
         | 
| 43 | 
            +
                        });
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                        return data;
         | 
| 46 | 
            +
                    } catch (error) {
         | 
| 47 | 
            +
                        if (isAxiosResponse(error) && error.status === 401) {
         | 
| 48 | 
            +
                            dispatch({
         | 
| 49 | 
            +
                                type: SET_UNAUTHENTICATED.SUCCESS,
         | 
| 50 | 
            +
                            });
         | 
| 51 | 
            +
                        } else if (isAxiosResponse(error) && error.status >= 500 && error.statusText) {
         | 
| 52 | 
            +
                            createToast({
         | 
| 53 | 
            +
                                name: 'Request failure',
         | 
| 54 | 
            +
                                title: 'Request failure',
         | 
| 55 | 
            +
                                type: 'error',
         | 
| 56 | 
            +
                                content: `${error.status} ${error.statusText}`,
         | 
| 57 | 
            +
                            });
         | 
| 58 | 
            +
                        }
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                        dispatch({
         | 
| 61 | 
            +
                            type: actions.FAILURE,
         | 
| 62 | 
            +
                            error,
         | 
| 63 | 
            +
                        });
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                        // TODO should probably throw the received error here, but this change requires a thorough revision of all api calls
         | 
| 66 | 
            +
                        return undefined;
         | 
| 67 | 
            +
                    }
         | 
| 68 | 
            +
                };
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                return doRequest;
         | 
| 71 | 
            +
            }
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            export type ApiRequestAction<
         | 
| 74 | 
            +
                Actions extends ReturnType<typeof createRequestActionTypes>,
         | 
| 75 | 
            +
                SuccessResponse = unknown,
         | 
| 76 | 
            +
                ErrorResponse = unknown
         | 
| 77 | 
            +
            > =
         | 
| 78 | 
            +
                | {
         | 
| 79 | 
            +
                    type: Actions['REQUEST'],
         | 
| 80 | 
            +
                }
         | 
| 81 | 
            +
                | {
         | 
| 82 | 
            +
                    type: Actions['SUCCESS'],
         | 
| 83 | 
            +
                    data: SuccessResponse,
         | 
| 84 | 
            +
                }
         | 
| 85 | 
            +
                | {
         | 
| 86 | 
            +
                    type: Actions['FAILURE'],
         | 
| 87 | 
            +
                    error: ErrorResponse,
         | 
| 88 | 
            +
                };
         | 
| @@ -0,0 +1,147 @@ | |
| 1 | 
            +
            // common
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            type Plan = Record<string, any>;
         | 
| 4 | 
            +
            type AST = string;
         | 
| 5 | 
            +
            type Stats = Record<string, any>;
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            export interface CommonFields {
         | 
| 8 | 
            +
                ast?: AST;
         | 
| 9 | 
            +
                plan?: Plan;
         | 
| 10 | 
            +
                stats?: Stats;
         | 
| 11 | 
            +
            };
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            interface DeprecatedCommonFields {
         | 
| 14 | 
            +
                stats?: Stats;
         | 
| 15 | 
            +
            }
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            export interface ErrorRepsonse {
         | 
| 18 | 
            +
                error?: any;
         | 
| 19 | 
            +
                issues?: any;
         | 
| 20 | 
            +
            };
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            export type ExecuteActions = 'execute-script' | 'execute' | 'execute-scan' | undefined;
         | 
| 23 | 
            +
            export type ExplainActions = 'explain' | 'explain-ast';
         | 
| 24 | 
            +
            export type Actions = ExecuteActions | ExplainActions;
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            // undefined == 'classic'
         | 
| 27 | 
            +
            export type Schemas = 'classic' | 'modern' | 'ydb' | undefined;
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            // ==== EXECUTE ====
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            // common types
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            type CellValue = string | number | null | undefined;
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            export type KeyValueRow<T = CellValue> = {
         | 
| 36 | 
            +
                [key: string]: T;
         | 
| 37 | 
            +
            }
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            export type ArrayRow<T = CellValue> = Array<T>;
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            export interface ColumnType {
         | 
| 42 | 
            +
                name: string;
         | 
| 43 | 
            +
                type: string;
         | 
| 44 | 
            +
            }
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            // modern response
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            export type ExecuteModernResponse = {
         | 
| 49 | 
            +
                // either both fields exist, or neither one does
         | 
| 50 | 
            +
                // they can be undefined for queries like `insert into`
         | 
| 51 | 
            +
                result?: ArrayRow[];
         | 
| 52 | 
            +
                columns?: ColumnType[];
         | 
| 53 | 
            +
            } & CommonFields;
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            export type ExecuteClassicResponseDeep = {
         | 
| 56 | 
            +
                // can be undefined for queries like `insert into`
         | 
| 57 | 
            +
                result?: KeyValueRow[];
         | 
| 58 | 
            +
            } & CommonFields;
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            // can be undefined for queries like `insert into`
         | 
| 61 | 
            +
            export type ExecuteClassicResponsePlain = KeyValueRow[] | undefined;
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            export type ExecuteClassicResponse = ExecuteClassicResponseDeep | ExecuteClassicResponsePlain;
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            export type ExecuteYdbResponse = {
         | 
| 66 | 
            +
                // can be undefined for queries like `insert into`
         | 
| 67 | 
            +
                result?: KeyValueRow[];
         | 
| 68 | 
            +
            } & CommonFields;
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            type ExecuteResponse<Schema extends Schemas> = (
         | 
| 71 | 
            +
                Schema extends 'modern'
         | 
| 72 | 
            +
                    ? ExecuteModernResponse
         | 
| 73 | 
            +
                    : Schema extends 'ydb'
         | 
| 74 | 
            +
                        ? ExecuteYdbResponse
         | 
| 75 | 
            +
                        : Schema extends 'classic' | undefined
         | 
| 76 | 
            +
                            ? ExecuteClassicResponse
         | 
| 77 | 
            +
                            : unknown
         | 
| 78 | 
            +
            );
         | 
| 79 | 
            +
             | 
| 80 | 
            +
            // deprecated response from older versions, backward compatibility
         | 
| 81 | 
            +
             | 
| 82 | 
            +
            type DeprecatedExecuteResponseValue =
         | 
| 83 | 
            +
                | KeyValueRow[]
         | 
| 84 | 
            +
                | string
         | 
| 85 | 
            +
                // can be here because of a bug in the previous backend version
         | 
| 86 | 
            +
                // should be ignored in parsing
         | 
| 87 | 
            +
                | Plan;
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            export type DeprecatedExecuteResponseDeep = {
         | 
| 90 | 
            +
                // can be undefined for queries like `insert into`
         | 
| 91 | 
            +
                result?: DeprecatedExecuteResponseValue;
         | 
| 92 | 
            +
            } & DeprecatedCommonFields;
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            // can be undefined for queries like `insert into`
         | 
| 95 | 
            +
            export type DeprecatedExecuteResponsePlain = DeprecatedExecuteResponseValue | undefined;
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            export type DeprecatedExecuteResponse = DeprecatedExecuteResponseDeep | DeprecatedExecuteResponsePlain;
         | 
| 98 | 
            +
             | 
| 99 | 
            +
             | 
| 100 | 
            +
            // ==== EXPLAIN ====
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            // modern response
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            type ExplainResponse = CommonFields;
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            // deprecated response from older versions, backward compatibility
         | 
| 107 | 
            +
             | 
| 108 | 
            +
            type DeprecatedExplainResponse<Action extends ExplainActions> = (
         | 
| 109 | 
            +
                Action extends 'explain-ast'
         | 
| 110 | 
            +
                    ? {ast: AST} & DeprecatedCommonFields
         | 
| 111 | 
            +
                    : Actions extends 'explain'
         | 
| 112 | 
            +
                        ? ({result: Plan} & DeprecatedCommonFields) | Plan
         | 
| 113 | 
            +
                        : unknown
         | 
| 114 | 
            +
            );
         | 
| 115 | 
            +
             | 
| 116 | 
            +
             | 
| 117 | 
            +
            // ==== COMBINED API RESPONSE ====
         | 
| 118 | 
            +
             | 
| 119 | 
            +
            export type QueryAPIExecuteResponse<Schema extends Schemas = undefined> =
         | 
| 120 | 
            +
                | ExecuteResponse<Schema>
         | 
| 121 | 
            +
                | DeprecatedExecuteResponse
         | 
| 122 | 
            +
                | null;
         | 
| 123 | 
            +
             | 
| 124 | 
            +
            export type QueryAPIExplainResponse<Action extends ExplainActions> =
         | 
| 125 | 
            +
                | ExplainResponse
         | 
| 126 | 
            +
                | DeprecatedExplainResponse<Action>
         | 
| 127 | 
            +
                | null;
         | 
| 128 | 
            +
             | 
| 129 | 
            +
            export type QueryAPIResponse<Action extends Actions, Schema extends Schemas = undefined> = (
         | 
| 130 | 
            +
                Action extends ExecuteActions
         | 
| 131 | 
            +
                    ? QueryAPIExecuteResponse<Schema>
         | 
| 132 | 
            +
                    : Action extends ExplainActions
         | 
| 133 | 
            +
                        ? QueryAPIExplainResponse<Action>
         | 
| 134 | 
            +
                        : unknown
         | 
| 135 | 
            +
            );
         | 
| 136 | 
            +
             | 
| 137 | 
            +
            export type AnyExecuteResponse = 
         | 
| 138 | 
            +
                | ExecuteModernResponse
         | 
| 139 | 
            +
                | ExecuteClassicResponse
         | 
| 140 | 
            +
                | ExecuteYdbResponse
         | 
| 141 | 
            +
                | DeprecatedExecuteResponse;
         | 
| 142 | 
            +
             | 
| 143 | 
            +
            export type DeepExecuteResponse =
         | 
| 144 | 
            +
                | ExecuteModernResponse
         | 
| 145 | 
            +
                | ExecuteClassicResponseDeep
         | 
| 146 | 
            +
                | ExecuteYdbResponse
         | 
| 147 | 
            +
                | DeprecatedExecuteResponseDeep;
         |