ydb-embedded-ui 6.0.1 → 6.1.0

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.
Files changed (34) hide show
  1. package/dist/components/CriticalActionDialog/CriticalActionDialog.scss +0 -2
  2. package/dist/containers/PDiskPage/PDiskPage.js +6 -1
  3. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +2 -1
  4. package/dist/containers/Tenant/Query/QueryEditor/helpers.js +4 -3
  5. package/dist/containers/Tenant/Tenant.js +1 -1
  6. package/dist/containers/UserSettings/i18n/en.json +2 -0
  7. package/dist/containers/UserSettings/i18n/index.d.ts +1 -1
  8. package/dist/containers/UserSettings/settings.d.ts +1 -0
  9. package/dist/containers/UserSettings/settings.js +7 -2
  10. package/dist/services/api.d.ts +9 -1
  11. package/dist/services/api.js +5 -0
  12. package/dist/services/settings.js +2 -1
  13. package/dist/types/api/autocomplete.d.ts +21 -0
  14. package/dist/types/api/autocomplete.js +1 -0
  15. package/dist/types/api/restartPDisk.d.ts +4 -0
  16. package/dist/types/api/restartPDisk.js +1 -0
  17. package/dist/utils/constants.d.ts +1 -0
  18. package/dist/utils/constants.js +1 -0
  19. package/dist/utils/monaco/index.js +2 -0
  20. package/dist/utils/monaco/{yqlSuggestions → yql}/constants.d.ts +1 -0
  21. package/dist/utils/monaco/{yqlSuggestions → yql}/constants.js +1 -0
  22. package/dist/utils/monaco/{yqlSuggestions → yql}/generateSuggestions.d.ts +3 -3
  23. package/dist/utils/monaco/{yqlSuggestions → yql}/generateSuggestions.js +124 -64
  24. package/dist/utils/monaco/yql/registerLanguage.d.ts +1 -0
  25. package/dist/utils/monaco/yql/registerLanguage.js +8 -0
  26. package/dist/utils/monaco/{yqlSuggestions/registerCompletionItemProvider.js → yql/yql.completionItemProvider.js} +3 -2
  27. package/dist/utils/monaco/yql/yql.d.ts +7 -0
  28. package/dist/utils/monaco/yql/yql.js +180 -0
  29. package/dist/utils/monaco/yql/yql.keywords.d.ts +3 -0
  30. package/dist/utils/monaco/yql/yql.keywords.js +3 -0
  31. package/dist/utils/monaco/{yqlSuggestions → yql}/yqlSuggestions.js +14 -7
  32. package/package.json +3 -3
  33. /package/dist/utils/monaco/{yqlSuggestions/registerCompletionItemProvider.d.ts → yql/yql.completionItemProvider.d.ts} +0 -0
  34. /package/dist/utils/monaco/{yqlSuggestions → yql}/yqlSuggestions.d.ts +0 -0
@@ -15,7 +15,5 @@
15
15
  &__body {
16
16
  display: flex;
17
17
  align-items: center;
18
-
19
- padding: 16px 16px 0;
20
18
  }
21
19
  }
@@ -46,7 +46,12 @@ export function PDiskPage() {
46
46
  const groupsData = (_a = pDiskStorageQuery.currentData) !== null && _a !== void 0 ? _a : [];
47
47
  const handleRestart = async () => {
48
48
  if (valueIsDefined(nodeId) && valueIsDefined(pDiskId)) {
49
- return window.api.restartPDisk(nodeId, pDiskId);
49
+ return window.api.restartPDisk(nodeId, pDiskId).then((res) => {
50
+ if ((res === null || res === void 0 ? void 0 : res.result) === false) {
51
+ const err = { statusText: res.error };
52
+ throw err;
53
+ }
54
+ });
50
55
  }
51
56
  return undefined;
52
57
  };
@@ -10,6 +10,7 @@ import { setShowPreview } from '../../../../store/reducers/schema/schema';
10
10
  import { cn } from '../../../../utils/cn';
11
11
  import { DEFAULT_IS_QUERY_RESULT_COLLAPSED, DEFAULT_SIZE_RESULT_PANE_KEY, LAST_USED_QUERY_ACTION_KEY, QUERY_USE_MULTI_SCHEMA_KEY, SAVED_QUERIES_KEY, } from '../../../../utils/constants';
12
12
  import { useQueryModes, useSetting } from '../../../../utils/hooks';
13
+ import { LANGUAGE_YQL_ID } from '../../../../utils/monaco/yql/constants';
13
14
  import { QUERY_ACTIONS } from '../../../../utils/query';
14
15
  import { parseJson } from '../../../../utils/utils';
15
16
  import { PaneVisibilityActionTypes, paneVisibilityToggleReducerCreator, } from '../../utils/paneVisibilityToggleHelpers';
@@ -286,7 +287,7 @@ function QueryEditor(props) {
286
287
  };
287
288
  return (_jsx("div", { className: b(), children: _jsxs(SplitPane, { direction: "vertical", defaultSizePaneKey: DEFAULT_SIZE_RESULT_PANE_KEY, triggerCollapse: resultVisibilityState.triggerCollapse, triggerExpand: resultVisibilityState.triggerExpand, minSize: [0, 52], collapsedSizes: [100, 0], onSplitStartDragAdditional: onSplitStartDragAdditional, children: [_jsxs("div", { className: b('pane-wrapper', {
288
289
  top: true,
289
- }), children: [_jsx("div", { className: b('monaco-wrapper'), children: _jsx("div", { className: b('monaco'), children: _jsx(MonacoEditor, { language: "sql", value: executeQuery.input, options: editorOptions, onChange: onChange, editorDidMount: editorDidMount, theme: `vs-${theme}` }) }) }), renderControls()] }), _jsx("div", { className: b('pane-wrapper'), children: _jsx(Result, { executeQuery: executeQuery, explainQuery: explainQuery, resultVisibilityState: resultVisibilityState, onExpandResultHandler: onExpandResultHandler, onCollapseResultHandler: onCollapseResultHandler, type: type, handleAstQuery: handleAstQuery, theme: theme, resultType: resultType, path: path, showPreview: showPreview }) })] }) }));
290
+ }), children: [_jsx("div", { className: b('monaco-wrapper'), children: _jsx("div", { className: b('monaco'), children: _jsx(MonacoEditor, { language: LANGUAGE_YQL_ID, value: executeQuery.input, options: editorOptions, onChange: onChange, editorDidMount: editorDidMount, theme: `vs-${theme}` }) }) }), renderControls()] }), _jsx("div", { className: b('pane-wrapper'), children: _jsx(Result, { executeQuery: executeQuery, explainQuery: explainQuery, resultVisibilityState: resultVisibilityState, onExpandResultHandler: onExpandResultHandler, onCollapseResultHandler: onCollapseResultHandler, type: type, handleAstQuery: handleAstQuery, theme: theme, resultType: resultType, path: path, showPreview: showPreview }) })] }) }));
290
291
  }
