Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ Open http://localhost:8765 to view it in the browser.

1. Run on a machine with Docker installed:
```
docker pull cr.yandex/yc/yandex-docker-local-ydb
docker run --hostname localhost -e YDB_ALLOW_ORIGIN="http://localhost:3000" -dp 2135:2135 -dp 8765:8765 cr.yandex/yc/yandex-docker-local-ydb
docker run --rm -ti --name ydb-local -h localhost \
-p 8765:8765 \
-e MON_PORT=8765 \
cr.yandex/yc/yandex-docker-local-ydb:latest
```
2. Run the frontend app in the development mode, via invoking `npm run dev`
3. Open [http://localhost:3000](http://localhost:3000) to view it in the browser. The page will reload if you make edits.\
3. Open [localhost:3000](http://localhost:3000) to view it in the browser. The page will reload if you make edits.\
You will also see any lint errors in the console.

For API reference, open Swagger UI on http://localhost:8765/viewer/api/.
Expand All @@ -37,7 +39,9 @@ For API reference, open Swagger UI on http://localhost:8765/viewer/api/.

Image `cr.yandex/yc/yandex-docker-local-ydb` corresponds to `:latest` tag. It's the latest stable ydb version.

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. Also you can set specific version like `cr.yandex/yc/yandex-docker-local-ydb:23.1`
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
or use a build from `main` brunch with `ghcr.io/ydb-platform/local-ydb:trunk` image.
Also you can set specific version like `cr.yandex/yc/yandex-docker-local-ydb:23.1`

### Custom backend in dev mode

Expand Down
5 changes: 0 additions & 5 deletions src/containers/Tenant/Acl/Acl.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,12 @@
overflow: auto;
flex-grow: 1;

padding: 0 12px 16px;
@include query-data-table;

&__result {
align-self: flex-start;
}

&__message-container {
padding: 0 12px 16px;
}

&__owner-container {
position: sticky;
z-index: 2;
Expand Down
4 changes: 2 additions & 2 deletions src/containers/Tenant/Acl/Acl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,11 @@ export const Acl = () => {
}

if (error) {
return <ResponseError error={error} className={b('message-container')} />;
return <ResponseError error={error} />;
}

if (!loading && !acl && !owner) {
return <div className={b('message-container')}>{i18n('acl.empty')}</div>;
return <React.Fragment>{i18n('acl.empty')}</React.Fragment>;
}

return (
Expand Down
4 changes: 4 additions & 0 deletions src/containers/Tenant/Diagnostics/Diagnostics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {Heatmap} from '../../Heatmap';
import {NodesWrapper} from '../../Nodes/NodesWrapper';
import {StorageWrapper} from '../../Storage/StorageWrapper';
import {Tablets} from '../../Tablets';
import {SchemaViewer} from '../Schema/SchemaViewer/SchemaViewer';
import {TenantTabsGroups} from '../TenantPages';
import {isDatabaseEntityType} from '../utils/schema';

Expand Down Expand Up @@ -103,6 +104,9 @@ function Diagnostics(props: DiagnosticsProps) {
/>
);
}
case TENANT_DIAGNOSTICS_TABS_IDS.schema: {
return <SchemaViewer path={currentSchemaPath} type={type} withFamilies />;
}
case TENANT_DIAGNOSTICS_TABS_IDS.topQueries: {
return <TopQueries path={tenantNameString} type={type} />;
}
Expand Down
9 changes: 7 additions & 2 deletions src/containers/Tenant/Diagnostics/DiagnosticsPages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ const overview = {
title: 'Info',
};

const schema = {
id: TENANT_DIAGNOSTICS_TABS_IDS.schema,
title: 'Schema',
};

const topQueries = {
id: TENANT_DIAGNOSTICS_TABS_IDS.topQueries,
title: 'Top queries',
Expand Down Expand Up @@ -76,8 +81,8 @@ export const DATABASE_PAGES = [
describe,
];

export const TABLE_PAGES = [overview, topShards, nodes, graph, tablets, hotKeys, describe];
export const COLUMN_TABLE_PAGES = [overview, topShards, nodes, graph, tablets, describe];
export const TABLE_PAGES = [overview, schema, topShards, nodes, graph, tablets, hotKeys, describe];
export const COLUMN_TABLE_PAGES = [overview, schema, topShards, nodes, graph, tablets, describe];

export const DIR_PAGES = [overview, topShards, nodes, describe];

Expand Down
59 changes: 6 additions & 53 deletions src/containers/Tenant/ObjectSummary/ObjectSummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,7 @@ import {
TENANT_SUMMARY_TABS_IDS,
} from '../../../store/reducers/tenant/constants';
import {setQueryTab, setSummaryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
import type {
EPathSubType,
TColumnDescription,
TColumnTableDescription,
} from '../../../types/api/schema';
import type {EPathSubType} from '../../../types/api/schema';
import {EPathType} from '../../../types/api/schema';
import {cn} from '../../../utils/cn';
import {
Expand All @@ -48,7 +44,7 @@ import {
PaneVisibilityToggleButtons,
paneVisibilityToggleReducerCreator,
} from '../utils/paneVisibilityToggleHelpers';
import {isColumnEntityType, isExternalTable, isIndexTable, isTableType} from '../utils/schema';
import {isIndexTable, isTableType} from '../utils/schema';

import './ObjectSummary.scss';

Expand All @@ -64,29 +60,6 @@ const getTenantCommonInfoState = () => {
};
};

function prepareOlapTableSchema(tableSchema: TColumnTableDescription = {}) {
const {Name, Schema} = tableSchema;

if (Schema) {
const {Columns, KeyColumnNames} = Schema;
const KeyColumnIds = KeyColumnNames?.map((name: string) => {
const column = Columns?.find((el) => el.Name === name);
return column?.Id;
}).filter((id): id is number => id !== undefined);

return {
Columns,
KeyColumnNames,
Name,
KeyColumnIds,
};
}

return {
Name,
};
}

interface ObjectSummaryProps {
type?: EPathType;
subType?: EPathSubType;
Expand All @@ -112,7 +85,6 @@ export function ObjectSummary({
data,
currentSchemaPath,
currentSchema: currentItem = {},
loading: loadingSchema,
} = useTypedSelector((state) => state.schema);
const {summaryTab = TENANT_SUMMARY_TABS_IDS.overview} = useTypedSelector(
(state) => state.tenant,
Expand All @@ -130,21 +102,6 @@ export function ObjectSummary({
const currentObjectData = currentSchemaPath ? data[currentSchemaPath] : undefined;
const currentSchemaData = currentObjectData?.PathDescription?.Self;

let keyColumnIds: number[] | undefined;
let columns: TColumnDescription[] | undefined;

if (isTableType(type) && isColumnEntityType(type)) {
const description = currentObjectData?.PathDescription?.ColumnTableDescription;
const columnTableSchema = prepareOlapTableSchema(description);
keyColumnIds = columnTableSchema.KeyColumnIds;
columns = columnTableSchema.Columns;
} else if (isExternalTable(type)) {
columns = currentObjectData?.PathDescription?.ExternalTableDescription?.Columns;
} else {
keyColumnIds = currentObjectData?.PathDescription?.Table?.KeyColumnIds;
columns = currentObjectData?.PathDescription?.Table?.Columns;
}

React.useEffect(() => {
const isTable = isTableType(type);

Expand Down Expand Up @@ -218,7 +175,7 @@ export function ObjectSummary({
component = <InfoViewer info={[{label: 'Create time', value: createTime}]} />;
}

return <div className={b('overview-wrapper')}>{component}</div>;
return component;
};

const renderLoader = () => {
Expand All @@ -236,12 +193,8 @@ export function ObjectSummary({
return <Acl />;
}
case TENANT_SUMMARY_TABS_IDS.schema: {
return loadingSchema ? (
renderLoader()
) : (
<div className={b('schema')}>
<SchemaViewer keyColumnIds={keyColumnIds} columns={columns} type={type} />
</div>
return (
<SchemaViewer className={b('schema')} type={type} path={currentSchemaPath} />
);
}
default: {
Expand Down Expand Up @@ -364,7 +317,7 @@ export function ObjectSummary({
</div>
{renderTabs()}
</div>
{renderTabContent()}
<div className={b('overview-wrapper')}>{renderTabContent()}</div>
</div>
</SplitPane>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.schema-viewer {
padding: 0px 12px;
&__key-icon {
display: flex;
align-items: center;
Expand Down
126 changes: 39 additions & 87 deletions src/containers/Tenant/Schema/SchemaViewer/SchemaViewer.tsx
Original file line number Diff line number Diff line change
@@ -1,106 +1,58 @@
import React from 'react';

import type {Column} from '@gravity-ui/react-data-table';
import DataTable from '@gravity-ui/react-data-table';

import {Icon} from '../../../../components/Icon';
import type {EPathType, TColumnDescription} from '../../../../types/api/schema';
import {TableSkeleton} from '../../../../components/TableSkeleton/TableSkeleton';
import type {EPathType} from '../../../../types/api/schema';
import {cn} from '../../../../utils/cn';
import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
import {isExternalTable} from '../../utils/schema';
import {useTypedSelector} from '../../../../utils/hooks';

import {
SchemaViewerColumns,
prepareColumnDescriptions,
prepareFamilies,
prepareSchemaTableColumns,
} from './helpers';

import './SchemaViewer.scss';

const b = cn('schema-viewer');

const SchemaViewerColumns = {
id: 'Id',
name: 'Name',
key: 'Key',
type: 'Type',
notNull: 'NotNull',
};

interface SchemaViewerProps {
keyColumnIds?: number[];
columns?: TColumnDescription[];
className?: string;
type?: EPathType;
path?: string;
withFamilies?: boolean;
}

export const SchemaViewer = ({keyColumnIds = [], columns = [], type}: SchemaViewerProps) => {
// Keys should be displayd by their order in keyColumnIds (Primary Key)
const keyColumnsOrderValues = React.useMemo(() => {
return keyColumnIds.reduce<Record<number, number>>((result, keyColumnId, index) => {
// Put columns with negative values, so they will be the first with ascending sort
// Minus keyColumnIds.length for the first key, -1 for the last
result[keyColumnId] = index - keyColumnIds.length;
return result;
}, {});
}, [keyColumnIds]);
export const SchemaViewer = ({className, type, path, withFamilies = false}: SchemaViewerProps) => {
const {data, loading} = useTypedSelector((state) => state.schema);
const currentObjectData = path ? data[path] : undefined;

let dataTableColumns: Column<TColumnDescription>[] = [
{
name: SchemaViewerColumns.id,
width: 40,
},
{
name: SchemaViewerColumns.key,
width: 40,
// Table should start with key columns on sort click
defaultOrder: DataTable.ASCENDING,
sortAccessor: (row) => {
// Values in keyColumnsOrderValues are always negative, so it will be 1 for not key columns
return (row.Id && keyColumnsOrderValues[row.Id]) || 1;
},
render: ({row}) => {
return row.Id && keyColumnIds.includes(row.Id) ? (
<div className={b('key-icon')}>
<Icon name="key" viewBox="0 0 12 7" width={12} height={7} />
</div>
) : null;
},
},
{
name: SchemaViewerColumns.name,
width: 100,
},
{
name: SchemaViewerColumns.type,
width: 100,
},
{
name: SchemaViewerColumns.notNull,
width: 100,
// Table should start with notNull columns on sort click
defaultOrder: DataTable.DESCENDING,
render: ({row}) => {
if (row.NotNull) {
return '\u2713';
}

return undefined;
},
},
];

if (isExternalTable(type)) {
// External tables don't have key columns
dataTableColumns = dataTableColumns.filter(
(column) => column.name !== SchemaViewerColumns.key,
);
}
const {columns, keyColumnIds} = prepareColumnDescriptions(type, currentObjectData);
const families = prepareFamilies(currentObjectData);

return (
<div className={b()}>
<DataTable
theme="yandex-cloud"
data={columns}
columns={dataTableColumns}
settings={DEFAULT_TABLE_SETTINGS}
initialSortOrder={{columnId: SchemaViewerColumns.key, order: DataTable.ASCENDING}}
/>
<div className={b(null, className)}>
{loading ? (
<TableSkeleton />
) : (
<DataTable
theme="yandex-cloud"
data={columns}
columns={prepareSchemaTableColumns({
type,
b,
families,
keyColumnIds,
withFamilies,
})}
settings={DEFAULT_TABLE_SETTINGS}
initialSortOrder={{
columnId: SchemaViewerColumns.key,
order: DataTable.ASCENDING,
}}
/>
)}
</div>
);
};

export default SchemaViewer;
Loading