ydb-embedded-ui 6.10.1 → 6.10.3

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/README.md CHANGED
@@ -12,8 +12,8 @@ You can preview working UI using YDB docker image. It will be UI with the latest
12
12
  Run on a machine with Docker installed:
13
13
 
14
14
  ```
15
- docker pull cr.yandex/yc/yandex-docker-local-ydb
16
- docker run -dp 8765:8765 cr.yandex/yc/yandex-docker-local-ydb
15
+ docker pull ghcr.io/ydb-platform/local-ydb:nightly
16
+ docker run -dp 8765:8765 ghcr.io/ydb-platform/local-ydb:nightly
17
17
  ```
18
18
 
19
19
  Open http://localhost:8765 to view it in the browser.
@@ -25,7 +25,7 @@ Open http://localhost:8765 to view it in the browser.
25
25
  docker run --rm -ti --name ydb-local -h localhost \
26
26
  -p 8765:8765 \
27
27
  -e MON_PORT=8765 \
28
- cr.yandex/yc/yandex-docker-local-ydb:latest
28
+ ghcr.io/ydb-platform/local-ydb:nightly
29
29
  ```
30
30
  2. Install dependencies with `npm ci`
31
31
  3. Run the frontend app in the development mode, via invoking `npm run dev`
@@ -38,11 +38,8 @@ For API reference, open Swagger UI on http://localhost:8765/viewer/api/.
38
38
 
39
39
  [Docs on YDB docker images](https://ydb.tech/en/docs/getting_started/self_hosted/ydb_docker)
40
40
 
41
- Image `cr.yandex/yc/yandex-docker-local-ydb` corresponds to `:latest` tag. It's the latest stable ydb version.
42
-
43
- To test new features, you can use ydb version that is currently in testing mode with `cr.yandex/yc/yandex-docker-local-ydb:edge` image
44
- or use a build from `main` brunch with `ghcr.io/ydb-platform/local-ydb:nightly` image.
45
- Also you can set specific version like `cr.yandex/yc/yandex-docker-local-ydb:23.1`
41
+ To test new features, you can use ydb version built from `main` brunch with `ghcr.io/ydb-platform/local-ydb:nightly` image.
42
+ Also you can set specific version like `ghcr.io/ydb-platform/local-ydb:24.1`
46
43
 
47
44
  ### Custom configuration in dev mode with .env file
48
45
 
@@ -105,7 +102,7 @@ npm run test:e2e
105
102
 
106
103
  ### CI
107
104
 
108
- E2E tests are run in CI in `e2e_tests` job. Tests run on Playwright `webServer` (it is started with `npm run dev`), `webServer` uses docker container `cr.yandex/yc/yandex-docker-local-ydb` as backend.
105
+ E2E tests are run in CI in `e2e_tests` job. Tests run on Playwright `webServer` (it is started with `npm run dev`), `webServer` uses docker container `ghcr.io/ydb-platform/local-ydb:nightly` as backend.
109
106
 
110
107
  ## Making a production bundle.
111
108
 
@@ -118,7 +115,7 @@ To test production bundle with latest YDB backend release, do the following:
118
115
 
119
116
  1. Install dependencies with `npm ci`
120
117
  2. Build a production bundle with a few tweaks for embedded version: `npm run build:embedded`.
121
- 3. Invoke `docker run -it --hostname localhost -dp 2135:2135 -p 8765:8765 -v ~/projects/ydb-embedded-ui/build:/ydb_data/node_1/content/monitoring cr.yandex/yc/yandex-docker-local-ydb:latest`
118
+ 3. Invoke `docker run -it --hostname localhost -dp 2135:2135 -p 8765:8765 -v ~/projects/ydb-embedded-ui/build:/ydb_data/node_1/content/monitoring ghcr.io/ydb-platform/local-ydb:nightly`
122
119
  4. Open [embedded YDB UI](http://localhost:8765/monitoring) to view it in the browser.
123
120
 
124
121
  ### Testing production bundle with specific cluster host
@@ -6,7 +6,7 @@ import { Button, Card, Icon } from '@gravity-ui/uikit';
6
6
  import { ResponseError } from '../../../../components/Errors/ResponseError';
7
7
  import { ResizeableDataTable } from '../../../../components/ResizeableDataTable/ResizeableDataTable';
8
8
  import { hotKeysApi } from '../../../../store/reducers/hotKeys/hotKeys';
9
- import { schemaApi } from '../../../../store/reducers/schema/schema';
9
+ import { useGetSchemaQuery } from '../../../../store/reducers/schema/schema';
10
10
  import { cn } from '../../../../utils/cn';
11
11
  import { DEFAULT_TABLE_SETTINGS, IS_HOTKEYS_HELP_HIDDEN_KEY } from '../../../../utils/constants';
12
12
  import { useSetting } from '../../../../utils/hooks';
@@ -41,8 +41,7 @@ export function HotKeys({ path }) {
41
41
  var _a, _b;
42
42
  const { currentData: data, isFetching, error } = hotKeysApi.useGetHotKeysQuery({ path });
43
43
  const loading = isFetching && data === undefined;
44
- const { currentData: schemaData, isFetching: schemaIsFetching } = schemaApi.endpoints.getSchema.useQueryState({ path });
45
- const schemaLoading = schemaIsFetching && schemaData === undefined;
44
+ const { data: schemaData, isLoading: schemaLoading } = useGetSchemaQuery({ path });
46
45
  const keyColumnsIds = (_b = (_a = schemaData === null || schemaData === void 0 ? void 0 : schemaData.PathDescription) === null || _a === void 0 ? void 0 : _a.Table) === null || _b === void 0 ? void 0 : _b.KeyColumnNames;
47
46
  const tableColumns = React.useMemo(() => {
48
47
  return getHotKeysColumns(keyColumnsIds);
@@ -4,25 +4,31 @@ import { shallowEqual } from 'react-redux';
4
4
  import { ResponseError } from '../../../../components/Errors/ResponseError';
5
5
  import { TableIndexInfo } from '../../../../components/InfoViewer/schemaInfo';
6
6
  import { Loader } from '../../../../components/Loader';
7
- import { olapApi } from '../../../../store/reducers/olapStats';
8
7
  import { overviewApi } from '../../../../store/reducers/overview/overview';
9
- import { schemaApi, selectSchemaMergedChildrenPaths } from '../../../../store/reducers/schema/schema';
8
+ import { selectSchemaMergedChildrenPaths, useGetSchemaQuery, } from '../../../../store/reducers/schema/schema';
10
9
  import { EPathType } from '../../../../types/api/schema';
11
10
  import { useAutoRefreshInterval, useTypedSelector } from '../../../../utils/hooks';
12
11
  import { ExternalDataSourceInfo } from '../../Info/ExternalDataSource/ExternalDataSource';
13
12
  import { ExternalTableInfo } from '../../Info/ExternalTable/ExternalTable';
14
13
  import { ViewInfo } from '../../Info/View/View';
15
- import { isColumnEntityType, isEntityWithMergedImplementation, isTableType, } from '../../utils/schema';
14
+ import { isEntityWithMergedImplementation } from '../../utils/schema';
16
15
  import { AsyncReplicationInfo } from './AsyncReplicationInfo';
17
16
  import { ChangefeedInfo } from './ChangefeedInfo';
18
17
  import { TableInfo } from './TableInfo';
19
18
  import { TopicInfo } from './TopicInfo';
20
19
  function Overview({ type, path }) {
21
20
  const [autoRefreshInterval] = useAutoRefreshInterval();
22
- const olapParams = isTableType(type) && isColumnEntityType(type) ? { path } : skipToken;
23
- const { currentData: olapData, isFetching: olapIsFetching } = olapApi.useGetOlapStatsQuery(olapParams, { pollingInterval: autoRefreshInterval });
24
- const olapStatsLoading = olapIsFetching && olapData === undefined;
25
- const { result: olapStats } = olapData || { result: undefined };
21
+ // FIXME: The request is too heavy, stats table may have millions of items
22
+ // Disabled until fixed
23
+ // https://github.com/ydb-platform/ydb-embedded-ui/issues/907
24
+ // https://github.com/ydb-platform/ydb-embedded-ui/issues/908
25
+ // const olapParams = isTableType(type) && isColumnEntityType(type) ? {path} : skipToken;
26
+ // const {currentData: olapData, isFetching: olapIsFetching} = olapApi.useGetOlapStatsQuery(
27
+ // olapParams,
28
+ // {pollingInterval: autoRefreshInterval},
29
+ // );
30
+ // const olapStatsLoading = olapIsFetching && olapData === undefined;
31
+ // const {result: olapStats} = olapData || {result: undefined};
26
32
  const isEntityWithMergedImpl = isEntityWithMergedImplementation(type);
27
33
  // shallowEqual prevents rerenders when new schema data is loaded
28
34
  const mergedChildrenPaths = useTypedSelector((state) => selectSchemaMergedChildrenPaths(state, path, type), shallowEqual);
@@ -38,8 +44,9 @@ function Overview({ type, path }) {
38
44
  });
39
45
  const overviewLoading = isFetching && currentData === undefined;
40
46
  const { data: rawData, additionalData } = currentData || {};
41
- const { error: schemaError } = schemaApi.endpoints.getSchema.useQueryState({ path });
42
- const entityLoading = overviewLoading || olapStatsLoading;
47
+ const { error: schemaError } = useGetSchemaQuery({ path });
48
+ // overviewLoading || olapStatsLoading
49
+ const entityLoading = overviewLoading;
43
50
  const entityNotReady = isEntityWithMergedImpl && !mergedChildrenPaths;
44
51
  const renderContent = () => {
45
52
  var _a;
@@ -65,7 +72,7 @@ function Overview({ type, path }) {
65
72
  [EPathType.EPathTypeView]: () => _jsx(ViewInfo, { data: data }),
66
73
  [EPathType.EPathTypeReplication]: () => _jsx(AsyncReplicationInfo, { data: data }),
67
74
  };
68
- return ((type && ((_a = pathTypeToComponent[type]) === null || _a === void 0 ? void 0 : _a.call(pathTypeToComponent))) || (_jsx(TableInfo, { data: data, type: type, olapStats: olapStats })));
75
+ return ((type && ((_a = pathTypeToComponent[type]) === null || _a === void 0 ? void 0 : _a.call(pathTypeToComponent))) || (_jsx(TableInfo, { data: data, type: type })));
69
76
  };
70
77
  if (entityLoading || entityNotReady) {
71
78
  return _jsx(Loader, { size: "m" });
@@ -9,6 +9,6 @@ import './TableInfo.scss';
9
9
  const b = cn('ydb-diagnostics-table-info');
10
10
  export const TableInfo = ({ data, type, olapStats }) => {
11
11
  const title = _jsx(EntityTitle, { data: data === null || data === void 0 ? void 0 : data.PathDescription });
12
- const { generalInfo = [], tableStatsInfo = [], tabletMetricsInfo = [], partitionConfigInfo = [], } = React.useMemo(() => prepareTableInfo(data, type, olapStats), [data, type, olapStats]);
13
- return (_jsxs("div", { className: b(), children: [_jsx(InfoViewer, { info: generalInfo, title: title, className: b('info-block'), renderEmptyState: () => _jsx("div", { className: b('title'), children: title }) }), _jsxs("div", { className: b('row'), children: [_jsx("div", { className: b('col'), children: tableStatsInfo.map((info, index) => (_jsx(InfoViewer, { info: info, title: index === 0 ? i18n('tableStats') : undefined, className: b('info-block'), renderEmptyState: () => null }, index))) }), tabletMetricsInfo.length > 0 || partitionConfigInfo.length > 0 ? (_jsxs("div", { className: b('col'), children: [_jsx(InfoViewer, { info: tabletMetricsInfo, title: i18n('tabletMetrics'), className: b('info-block'), renderEmptyState: () => null }), _jsx(InfoViewer, { info: partitionConfigInfo, title: i18n('partitionConfig'), className: b('info-block'), renderEmptyState: () => null })] })) : null] })] }));
12
+ const { generalInfo, tableStatsInfo, tabletMetricsInfo = [], partitionConfigInfo = [], } = React.useMemo(() => prepareTableInfo(data, type, olapStats), [data, type, olapStats]);
13
+ return (_jsxs("div", { className: b(), children: [_jsx(InfoViewer, { info: generalInfo, title: title, className: b('info-block'), renderEmptyState: () => _jsx("div", { className: b('title'), children: title }) }), _jsxs("div", { className: b('row'), children: [tableStatsInfo ? (_jsx("div", { className: b('col'), children: tableStatsInfo.map((info, index) => (_jsx(InfoViewer, { info: info, title: index === 0 ? i18n('tableStats') : undefined, className: b('info-block'), renderEmptyState: () => null }, index))) })) : null, tabletMetricsInfo.length > 0 || partitionConfigInfo.length > 0 ? (_jsxs("div", { className: b('col'), children: [_jsx(InfoViewer, { info: tabletMetricsInfo, title: i18n('tabletMetrics'), className: b('info-block'), renderEmptyState: () => null }), _jsx(InfoViewer, { info: partitionConfigInfo, title: i18n('partitionConfig'), className: b('info-block'), renderEmptyState: () => null })] })) : null] })] }));
14
14
  };
@@ -10,7 +10,7 @@ export declare const prepareTableInfo: (data?: TEvDescribeSchemeResult, type?: E
10
10
  partitionConfigInfo?: undefined;
11
11
  } | {
12
12
  generalInfo: InfoViewerItem[];
13
- tableStatsInfo: InfoViewerItem[][];
13
+ tableStatsInfo: InfoViewerItem[][] | undefined;
14
14
  tabletMetricsInfo: InfoViewerItem[];
15
15
  partitionConfigInfo: InfoViewerItem[];
16
16
  };
@@ -120,7 +120,9 @@ export const prepareTableInfo = (data, type, olapStats) => {
120
120
  // There is no TableStats and TabletMetrics for ColumnTables inside ColumnStore
121
121
  // Therefore we parse olapStats
122
122
  if (type === EPathType.EPathTypeColumnTable && isInStoreColumnTable(ColumnTableDescription)) {
123
- tableStatsInfo = [prepareOlapStats(olapStats)];
123
+ if (olapStats) {
124
+ tableStatsInfo = [prepareOlapStats(olapStats)];
125
+ }
124
126
  }
125
127
  else {
126
128
  tableStatsInfo = [
@@ -13,7 +13,7 @@ import { LinkWithIcon } from '../../../components/LinkWithIcon/LinkWithIcon';
13
13
  import { Loader } from '../../../components/Loader';
14
14
  import SplitPane from '../../../components/SplitPane';
15
15
  import routes, { createExternalUILink, createHref } from '../../../routes';
16
- import { schemaApi, setShowPreview } from '../../../store/reducers/schema/schema';
16
+ import { setShowPreview, useGetSchemaQuery } from '../../../store/reducers/schema/schema';
17
17
  import { TENANT_PAGES_IDS, TENANT_QUERY_TABS_ID, TENANT_SUMMARY_TABS_IDS, } from '../../../store/reducers/tenant/constants';
18
18
  import { setQueryTab, setSummaryTab, setTenantPage } from '../../../store/reducers/tenant/tenant';
19
19
  import { EPathSubType, EPathType } from '../../../types/api/schema';
@@ -48,7 +48,7 @@ export function ObjectSummary({ type, subType, tenantName, path, onCollapseSumma
48
48
  const queryParams = qs.parse(location.search, {
49
49
  ignoreQueryPrefix: true,
50
50
  });
51
- const { currentData: currentObjectData } = schemaApi.endpoints.getSchema.useQueryState({ path });
51
+ const { data: currentObjectData } = useGetSchemaQuery({ path });
52
52
  const currentSchemaData = (_a = currentObjectData === null || currentObjectData === void 0 ? void 0 : currentObjectData.PathDescription) === null || _a === void 0 ? void 0 : _a.Self;
53
53
  React.useEffect(() => {
54
54
  const isTable = isTableType(type);
@@ -255,12 +255,12 @@ export function ObjectSummary({ type, subType, tenantName, path, onCollapseSumma
255
255
  }
256
256
  function ObjectTree({ tenantName, path }) {
257
257
  var _a;
258
- const { currentData: tenantData = {}, isFetching } = schemaApi.useGetSchemaQuery({
258
+ const { data: tenantData = {}, isLoading } = useGetSchemaQuery({
259
259
  path: tenantName,
260
260
  });
261
261
  const pathData = (_a = tenantData === null || tenantData === void 0 ? void 0 : tenantData.PathDescription) === null || _a === void 0 ? void 0 : _a.Self;
262
262
  const [, setCurrentPath] = useQueryParam('schema', StringParam);
263
- if (!pathData && isFetching) {
263
+ if (!pathData && isLoading) {
264
264
  // If Loader isn't wrapped with div, SplitPane doesn't calculate panes height correctly
265
265
  return (_jsx("div", { children: _jsx(Loader, {}) }));
266
266
  }
@@ -47,12 +47,8 @@
47
47
  &__inspector {
48
48
  overflow-y: auto;
49
49
 
50
- width: 100%;
51
50
  padding: 15px 20px;
52
51
  @include json-tree-styles();
53
- & .json-inspector__leaf.json-inspector__leaf_root.json-inspector__leaf_composite {
54
- max-width: calc(100% - 50px);
55
- }
56
52
 
57
53
  &_fullscreen {
58
54
  padding: 10px;
@@ -20,13 +20,23 @@ export function SchemaTree(props) {
20
20
  const [parentPath, setParentPath] = React.useState('');
21
21
  const [schemaTreeKey, setSchemaTreeKey] = React.useState('');
22
22
  const fetchPath = async (path) => {
23
- const promise = dispatch(schemaApi.endpoints.getSchema.initiate({ path }, { forceRefetch: true }));
24
- const { data } = await promise;
25
- promise.unsubscribe();
26
- if (!data) {
23
+ let schemaData;
24
+ do {
25
+ const promise = dispatch(schemaApi.endpoints.getSchema.initiate({ path }, { forceRefetch: true }));
26
+ const { data, originalArgs } = await promise;
27
+ promise.unsubscribe();
28
+ // Check if the result from the current request is received. rtk-query may skip the current request and
29
+ // return data from a parallel request, due to the same cache key.
30
+ if ((originalArgs === null || originalArgs === void 0 ? void 0 : originalArgs.path) === path) {
31
+ schemaData = data === null || data === void 0 ? void 0 : data[path];
32
+ break;
33
+ }
34
+ // eslint-disable-next-line no-constant-condition
35
+ } while (true);
36
+ if (!schemaData) {
27
37
  throw new Error(`no describe data about path ${path}`);
28
38
  }
29
- const { PathDescription: { Children = [] } = {} } = data;
39
+ const { PathDescription: { Children = [] } = {} } = schemaData;
30
40
  const childItems = Children.map((childData) => {
31
41
  const { Name = '', PathType, PathSubType } = childData;
32
42
  return {
@@ -4,7 +4,7 @@ import DataTable from '@gravity-ui/react-data-table';
4
4
  import { skipToken } from '@reduxjs/toolkit/query';
5
5
  import { ResizeableDataTable } from '../../../../components/ResizeableDataTable/ResizeableDataTable';
6
6
  import { TableSkeleton } from '../../../../components/TableSkeleton/TableSkeleton';
7
- import { schemaApi } from '../../../../store/reducers/schema/schema';
7
+ import { useGetSchemaQuery } from '../../../../store/reducers/schema/schema';
8
8
  import { viewSchemaApi } from '../../../../store/reducers/viewSchema/viewSchema';
9
9
  import { DEFAULT_TABLE_SETTINGS } from '../../../../utils/constants';
10
10
  import { isColumnEntityType, isExternalTableType, isRowTableType, isViewType, } from '../../utils/schema';
@@ -13,10 +13,7 @@ import { prepareSchemaData, prepareViewSchema } from './prepareData';
13
13
  import { b } from './shared';
14
14
  import './SchemaViewer.scss';
15
15
  export const SchemaViewer = ({ type, path, tenantName, extended = false }) => {
16
- const { currentData: schemaData, isFetching } = schemaApi.endpoints.getSchema.useQueryState({
17
- path,
18
- });
19
- const loading = isFetching && schemaData === undefined;
16
+ const { data: schemaData, isLoading: loading } = useGetSchemaQuery({ path });
20
17
  const viewSchemaRequestParams = isViewType(type) ? { path, database: tenantName } : skipToken;
21
18
  const { data: viewColumnsData, isLoading: isViewSchemaLoading } = viewSchemaApi.useGetViewSchemaQuery(viewSchemaRequestParams);
22
19
  const tableData = React.useMemo(() => {
@@ -6,7 +6,7 @@ import { AccessDenied } from '../../components/Errors/403';
6
6
  import { Loader } from '../../components/Loader';
7
7
  import SplitPane from '../../components/SplitPane';
8
8
  import { setHeaderBreadcrumbs } from '../../store/reducers/header/header';
9
- import { schemaApi } from '../../store/reducers/schema/schema';
9
+ import { useGetSchemaQuery } from '../../store/reducers/schema/schema';
10
10
  import { cn } from '../../utils/cn';
11
11
  import { DEFAULT_IS_TENANT_SUMMARY_COLLAPSED, DEFAULT_SIZE_TENANT_KEY } from '../../utils/constants';
12
12
  import { useTypedDispatch } from '../../utils/hooks';
@@ -47,7 +47,7 @@ export function Tenant(props) {
47
47
  dispatch(setHeaderBreadcrumbs('tenant', { tenantName }));
48
48
  }, [tenantName, dispatch]);
49
49
  const path = schema !== null && schema !== void 0 ? schema : tenantName;
50
- const { currentData: currentItem, error, isLoading, } = schemaApi.useGetSchemaQuery({ path }, { refetchOnMountOrArgChange: true });
50
+ const { data: currentItem, error, isLoading } = useGetSchemaQuery({ path });
51
51
  const { PathType: currentPathType, PathSubType: currentPathSubType } = ((_a = currentItem === null || currentItem === void 0 ? void 0 : currentItem.PathDescription) === null || _a === void 0 ? void 0 : _a.Self) || {};
52
52
  let showBlockingError = false;
53
53
  if (error && typeof error === 'object' && 'status' in error) {
@@ -21,11 +21,22 @@ export declare const schemaApi: import("@reduxjs/toolkit/query").Api<import("@re
21
21
  }, import("@reduxjs/toolkit/query").BaseQueryFn<void, typeof import("../api")._NEVER, unknown, {}>, "All", unknown, "api">;
22
22
  getSchema: import("@reduxjs/toolkit/query").QueryDefinition<{
23
23
  path: string;
24
- }, import("@reduxjs/toolkit/query").BaseQueryFn<void, typeof import("../api")._NEVER, unknown, {}>, "All", TEvDescribeSchemeResult & {
25
- partial?: boolean;
24
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<void, typeof import("../api")._NEVER, unknown, {}>, "All", {
25
+ [path: string]: TEvDescribeSchemeResult & {
26
+ partial?: boolean;
27
+ };
26
28
  }, "api">;
27
29
  }, "api", "All", typeof import("@reduxjs/toolkit/query").coreModuleName | typeof import("@reduxjs/toolkit/query/react").reactHooksModuleName>;
28
30
  export declare const selectSchemaMergedChildrenPaths: Selector<RootState, string[] | undefined, [
29
31
  string | undefined,
30
32
  EPathType | undefined
31
33
  ]>;
34
+ export declare function useGetSchemaQuery({ path }: {
35
+ path: string;
36
+ }): {
37
+ data: (TEvDescribeSchemeResult & {
38
+ partial?: boolean;
39
+ }) | undefined;
40
+ isLoading: boolean;
41
+ error: unknown;
42
+ };
@@ -1,3 +1,4 @@
1
+ import React from 'react';
1
2
  import { createSelector } from '@reduxjs/toolkit';
2
3
  import { isEntityWithMergedImplementation } from '../../../containers/Tenant/utils/schema';
3
4
  import { api } from '../api';
@@ -44,42 +45,44 @@ export const schemaApi = api.injectEndpoints({
44
45
  queryFn: async ({ path }, { signal }) => {
45
46
  try {
46
47
  const data = await window.api.getSchema({ path }, { signal });
47
- return { data: data !== null && data !== void 0 ? data : {} };
48
+ return { data: data ? { [path]: data, ...getSchemaChildren(data) } : {} };
48
49
  }
49
50
  catch (error) {
50
51
  return { error };
51
52
  }
52
53
  },
53
54
  keepUnusedDataFor: Infinity,
54
- forceRefetch: ({ endpointState }) => {
55
- const data = endpointState === null || endpointState === void 0 ? void 0 : endpointState.data;
56
- if (data && typeof data === 'object' && 'partial' in data && data.partial) {
57
- return true;
58
- }
59
- return false;
55
+ serializeQueryArgs: ({ queryArgs: { path } }) => {
56
+ const parts = path.split('/');
57
+ return { path: parts[0] || parts[1] };
60
58
  },
61
- onQueryStarted: async ({ path }, { dispatch, getState, queryFulfilled }) => {
62
- const { data } = await queryFulfilled;
59
+ merge: (existing, incoming, { arg: { path } }) => {
60
+ const { [path]: data, ...children } = incoming;
63
61
  if (data) {
64
- const state = getState();
65
- const { PathDescription: { Children = [] } = {} } = data;
66
- for (const child of Children) {
67
- const { Name = '' } = child;
68
- const childPath = `${path}/${Name}`;
69
- const cachedData = schemaApi.endpoints.getSchema.select({ path: childPath })(state).data;
70
- if (!cachedData) {
71
- // not full data, but it contains PathType, which ensures seamless switch between nodes
72
- dispatch(schemaApi.util.upsertQueryData('getSchema', { path: childPath }, { PathDescription: { Self: child }, partial: true }));
73
- }
74
- }
62
+ return {
63
+ ...children,
64
+ ...existing,
65
+ [path]: data,
66
+ };
75
67
  }
68
+ return existing;
76
69
  },
77
70
  }),
78
71
  }),
79
72
  overrideExisting: 'throw',
80
73
  });
74
+ function getSchemaChildren(data) {
75
+ const children = {};
76
+ const { PathDescription: { Children = [] } = {}, Path: path } = data;
77
+ for (const child of Children) {
78
+ const { Name = '' } = child;
79
+ const childPath = `${path}/${Name}`;
80
+ children[childPath] = { PathDescription: { Self: child }, Path: childPath, partial: true };
81
+ }
82
+ return children;
83
+ }
81
84
  const getSchemaSelector = createSelector((path) => path, (path) => schemaApi.endpoints.getSchema.select({ path }));
82
- const selectGetSchema = createSelector((state) => state, (_state, path) => getSchemaSelector(path), (state, selectTabletsInfo) => selectTabletsInfo(state).data);
85
+ const selectGetSchema = createSelector((state) => state, (_state, path) => path, (_state, path) => getSchemaSelector(path), (state, path, selectTabletsInfo) => { var _a; return (_a = selectTabletsInfo(state).data) === null || _a === void 0 ? void 0 : _a[path]; });
83
86
  const selectSchemaChildren = (state, path) => { var _a, _b; return (_b = (_a = selectGetSchema(state, path)) === null || _a === void 0 ? void 0 : _a.PathDescription) === null || _b === void 0 ? void 0 : _b.Children; };
84
87
  export const selectSchemaMergedChildrenPaths = createSelector([
85
88
  (_, path) => path,
@@ -90,3 +93,15 @@ export const selectSchemaMergedChildrenPaths = createSelector([
90
93
  ? children === null || children === void 0 ? void 0 : children.map(({ Name }) => path + '/' + Name)
91
94
  : undefined;
92
95
  });
96
+ export function useGetSchemaQuery({ path }) {
97
+ const { currentData, isFetching, error, refetch } = schemaApi.useGetSchemaQuery({ path });
98
+ const data = currentData === null || currentData === void 0 ? void 0 : currentData[path];
99
+ const isLoading = isFetching && data === undefined;
100
+ const shouldLoad = !isLoading && ((!data && !error) || (data === null || data === void 0 ? void 0 : data.partial));
101
+ React.useEffect(() => {
102
+ if (shouldLoad) {
103
+ refetch();
104
+ }
105
+ }, [refetch, path, shouldLoad]);
106
+ return { data, isLoading, error };
107
+ }
@@ -196,6 +196,10 @@
196
196
  }
197
197
 
198
198
  @mixin json-tree-styles {
199
+ width: 100%;
200
+
201
+ word-wrap: break-word;
202
+
199
203
  // stylelint-disable
200
204
  font-family: var(--g-font-family-monospace) !important;
201
205
  font-size: var(--g-text-code-1-font-size) !important;
@@ -276,4 +280,8 @@
276
280
  color: var(--g-color-text-primary);
277
281
  }
278
282
  }
283
+
284
+ & .json-inspector__leaf.json-inspector__leaf_root.json-inspector__leaf_composite {
285
+ max-width: calc(100% - 50px);
286
+ }
279
287
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "6.10.1",
3
+ "version": "6.10.3",
4
4
  "files": [
5
5
  "dist"
6
6
  ],