291
292
  const mapStateToProps = (state) => {
292
293
  return {
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { ENABLE_AUTOCOMPLETE, useSetting } from '../../../../lib';
2
+ import { AUTOCOMPLETE_ON_ENTER, ENABLE_AUTOCOMPLETE, useSetting } from '../../../../lib';
3
3
  export const EDITOR_OPTIONS = {
4
4
  automaticLayout: true,
5
5
  selectOnLineNumbers: true,
@@ -9,9 +9,10 @@ export const EDITOR_OPTIONS = {
9
9
  };
10
10
  export function useEditorOptions() {
11
11
  const [enableAutocomplete] = useSetting(ENABLE_AUTOCOMPLETE);
12
+ const [autocompleteOnEnter] = useSetting(AUTOCOMPLETE_ON_ENTER);
12
13
  const options = React.useMemo(() => {
13
14
  const useAutocomplete = Boolean(enableAutocomplete);
14
- return Object.assign({ quickSuggestions: useAutocomplete, suggestOnTriggerCharacters: useAutocomplete }, EDITOR_OPTIONS);
15
- }, [enableAutocomplete]);
15
+ return Object.assign({ quickSuggestions: useAutocomplete, suggestOnTriggerCharacters: useAutocomplete, acceptSuggestionOnEnter: autocompleteOnEnter ? 'on' : 'off' }, EDITOR_OPTIONS);
16
+ }, [enableAutocomplete, autocompleteOnEnter]);
16
17
  return options;
17
18
  }
@@ -47,7 +47,7 @@ function Tenant(props) {
47
47
  React.useEffect(() => {
48
48
  if (tenantName && typeof tenantName === 'string' && previousTenant.current !== tenantName) {
49
49
  const register = async () => {
50
- const { registerYQLCompletionItemProvider } = await import('../../utils/monaco/yqlSuggestions/registerCompletionItemProvider');
50
+ const { registerYQLCompletionItemProvider } = await import('../../utils/monaco/yql/yql.completionItemProvider');
51
51
  registerYQLCompletionItemProvider(tenantName);
52
52
  };
53
53
  register().catch(console.error);
@@ -7,6 +7,8 @@
7
7
  "section.dev-setting": "Development settings",
8
8
  "settings.editor.autocomplete.title": "Enable autocomplete",
9
9
  "settings.editor.autocomplete.description": "You’re always able to get suggestions by pressing Ctrl+Space.",
10
+ "settings.editor.autocomplete-on-enter.title": "Accept suggestion on Enter",
11
+ "settings.editor.autocomplete-on-enter.description": "Controls whether suggestions should be accepted on Enter, in addition to Tab. Helps to avoid ambiguity between inserting new lines or accepting suggestions.",
10
12
  "settings.theme.title": "Interface theme",
11
13
  "settings.theme.option-dark": "Dark",
12
14
  "settings.theme.option-light": "Light",
@@ -1,2 +1,2 @@
1
- declare const _default: (key: "page.general" | "section.appearance" | "page.experiments" | "section.experiments" | "page.editor" | "section.dev-setting" | "settings.editor.autocomplete.title" | "settings.editor.autocomplete.description" | "settings.theme.title" | "settings.theme.option-dark" | "settings.theme.option-light" | "settings.theme.option-system" | "settings.language.title" | "settings.language.option-russian" | "settings.language.option-english" | "settings.binaryDataInPlainTextDisplay.title" | "settings.binaryDataInPlainTextDisplay.description" | "settings.invertedDisks.title" | "settings.useNodesEndpoint.title" | "settings.useNodesEndpoint.popover" | "settings.useVirtualTables.title" | "settings.useVirtualTables.popover" | "settings.queryUseMultiSchema.title" | "settings.queryUseMultiSchema.popover", params?: import("@gravity-ui/i18n").Params | undefined) => string;
1
+ declare const _default: (key: "page.general" | "section.appearance" | "page.experiments" | "section.experiments" | "page.editor" | "section.dev-setting" | "settings.editor.autocomplete.title" | "settings.editor.autocomplete.description" | "settings.editor.autocomplete-on-enter.title" | "settings.editor.autocomplete-on-enter.description" | "settings.theme.title" | "settings.theme.option-dark" | "settings.theme.option-light" | "settings.theme.option-system" | "settings.language.title" | "settings.language.option-russian" | "settings.language.option-english" | "settings.binaryDataInPlainTextDisplay.title" | "settings.binaryDataInPlainTextDisplay.description" | "settings.invertedDisks.title" | "settings.useNodesEndpoint.title" | "settings.useNodesEndpoint.popover" | "settings.useVirtualTables.title" | "settings.useVirtualTables.popover" | "settings.queryUseMultiSchema.title" | "settings.queryUseMultiSchema.popover", params?: import("@gravity-ui/i18n").Params | undefined) => string;
2
2
  export default _default;
@@ -20,6 +20,7 @@ export declare const useNodesEndpointSetting: SettingProps;
20
20
  export declare const useVirtualTables: SettingProps;
21
21
  export declare const queryUseMultiSchemaSetting: SettingProps;
22
22
  export declare const enableAutocompleteSetting: SettingProps;
23
+ export declare const autocompleteOnEnterSetting: SettingProps;
23
24
  export declare const appearanceSection: SettingsSection;
24
25
  export declare const experimentsSection: SettingsSection;
25
26
  export declare const devSettingsSection: SettingsSection;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Flask, PencilToSquare, StarFill } from '@gravity-ui/icons';
3
- import { BINARY_DATA_IN_PLAIN_TEXT_DISPLAY, ENABLE_AUTOCOMPLETE, INVERTED_DISKS_KEY, LANGUAGE_KEY, QUERY_USE_MULTI_SCHEMA_KEY, THEME_KEY, USE_BACKEND_PARAMS_FOR_TABLES_KEY, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, } from '../../utils/constants';
3
+ import { AUTOCOMPLETE_ON_ENTER, BINARY_DATA_IN_PLAIN_TEXT_DISPLAY, ENABLE_AUTOCOMPLETE, INVERTED_DISKS_KEY, LANGUAGE_KEY, QUERY_USE_MULTI_SCHEMA_KEY, THEME_KEY, USE_BACKEND_PARAMS_FOR_TABLES_KEY, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, } from '../../utils/constants';
4
4
  import { Lang, defaultLang } from '../../utils/i18n';
5
5
  import { ClusterModeGuard } from '../ClusterModeGuard';
6
6
  import i18n from './i18n';
@@ -73,6 +73,11 @@ export const enableAutocompleteSetting = {
73
73
  title: i18n('settings.editor.autocomplete.title'),
74
74
  description: i18n('settings.editor.autocomplete.description'),
75
75
  };
76
+ export const autocompleteOnEnterSetting = {
77
+ settingKey: AUTOCOMPLETE_ON_ENTER,
78
+ title: i18n('settings.editor.autocomplete-on-enter.title'),
79
+ description: i18n('settings.editor.autocomplete-on-enter.description'),
80
+ };
76
81
  export const appearanceSection = {
77
82
  id: 'appearanceSection',
78
83
  title: i18n('section.appearance'),
@@ -86,7 +91,7 @@ export const experimentsSection = {
86
91
  export const devSettingsSection = {
87
92
  id: 'devSettingsSection',
88
93
  title: i18n('section.dev-setting'),
89
- settings: [enableAutocompleteSetting],
94
+ settings: [enableAutocompleteSetting, autocompleteOnEnterSetting],
90
95
  };
91
96
  export const generalPage = {
92
97
  id: 'generalPage',
@@ -2,6 +2,7 @@ import AxiosWrapper from '@gravity-ui/axios-wrapper';
2
2
  import type { ComputeApiRequestParams, NodesApiRequestParams } from '../store/reducers/nodes/types';
3
3
  import type { StorageApiRequestParams } from '../store/reducers/storage/types';
4
4
  import type { TMetaInfo } from '../types/api/acl';
5
+ import type { TQueryAutocomplete } from '../types/api/autocomplete';
5
6
  import type { TClusterInfo } from '../types/api/cluster';
6
7
  import type { TComputeInfo } from '../types/api/compute';
7
8
  import type { DescribeConsumerResult } from '../types/api/consumer';
@@ -14,6 +15,7 @@ import type { TEvNodesInfo } from '../types/api/nodesList';
14
15
  import type { TEvPDiskStateResponse } from '../types/api/pdisk';
15
16
  import type { Actions, ExplainActions, ExplainResponse, QueryAPIResponse, Schemas } from '../types/api/query';
16
17
  import type { JsonRenderRequestParams, JsonRenderResponse } from '../types/api/render';
18
+ import type { RestartPDiskResponse } from '../types/api/restartPDisk';
17
19
  import type { TEvDescribeSchemeResult } from '../types/api/schema';
18
20
  import type { TStorageInfo } from '../types/api/storage';
19
21
  import type { TEvSystemStateResponse } from '../types/api/systemState';
@@ -104,7 +106,7 @@ export declare class YdbEmbeddedAPI extends AxiosWrapper {
104
106
  failDomainIdx: string | number;
105
107
  vDiskIdx: string | number;
106
108
  }): Promise<any>;
107
- restartPDisk(nodeId: number | string, pDiskId: number | string): Promise<any>;
109
+ restartPDisk(nodeId: number | string, pDiskId: number | string): Promise<RestartPDiskResponse>;
108
110
  killTablet(id?: string): Promise<string>;
109
111
  stopTablet(id?: string, hiveId?: string): Promise<string>;
110
112
  resumeTablet(id?: string, hiveId?: string): Promise<string>;
@@ -115,6 +117,12 @@ export declare class YdbEmbeddedAPI extends AxiosWrapper {
115
117
  authenticate(user: string, password: string): Promise<any>;
116
118
  logout(): Promise<any>;
117
119
  whoami(): Promise<TUserToken>;
120
+ autocomplete(params: {
121
+ database: string;
122
+ prefix?: string;
123
+ limit?: number;
124
+ table?: string[];
125
+ }): Promise<TQueryAutocomplete>;
118
126
  getClustersList(_?: never, { signal }?: {
119
127
  signal?: AbortSignal;
120
128
  }): Promise<MetaClusters>;
@@ -302,6 +302,11 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
302
302
  whoami() {
303
303
  return this.get(this.getPath('/viewer/json/whoami'), {});
304
304
  }
305
+ autocomplete(params) {
306
+ const { table } = params, rest = __rest(params, ["table"]);
307
+ const tablesParam = table === null || table === void 0 ? void 0 : table.join(',');
308
+ return this.get(this.getPath('/viewer/json/autocomplete'), Object.assign(Object.assign({}, rest), { table: tablesParam }), { concurrentId: 'sql-autocomplete' });
309
+ }
305
310
  // used if not single cluster mode
306
311
  getClustersList(_, { signal } = {}) {
307
312
  return this.get(`${META_BACKEND || ''}/meta/clusters`, null, {
@@ -1,5 +1,5 @@
1
1
  import { TENANT_PAGES_IDS } from '../store/reducers/tenant/constants';
2
- import { ASIDE_HEADER_COMPACT_KEY, BINARY_DATA_IN_PLAIN_TEXT_DISPLAY, ENABLE_AUTOCOMPLETE, INVERTED_DISKS_KEY, LANGUAGE_KEY, LAST_USED_QUERY_ACTION_KEY, PARTITIONS_HIDDEN_COLUMNS_KEY, QUERY_INITIAL_MODE_KEY, QUERY_USE_MULTI_SCHEMA_KEY, SAVED_QUERIES_KEY, TENANT_INITIAL_PAGE_KEY, THEME_KEY, USE_BACKEND_PARAMS_FOR_TABLES_KEY, USE_CLUSTER_BALANCER_AS_BACKEND_KEY, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, } from '../utils/constants';
2
+ import { ASIDE_HEADER_COMPACT_KEY, AUTOCOMPLETE_ON_ENTER, BINARY_DATA_IN_PLAIN_TEXT_DISPLAY, ENABLE_AUTOCOMPLETE, INVERTED_DISKS_KEY, LANGUAGE_KEY, LAST_USED_QUERY_ACTION_KEY, PARTITIONS_HIDDEN_COLUMNS_KEY, QUERY_INITIAL_MODE_KEY, QUERY_USE_MULTI_SCHEMA_KEY, SAVED_QUERIES_KEY, TENANT_INITIAL_PAGE_KEY, THEME_KEY, USE_BACKEND_PARAMS_FOR_TABLES_KEY, USE_CLUSTER_BALANCER_AS_BACKEND_KEY, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, } from '../utils/constants';
3
3
  import { QUERY_ACTIONS, QUERY_MODES } from '../utils/query';
4
4
  import { parseJson } from '../utils/utils';
5
5
  /** User settings keys and their default values */
@@ -19,6 +19,7 @@ export const DEFAULT_USER_SETTINGS = {
19
19
  [USE_BACKEND_PARAMS_FOR_TABLES_KEY]: false,
20
20
  [USE_CLUSTER_BALANCER_AS_BACKEND_KEY]: true,
21
21
  [ENABLE_AUTOCOMPLETE]: false,
22
+ [AUTOCOMPLETE_ON_ENTER]: true,
22
23
  };
23
24
  class SettingsManager {
24
25
  constructor() {
@@ -0,0 +1,21 @@
1
+ /**
2
+ * endpoint: /viewer/json/autocomplete
3
+ *
4
+ * source: https://github.com/ydb-platform/ydb/blob/main/ydb/core/viewer/protos/viewer.proto
5
+ */
6
+ export interface TQueryAutocomplete {
7
+ Success: boolean;
8
+ Error?: string[];
9
+ Result: TAutocompleteResult;
10
+ }
11
+ interface TAutocompleteResult {
12
+ Entities: TAutocompleteEntity[];
13
+ Total?: number;
14
+ }
15
+ export interface TAutocompleteEntity {
16
+ Name: string;
17
+ Type: AutocompleteEntityType;
18
+ Parent: string;
19
+ }
20
+ export type AutocompleteEntityType = 'unknown' | 'dir' | 'table' | 'pers_queue_group' | 'sub_domain' | 'rtmr_volume' | 'block_store_volume' | 'kesus' | 'solomon_volume' | 'table_index' | 'ext_sub_domain' | 'file_store' | 'column_store' | 'column_table' | 'cdc_stream' | 'sequence' | 'replication' | 'blob_depot' | 'external_table' | 'external_data_source' | 'view' | 'column' | 'index';
21
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ export interface RestartPDiskResponse {
2
+ result?: boolean;
3
+ error?: string;
4
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -88,3 +88,4 @@ export declare const USE_BACKEND_PARAMS_FOR_TABLES_KEY = "useBackendParamsForTab
88
88
  export declare const QUERY_USE_MULTI_SCHEMA_KEY = "queryUseMultiSchema";
89
89
  export declare const USE_CLUSTER_BALANCER_AS_BACKEND_KEY = "useClusterBalancerAsBacked";
90
90
  export declare const ENABLE_AUTOCOMPLETE = "enableAutocomplete";
91
+ export declare const AUTOCOMPLETE_ON_ENTER = "autocompleteOnEnter";
@@ -101,3 +101,4 @@ export const USE_BACKEND_PARAMS_FOR_TABLES_KEY = 'useBackendParamsForTables';
101
101
  export const QUERY_USE_MULTI_SCHEMA_KEY = 'queryUseMultiSchema';
102
102
  export const USE_CLUSTER_BALANCER_AS_BACKEND_KEY = 'useClusterBalancerAsBacked';
103
103
  export const ENABLE_AUTOCOMPLETE = 'enableAutocomplete';
104
+ export const AUTOCOMPLETE_ON_ENTER = 'autocompleteOnEnter';
@@ -1,4 +1,6 @@
1
1
  import { registerSExpressionLanguage } from './s-expression/registerLanguage';
2
+ import { registerYqlLanguage } from './yql/registerLanguage';
2
3
  export function registerLanguages() {
3
4
  registerSExpressionLanguage();
5
+ registerYqlLanguage();
4
6
  }
@@ -1,3 +1,4 @@
1
+ export declare const LANGUAGE_YQL_ID = "yql";
1
2
  export declare const SimpleTypes: string[];
2
3
  export declare const SimpleFunctions: string[];
3
4
  export declare const AggregateFunctions: string[];
@@ -1,3 +1,4 @@
1
+ export const LANGUAGE_YQL_ID = 'yql';
1
2
  export const SimpleTypes = [
2
3
  'String',
3
4
  'Bool',
@@ -1,5 +1,5 @@
1
- import type { ColumnAliasSuggestion, KeywordSuggestion, YqlAutocompleteResult } from '@gravity-ui/websql-autocomplete';
2
- import type * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
1
+ import type { ColumnAliasSuggestion, KeywordSuggestion, YQLEntity, YqlAutocompleteResult } from '@gravity-ui/websql-autocomplete';
2
+ import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
3
3
  export declare function generateColumnsSuggestion(rangeToInsertSuggestion: monaco.IRange, suggestColumns: YqlAutocompleteResult['suggestColumns'] | undefined, database: string): Promise<monaco.languages.CompletionItem[]>;
4
4
  export declare function generateColumnAliasesSuggestion(rangeToInsertSuggestion: monaco.IRange, suggestColumnAliases?: ColumnAliasSuggestion[]): {
5
5
  label: string;
@@ -17,7 +17,7 @@ export declare function generateKeywordsSuggestion(rangeToInsertSuggestion: mona
17
17
  range: monaco.IRange;
18
18
  sortText: string;
19
19
  }[];
20
- export declare function generateEntitiesSuggestion(_rangeToInsertSuggestion: monaco.IRange): Promise<monaco.languages.CompletionItem[]>;
20
+ export declare function generateEntitiesSuggestion(rangeToInsertSuggestion: monaco.IRange, suggestEntities: YQLEntity[], database: string, prefix?: string): Promise<monaco.languages.CompletionItem[]>;
21
21
  export declare function generateSimpleFunctionsSuggestion(rangeToInsertSuggestion: monaco.IRange): Promise<monaco.languages.CompletionItem[]>;
22
22
  export declare function generateSimpleTypesSuggestion(rangeToInsertSuggestion: monaco.IRange): Promise<monaco.languages.CompletionItem[]>;
23
23
  export declare function generateUdfSuggestion(rangeToInsertSuggestion: monaco.IRange): Promise<monaco.languages.CompletionItem[]>;
@@ -1,3 +1,4 @@
1
+ import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
1
2
  import { AggregateFunctions, Pragmas, SimpleFunctions, SimpleTypes, TableFunction, Udfs, WindowFunctions, } from './constants';
2
3
  const CompletionItemKind = {
3
4
  Method: 0,
@@ -30,6 +31,27 @@ const CompletionItemKind = {
30
31
  Snippet: 27,
31
32
  };
32
33
  const re = /[\s'"-/@]/;
34
+ const suggestionEntityToAutocomplete = {
35
+ externalDataSource: ['external_data_source'],
36
+ replication: ['replication'],
37
+ table: ['table'],
38
+ tableStore: ['column_store'],
39
+ topic: ['pers_queue_group'],
40
+ view: ['view'],
41
+ //TODO: add after websql-autocomplete support indexex
42
+ // index: ['table_index', 'index'],
43
+ };
44
+ const commonSuggestionEntities = ['dir', 'unknown'];
45
+ function filterAutocompleteEntities(autocompleteEntities, suggestions) {
46
+ const suggestionsSet = suggestions.reduce((acc, el) => {
47
+ const autocompleteEntity = suggestionEntityToAutocomplete[el];
48
+ if (autocompleteEntity) {
49
+ autocompleteEntity.forEach((el) => acc.add(el));
50
+ }
51
+ return acc;
52
+ }, new Set(commonSuggestionEntities));
53
+ return autocompleteEntities.filter(({ Type }) => suggestionsSet.has(Type));
54
+ }
33
55
  function wrapStringToBackticks(value) {
34
56
  let result = value;
35
57
  if (value.match(re)) {
@@ -38,11 +60,29 @@ function wrapStringToBackticks(value) {
38
60
  return result;
39
61
  }
40
62
  function removeBackticks(value) {
41
- let normalizedValue = value;
63
+ let sliceStart = 0;
64
+ let sliceEnd = value.length;
42
65
  if (value.startsWith('`')) {
43
- normalizedValue = value.slice(1, -1);
66
+ sliceStart = 1;
67
+ }
68
+ if (value.endsWith('`')) {
69
+ sliceEnd = -1;
70
+ }
71
+ return value.slice(sliceStart, sliceEnd);
72
+ }
73
+ function removeStartSlash(value) {
74
+ if (value.startsWith('/')) {
75
+ return value.slice(1);
76
+ }
77
+ return value;
78
+ }
79
+ function normalizeEntityPrefix(value = '', database) {
80
+ let cleanedValue = removeStartSlash(removeBackticks(value));
81
+ const cleanedDatabase = removeStartSlash(database);
82
+ if (cleanedValue.startsWith(cleanedDatabase)) {
83
+ cleanedValue = cleanedValue.slice(cleanedDatabase.length);
44
84
  }
45
- return normalizedValue;
85
+ return removeStartSlash(cleanedValue);
46
86
  }
47
87
  const SuggestionsWeight = {
48
88
  suggestTemplates: 0,
@@ -58,50 +98,6 @@ const SuggestionsWeight = {
58
98
  suggestUdfs: 10,
59
99
  suggestSimpleTypes: 11,
60
100
  };
61
- const KEEP_CACHE_MILLIS = 5 * 60 * 1000;
62
- function getColumnsWithCache() {
63
- const cache = new Map();
64
- return async (path) => {
65
- var _a, _b, _c, _d;
66
- const normalizedPath = removeBackticks(path);
67
- const existed = cache.get(path);
68
- if (existed) {
69
- return existed;
70
- }
71
- const columns = [];
72
- const data = await window.api.getDescribe({ path: normalizedPath });
73
- if ((data === null || data === void 0 ? void 0 : data.Status) === 'StatusSuccess') {
74
- const desc = data.PathDescription;
75
- if ((_a = desc === null || desc === void 0 ? void 0 : desc.Table) === null || _a === void 0 ? void 0 : _a.Columns) {
76
- for (const c of desc.Table.Columns) {
77
- if (c.Name) {
78
- columns.push(c.Name);
79
- }
80
- }
81
- }
82
- if ((_c = (_b = desc === null || desc === void 0 ? void 0 : desc.ColumnTableDescription) === null || _b === void 0 ? void 0 : _b.Schema) === null || _c === void 0 ? void 0 : _c.Columns) {
83
- for (const c of desc.ColumnTableDescription.Schema.Columns) {
84
- if (c.Name) {
85
- columns.push(c.Name);
86
- }
87
- }
88
- }
89
- if ((_d = desc === null || desc === void 0 ? void 0 : desc.ExternalTableDescription) === null || _d === void 0 ? void 0 : _d.Columns) {
90
- for (const c of desc.ExternalTableDescription.Columns) {
91
- if (c.Name) {
92
- columns.push(c.Name);
93
- }
94
- }
95
- }
96
- }
97
- cache.set(path, columns);
98
- setTimeout(() => {
99
- cache.delete(path);
100
- }, KEEP_CACHE_MILLIS);
101
- return columns;
102
- };
103
- }
104
- const getColumns = getColumnsWithCache();
105
101
  function getSuggestionIndex(suggestionType) {
106
102
  return SuggestionsWeight[suggestionType];
107
103
  }
@@ -127,28 +123,63 @@ async function getSimpleTypes() {
127
123
  return SimpleTypes;
128
124
  }
129
125
  export async function generateColumnsSuggestion(rangeToInsertSuggestion, suggestColumns, database) {
130
- var _a;
126
+ var _a, _b, _c;
131
127
  if (!(suggestColumns === null || suggestColumns === void 0 ? void 0 : suggestColumns.tables)) {
132
128
  return [];
133
129
  }
134
130
  const suggestions = [];
135
131
  const multi = suggestColumns.tables.length > 1;
136
- for (const entity of (_a = suggestColumns.tables) !== null && _a !== void 0 ? _a : []) {
132
+ const normalizedTableNames = (_b = (_a = suggestColumns.tables) === null || _a === void 0 ? void 0 : _a.map((entity) => {
137
133
  let normalizedEntityName = removeBackticks(entity.name);
138
- // if it's relative entity path
139
- if (!normalizedEntityName.startsWith('/')) {
140
- normalizedEntityName = `${database}/${normalizedEntityName}`;
134
+ if (!normalizedEntityName.endsWith('/')) {
135
+ normalizedEntityName = `${normalizedEntityName}/`;
141
136
  }
142
- const fields = await getColumns(normalizedEntityName);
143
- fields.forEach((columnName) => {
144
- const normalizedName = wrapStringToBackticks(columnName);
137
+ return normalizeEntityPrefix(normalizedEntityName, database);
138
+ })) !== null && _b !== void 0 ? _b : [];
139
+ // remove duplicates if any
140
+ const filteredTableNames = Array.from(new Set(normalizedTableNames));
141
+ const autocompleteResponse = await window.api.autocomplete({
142
+ database,
143
+ table: filteredTableNames,
144
+ limit: 1000,
145
+ });
146
+ if (!autocompleteResponse.Success) {
147
+ return [];
148
+ }
149
+ const tableNameToAliasMap = (_c = suggestColumns.tables) === null || _c === void 0 ? void 0 : _c.reduce((acc, entity) => {
150
+ var _a;
151
+ const normalizedEntityName = normalizeEntityPrefix(removeBackticks(entity.name), database);
152
+ const aliases = (_a = acc[normalizedEntityName]) !== null && _a !== void 0 ? _a : [];
153
+ if (entity.alias) {
154
+ aliases.push(entity.alias);
155
+ }
156
+ acc[normalizedEntityName] = aliases;
157
+ return acc;
158
+ }, {});
159
+ autocompleteResponse.Result.Entities.forEach((col) => {
160
+ if (col.Type !== 'column') {
161
+ return;
162
+ }
163
+ const normalizedName = wrapStringToBackticks(col.Name);
164
+ const normalizedParentName = normalizeEntityPrefix(col.Parent, database);
165
+ const aliases = tableNameToAliasMap[normalizedParentName];
166
+ if (aliases === null || aliases === void 0 ? void 0 : aliases.length) {
167
+ aliases.forEach((a) => {
168
+ const columnNameSuggestion = `${a}.${normalizedName}`;
169
+ suggestions.push({
170
+ label: columnNameSuggestion,
171
+ insertText: columnNameSuggestion,
172
+ kind: CompletionItemKind.Field,
173
+ detail: 'Column',
174
+ range: rangeToInsertSuggestion,
175
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestColumns')),
176
+ });
177
+ });
178
+ }
179
+ else {
145
180
  let columnNameSuggestion = normalizedName;
146
- if (entity.alias) {
147
- columnNameSuggestion = `${entity.alias}.${normalizedName}`;
148
- }
149
- else if (multi) {
150
- // no need to wrap entity.name to backticks, because it's already with them if needed
151
- columnNameSuggestion = `${entity.name}.${normalizedName}`;
181
+ if (multi) {
182
+ columnNameSuggestion = `${wrapStringToBackticks(normalizedParentName)}.${normalizedName}`;
152
183
  }
153
184
  suggestions.push({
154
185
  label: columnNameSuggestion,
@@ -158,8 +189,8 @@ export async function generateColumnsSuggestion(rangeToInsertSuggestion, suggest
158
189
  range: rangeToInsertSuggestion,
159
190
  sortText: suggestionIndexToWeight(getSuggestionIndex('suggestColumns')),
160
191
  });
161
- });
162
- }
192
+ }
193
+ });
163
194
  return suggestions;
164
195
  }
165
196
  export function generateColumnAliasesSuggestion(rangeToInsertSuggestion, suggestColumnAliases) {
@@ -188,7 +219,36 @@ export function generateKeywordsSuggestion(rangeToInsertSuggestion, suggestKeywo
188
219
  sortText: suggestionIndexToWeight(getSuggestionIndex('suggestKeywords')),
189
220
  }));
190
221
  }
191
- export async function generateEntitiesSuggestion(_rangeToInsertSuggestion) {
222
+ export async function generateEntitiesSuggestion(rangeToInsertSuggestion, suggestEntities, database, prefix) {
223
+ const normalizedPrefix = normalizeEntityPrefix(prefix, database);
224
+ const data = await window.api.autocomplete({ database, prefix: normalizedPrefix, limit: 1000 });
225
+ const withBackticks = prefix === null || prefix === void 0 ? void 0 : prefix.startsWith('`');
226
+ if (data.Success) {
227
+ const filteredEntities = filterAutocompleteEntities(data.Result.Entities, suggestEntities);
228
+ return filteredEntities.reduce((acc, { Name, Type }) => {
229
+ const isDir = Type === 'dir';
230
+ const label = isDir ? `${Name}/` : Name;
231
+ let labelAsSnippet;
232
+ if (isDir && !withBackticks) {
233
+ labelAsSnippet = `\`${label}$0\``;
234
+ }
235
+ acc.push({
236
+ label,
237
+ insertText: labelAsSnippet !== null && labelAsSnippet !== void 0 ? labelAsSnippet : label,
238
+ kind: isDir ? CompletionItemKind.Folder : CompletionItemKind.Text,
239
+ insertTextRules: labelAsSnippet
240
+ ? monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
241
+ : monaco.languages.CompletionItemInsertTextRule.None,
242
+ detail: Type,
243
+ range: rangeToInsertSuggestion,
244
+ command: label.endsWith('/')
245
+ ? { id: 'editor.action.triggerSuggest', title: '' }
246
+ : undefined,
247
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestEntity')),
248
+ });
249
+ return acc;
250
+ }, []);
251
+ }
192
252
  return [];
193
253
  }
194
254
  export async function generateSimpleFunctionsSuggestion(rangeToInsertSuggestion) {
@@ -0,0 +1 @@
1
+ export declare function registerYqlLanguage(): void;
@@ -0,0 +1,8 @@
1
+ import * as monaco from 'monaco-editor';
2
+ import { LANGUAGE_YQL_ID } from './constants';
3
+ import { conf, getLanguage } from './yql';
4
+ export function registerYqlLanguage() {
5
+ monaco.languages.register({ id: LANGUAGE_YQL_ID });
6
+ monaco.languages.setMonarchTokensProvider(LANGUAGE_YQL_ID, getLanguage());
7
+ monaco.languages.setLanguageConfiguration(LANGUAGE_YQL_ID, conf);
8
+ }
@@ -1,4 +1,5 @@
1
1
  import * as monaco from 'monaco-editor';
2
+ import { LANGUAGE_YQL_ID } from './constants';
2
3
  import { createProvideSuggestionsFunction } from './yqlSuggestions';
3
4
  let completionProvider;
4
5
  function disableCodeSuggestions() {
@@ -8,8 +9,8 @@ function disableCodeSuggestions() {
8
9
  }
9
10
  export function registerYQLCompletionItemProvider(database) {
10
11
  disableCodeSuggestions();
11
- completionProvider = monaco.languages.registerCompletionItemProvider('sql', {
12
- triggerCharacters: [' ', '\n', '', ',', '.', '`', '('],
12
+ completionProvider = monaco.languages.registerCompletionItemProvider(LANGUAGE_YQL_ID, {
13
+ triggerCharacters: [' ', '', ',', '.', '`', '(', '/'],
13
14
  provideCompletionItems: createProvideSuggestionsFunction(database),
14
15
  });
15
16
  }
@@ -0,0 +1,7 @@
1
+ import type * as monaco from 'monaco-editor';
2
+ export declare const conf: monaco.languages.LanguageConfiguration;
3
+ interface LanguageOptions {
4
+ ansi?: boolean;
5
+ }
6
+ export declare function getLanguage({ ansi, }?: LanguageOptions): monaco.languages.IMonarchLanguage & Record<string, unknown>;
7
+ export {};
@@ -0,0 +1,180 @@
1
+ import { builtinFunctions, keywords, typeKeywords } from './yql.keywords';
2
+ export const conf = {
3
+ comments: {
4
+ lineComment: '--',
5
+ blockComment: ['/*', '*/'],
6
+ },
7
+ brackets: [
8
+ ['{', '}'],
9
+ ['[', ']'],
10
+ ['(', ')'],
11
+ ],
12
+ autoClosingPairs: [
13
+ { open: '{', close: '}' },
14
+ { open: '[', close: ']' },
15
+ { open: '(', close: ')' },
16
+ { open: '"', close: '"' },
17
+ { open: "'", close: "'" },
18
+ { open: '`', close: '`' },
19
+ ],
20
+ surroundingPairs: [
21
+ { open: '{', close: '}' },
22
+ { open: '[', close: ']' },
23
+ { open: '(', close: ')' },
24
+ { open: '"', close: '"' },
25
+ { open: "'", close: "'" },
26
+ { open: '`', close: '`' },
27
+ ],
28
+ wordPattern: /(-?\d*\.\d\w*)|([^`~!@#%^&*()\-=+[{\]}\\|;:'",./?\s]+)/g,
29
+ };
30
+ export function getLanguage({ ansi = false, } = {}) {
31
+ return {
32
+ defaultToken: 'text',
33
+ ignoreCase: true,
34
+ brackets: [
35
+ { open: '[', close: ']', token: 'delimiter.square' },
36
+ { open: '(', close: ')', token: 'delimiter.parenthesis' },
37
+ { open: '{', close: '}', token: 'delimiter.curly' },
38
+ ],
39
+ keywords,
40
+ typeKeywords,
41
+ constants: ['true', 'false'],
42
+ builtinFunctions,
43
+ operators: [
44
+ '+',
45
+ '-',
46
+ '/',
47
+ '//',
48
+ '%',
49
+ '<@>',
50
+ '@>',
51
+ '<@',
52
+ '&',
53
+ '^',
54
+ '~',
55
+ '<',
56
+ '>',
57
+ '<=',
58
+ '>=',
59
+ '=>',
60
+ '==',
61
+ '!=',
62
+ '<>',
63
+ '=',
64
+ ],
65
+ symbols: /[=><!~?:&|+\-*/^%]+/,
66
+ escapes: /\\(?:[abfnrtv\\"'`]|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
67
+ variables: /[a-zA-Z_]\w*/,
68
+ tokenizer: {
69
+ root: [
70
+ { include: '@whitespace' },
71
+ { include: '@comments' },
72
+ { include: '@numbers' },
73
+ { include: '@tablePath' },
74
+ { include: '@strings' },
75
+ // support function
76
+ [/(@variables)::(@variables)/, 'support.function'],
77
+ [/[;,.]/, 'delimiter'],
78
+ [/[(){}[\]]/, '@brackets'],
79
+ // identifiers and keywords
80
+ [
81
+ /@?[a-zA-Z_$]\w*/,
82
+ {
83
+ cases: {
84
+ '@keywords': 'keyword',
85
+ '@typeKeywords': 'keyword.type',
86
+ '@constants': 'constant.yql',
87
+ '@builtinFunctions': 'constant.other.color',
88
+ '[$@][a-zA-Z_]\\w*': 'variable',
89
+ '@default': 'identifier',
90
+ },
91
+ },
92
+ ],
93
+ [
94
+ /@symbols/,
95
+ {
96
+ cases: {
97
+ '@operators': 'operator.sql',
98
+ '@default': '',
99
+ },
100
+ },
101
+ ],
102
+ ],
103
+ whitespace: [[/\s+/, 'white']],
104
+ comments: [
105
+ [/--.*/, 'comment'],
106
+ [/\/\*/, { token: 'comment.quote', next: ansi ? '@commentAnsi' : '@comment' }],
107
+ ],
108
+ comment: [
109
+ [/[^*/]+/, 'comment'],
110
+ [/\*\//, { token: 'comment.quote', next: '@pop' }],
111
+ [/./, 'comment'],
112
+ ],
113
+ commentAnsi: [
114
+ [/\/\*/, { token: 'comment.quote', next: '@comment' }],
115
+ [/[^*/]+/, 'comment'],
116
+ [/\*\//, { token: 'comment.quote', next: '@pop' }],
117
+ [/./, 'comment'],
118
+ ],
119
+ numbers: [
120
+ [/[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?f?\b/, 'number.float'],
121
+ [/[+-]?(?:\d+|0b[01]+|0o[0-8]+|0x[\da-f]+)(?:u?[lst]?)?\b/, 'number'],
122
+ ],
123
+ strings: [
124
+ [/'/, { token: 'string', next: ansi ? '@stringAnsiSingle' : '@stringSingle' }],
125
+ [/"/, { token: 'string', next: ansi ? '@stringAnsiDouble' : '@stringDouble' }],
126
+ [/[@]{2}/, { token: 'string', next: '@multilineString' }],
127
+ ],
128
+ stringSingle: [
129
+ [/[^\\']+/, 'string'],
130
+ [/@escapes/, 'string.escape'],
131
+ [/\\./, 'string.escape.invalid'],
132
+ [/'[uyj]?/, { token: 'string', next: '@pop' }],
133
+ ],
134
+ stringAnsiSingle: [
135
+ [/[^']+/, 'string'],
136
+ [/''/, 'string'],
137
+ [/'[uyj]?/, { token: 'string', next: '@pop' }],
138
+ ],
139
+ stringDouble: [
140
+ [/[^\\"]+/, 'string'],
141
+ [/@escapes/, 'string.escape'],
142
+ [/\\./, 'string.escape.invalid'],
143
+ [/"[uyj]?/, { token: 'string', next: '@pop' }],
144
+ ],
145
+ stringAnsiDouble: [
146
+ [/[^"]+/, 'string'],
147
+ [/""/, 'string'],
148
+ [/"[uyj]?/, { token: 'string', next: '@pop' }],
149
+ ],
150
+ multilineString: [
151
+ [
152
+ /#py/,
153
+ { token: 'string.python', nextEmbedded: 'python', next: '@embedded', goBack: 3 },
154
+ ],
155
+ [
156
+ /\/\/js/,
157
+ { token: 'string.js', nextEmbedded: 'javascript', next: '@embedded', goBack: 4 },
158
+ ],
159
+ [/[^@]+/, 'string'],
160
+ [/[@]{4}/, 'string'],
161
+ [/[@]{2}[uyj]?/, { token: 'string', next: '@pop' }],
162
+ [/./, 'string'],
163
+ ],
164
+ embedded: [
165
+ [
166
+ /([^@]|^)([@]{4})*[@]{2}([@]([^@]|$)|[^@]|$)/,
167
+ { token: '@rematch', next: '@pop', nextEmbedded: '@pop' },
168
+ ],
169
+ ],
170
+ tablePath: [[/((`)?[\w/]+\2\s*\.\s*)?`/, { token: 'string.tablepath', next: '@table' }]],
171
+ table: [
172
+ [/[^\\`]+/, 'string.tablepath'],
173
+ [/``/, 'string.tablepath'],
174
+ [/@escapes/, 'string.escape.tablepath'],
175
+ [/\\./, 'string.escape.invalid.tablepath'],
176
+ [/`/, { token: 'string.tablepath', next: '@pop' }],
177
+ ],
178
+ },
179
+ };
180
+ }
@@ -0,0 +1,3 @@
1
+ export declare const keywords: string[];
2
+ export declare const typeKeywords: string[];
3
+ export declare const builtinFunctions: string[];
@@ -0,0 +1,3 @@
1
+ export const keywords = '$row|$rows|action|all|and|any|as|asc|assume|begin|bernoulli|between|by|case|columns|commit|compact|create|cross|cube|declare|define|delete|desc|dict|discard|distinct|do|drop|else|empty_action|end|erase|evaluate|exclusion|exists|export|flatten|for|from|full|group|grouping|having|if|ignore|ilike|import|in|inner|insert|into|is|join|left|like|limit|list|match|not|null|nulls|offset|on|only|optional|or|order|over|partition|pragma|presort|process|reduce|regexp|repeatable|replace|respect|result|return|right|rlike|rollup|sample|schema|select|semi|set|sets|stream|subquery|table|tablesample|then|truncate|union|update|upsert|use|using|values|view|when|where|window|with|without|xor'.split('|');
2
+ export const typeKeywords = 'bool|date|datetime|decimal|double|float|int16|int32|int64|int8|interval|json|string|timestamp|tzdate|tzdatetime|tztimestamp|uint16|uint32|uint64|uint8|utf8|uuid|yson'.split('|');
3
+ export const builtinFunctions = 'abs|aggregate_by|aggregate_list|aggregate_list_distinct|agg_list|agg_list_distinct|as_table|avg|avg_if|adaptivedistancehistogram|adaptivewardhistogram|adaptiveweighthistogram|addmember|addtimezone|aggregateflatten|aggregatetransforminput|aggregatetransformoutput|aggregationfactory|asatom|asdict|asdictstrict|asenum|aslist|asliststrict|asset|assetstrict|asstruct|astagged|astuple|asvariant|atomcode|bitcast|bit_and|bit_or|bit_xor|bool_and|bool_or|bool_xor|bottom|bottom_by|blockwardhistogram|blockweighthistogram|cast|coalesce|concat|concat_strict|correlation|count|count_if|covariance|covariance_population|covariance_sample|callableargument|callableargumenttype|callableresulttype|callabletype|callabletypecomponents|callabletypehandle|choosemembers|combinemembers|countdistinctestimate|currentauthenticateduser|currentoperationid|currentoperationsharedid|currenttzdate|currenttzdatetime|currenttztimestamp|currentutcdate|currentutcdatetime|currentutctimestamp|dense_rank|datatype|datatypecomponents|datatypehandle|dictaggregate|dictcontains|dictcreate|dicthasitems|dictitems|dictkeytype|dictkeys|dictlength|dictlookup|dictpayloadtype|dictpayloads|dicttype|dicttypecomponents|dicttypehandle|each|each_strict|emptydicttype|emptydicttypehandle|emptylisttype|emptylisttypehandle|endswith|ensure|ensureconvertibleto|ensuretype|enum|evaluateatom|evaluatecode|evaluateexpr|evaluatetype|expandstruct|filter|filter_strict|find|first_value|folder|filecontent|filepath|flattenmembers|forceremovemember|forceremovemembers|forcerenamemembers|forcespreadmembers|formatcode|formattype|frombytes|funccode|greatest|grouping|gathermembers|generictype|histogram|hll|hyperloglog|if|if_strict|instanceof|json_exists|json_query|json_value|jointablerow|just|lag|last_value|lead|least|len|length|like|likely|like_strict|lambdaargumentscount|lambdacode|linearhistogram|listaggregate|listall|listany|listavg|listcode|listcollect|listconcat|listcreate|listdistinct|listenumerate|listextend|listextendstrict|listextract|listfilter|listflatmap|listflatten|listfromrange|listhas|listhasitems|listhead|listindexof|listitemtype|listlast|listlength|listmap|listmax|listmin|listnotnull|listreplicate|listreverse|listskip|listskipwhile|listskipwhileinclusive|listsort|listsortasc|listsortdesc|listsum|listtake|listtakewhile|listtakewhileinclusive|listtype|listtypehandle|listunionall|listuniq|listzip|listzipall|loghistogram|logarithmichistogram|max|max_by|max_of|median|min|min_by|min_of|mode|multi_aggregate_by|nanvl|nvl|nothing|nulltype|nulltypehandle|optionalitemtype|optionaltype|optionaltypehandle|percentile|parsefile|parsetype|parsetypehandle|pickle|quotecode|range|range_strict|rank|regexp|regexp_strict|rfind|row_number|random|randomnumber|randomuuid|removemember|removemembers|removetimezone|renamemembers|replacemember|reprcode|resourcetype|resourcetypehandle|resourcetypetag|some|stddev|stddev_population|stddev_sample|substring|sum|sum_if|sessionstart|sessionwindow|setcreate|setdifference|setincludes|setintersection|setisdisjoint|setsymmetricdifference|setunion|spreadmembers|stablepickle|startswith|staticmap|streamitemtype|streamtype|streamtypehandle|structmembertype|structmembers|structtypecomponents|structtypehandle|subqueryextend|subqueryextendfor|subquerymerge|subquerymergefor|subqueryunionall|subqueryunionallfor|subqueryunionmerge|subqueryunionmergefor|top|topfreq|top_by|tablename|tablepath|tablerecordindex|tablerow|taggedtype|taggedtypecomponents|taggedtypehandle|tobytes|todict|tomultidict|toset|tosorteddict|tosortedmultidict|trymember|tupleelementtype|tupletype|tupletypecomponents|tupletypehandle|typehandle|typekind|typeof|udaf|unittype|unpickle|untag|unwrap|variance|variance_population|variance_sample|variant|varianttype|varianttypehandle|variantunderlyingtype|voidtype|voidtypehandle|way|worldcode'.split('|');
@@ -1,18 +1,24 @@
1
1
  import { generateAggregateFunctionsSuggestion, generateColumnAliasesSuggestion, generateColumnsSuggestion, generateEntitiesSuggestion, generateKeywordsSuggestion, generatePragmasSuggestion, generateSimpleFunctionsSuggestion, generateSimpleTypesSuggestion, generateTableFunctionsSuggestion, generateUdfSuggestion, generateWindowFunctionsSuggestion, } from './generateSuggestions';
2
2
  export function createProvideSuggestionsFunction(database) {
3
3
  return async (model, monacoCursorPosition, _context, _token) => {
4
- const cursorPosition = {
5
- line: monacoCursorPosition.lineNumber,
6
- column: monacoCursorPosition.column,
7
- };
8
4
  const rangeToInsertSuggestion = getRangeToInsertSuggestion(model, monacoCursorPosition);
9
- const suggestions = await getSuggestions(model, cursorPosition, rangeToInsertSuggestion, database);
5
+ const suggestions = await getSuggestions(model, monacoCursorPosition, rangeToInsertSuggestion, database);
10
6
  return { suggestions };
11
7
  };
12
8
  }
9
+ function getEntityNameAtCursor(model, cursorPosition) {
10
+ var _a, _b, _c, _d;
11
+ const prevWord = model.findPreviousMatch('\\s(`?[^\\s]*)', cursorPosition, true, false, null, true);
12
+ const nextWord = model.findNextMatch('([^\\s]*)`?', cursorPosition, true, false, null, true);
13
+ return `${(_b = (_a = prevWord === null || prevWord === void 0 ? void 0 : prevWord.matches) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : ''}${(_d = (_c = nextWord === null || nextWord === void 0 ? void 0 : nextWord.matches) === null || _c === void 0 ? void 0 : _c[1]) !== null && _d !== void 0 ? _d : ''}`;
14
+ }
13
15
  async function getSuggestions(model, cursorPosition, rangeToInsertSuggestion, database) {
14
16
  const { parseYqlQuery } = await import('@gravity-ui/websql-autocomplete');
15
- const parseResult = parseYqlQuery(model.getValue(), cursorPosition);
17
+ const cursorForParsing = {
18
+ line: cursorPosition.lineNumber,
19
+ column: cursorPosition.column,
20
+ };
21
+ const parseResult = parseYqlQuery(model.getValue(), cursorForParsing);
16
22
  let entitiesSuggestions = [];
17
23
  let functionsSuggestions = [];
18
24
  let aggregateFunctionsSuggestions = [];
@@ -22,7 +28,8 @@ async function getSuggestions(model, cursorPosition, rangeToInsertSuggestion, da
22
28
  let simpleTypesSuggestions = [];
23
29
  let pragmasSuggestions = [];
24
30
  if (parseResult.suggestEntity) {
25
- entitiesSuggestions = await generateEntitiesSuggestion(rangeToInsertSuggestion);
31
+ const entityNamePrefix = getEntityNameAtCursor(model, cursorPosition);
32
+ entitiesSuggestions = await generateEntitiesSuggestion(rangeToInsertSuggestion, parseResult.suggestEntity, database, entityNamePrefix);
26
33
  }
27
34
  if (parseResult.suggestFunctions) {
28
35
  functionsSuggestions = await generateSimpleFunctionsSuggestion(rangeToInsertSuggestion);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "6.0.1",
3
+ "version": "6.1.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -21,7 +21,7 @@
21
21
  "@gravity-ui/paranoid": "^1.4.1",
22
22
  "@gravity-ui/react-data-table": "^2.0.1",
23
23
  "@gravity-ui/uikit": "^6.10.2",
24
- "@gravity-ui/websql-autocomplete": "^8.0.2",
24
+ "@gravity-ui/websql-autocomplete": "^8.1.0",
25
25
  "@reduxjs/toolkit": "^2.2.3",
26
26
  "axios": "^1.6.8",
27
27
  "colord": "^2.9.3",
@@ -70,7 +70,7 @@
70
70
  "prepublishOnly": "npm run package",
71
71
  "typecheck": "tsc --noEmit",
72
72
  "prepare": "husky",
73
- "test:e2e:install": "npx playwright install --with-deps chromium",
73
+ "test:e2e:install": "npx playwright install --with-deps",
74
74
  "test:e2e": "npx playwright test --config=playwright.config.ts"
75
75
  },
76
76
  "lint-staged": {