Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: rework overview pane in schema browser #954

Merged
merged 7 commits into from
Jun 28, 2024
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
21 changes: 17 additions & 4 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
"root": true,
"overrides": [
{
"files": ["config-overrides.js", "commitlint.config.js"],
"files": [
"config-overrides.js",
"commitlint.config.js"
],
"env": {
"node": true,
},
Expand All @@ -17,10 +20,20 @@
"project": "./tsconfig.json",
},
"rules": {
"import/consistent-type-specifier-style": ["error", "prefer-top-level"],
"import/consistent-type-specifier-style": [
"error",
"prefer-top-level"
],
"@typescript-eslint/consistent-type-imports": [
"error",
{"prefer": "type-imports", "fixStyle": "separate-type-imports"},
{
"prefer": "type-imports",
"fixStyle": "separate-type-imports"
},
],
"curly": [
"error",
"all"
],
},
}
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ yarn-debug.log*
yarn-error.log*

.env


embedded-ui.tar.bz2
31 changes: 0 additions & 31 deletions src/components/InfoViewer/schemaOverview/CDCStreamOverview.tsx

This file was deleted.

This file was deleted.

2 changes: 0 additions & 2 deletions src/components/InfoViewer/schemaOverview/index.ts

This file was deleted.

201 changes: 140 additions & 61 deletions src/containers/Tenant/ObjectSummary/ObjectSummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,28 @@ import {StringParam, useQueryParam} from 'use-query-params';
import {AsyncReplicationState} from '../../../components/AsyncReplicationState';
import {ClipboardButton} from '../../../components/ClipboardButton';
import InfoViewer from '../../../components/InfoViewer/InfoViewer';
import {
CDCStreamOverview,
PersQueueGroupOverview,
} from '../../../components/InfoViewer/schemaOverview';
import type {InfoViewerItem} from '../../../components/InfoViewer/InfoViewer';
import {LinkWithIcon} from '../../../components/LinkWithIcon/LinkWithIcon';
import {Loader} from '../../../components/Loader';
import SplitPane from '../../../components/SplitPane';
import routes, {createHref} from '../../../routes';
import {getEntityName} from '../../../containers/Tenant/utils';
import routes, {createExternalUILink, createHref} from '../../../routes';
import {schemaApi, setShowPreview} from '../../../store/reducers/schema/schema';
import {
TENANT_PAGES_IDS,
TENANT_QUERY_TABS_ID,
TENANT_SUMMARY_TABS_IDS,
} from '../../../store/reducers/tenant/constants';
import {setQueryTab, setSummaryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
import type {EPathSubType} from '../../../types/api/schema';
import {EPathType} from '../../../types/api/schema';
import {EPathSubType, EPathType} from '../../../types/api/schema';
import {cn} from '../../../utils/cn';
import {
DEFAULT_IS_TENANT_COMMON_INFO_COLLAPSED,
DEFAULT_SIZE_TENANT_SUMMARY_KEY,
} from '../../../utils/constants';
import {formatDateTime} from '../../../utils/dataFormatters/dataFormatters';
import {formatDateTime, formatSecondsToHours} from '../../../utils/dataFormatters/dataFormatters';
import {useTypedDispatch, useTypedSelector} from '../../../utils/hooks';
import {Acl} from '../Acl/Acl';
import {ExternalDataSourceSummary} from '../Info/ExternalDataSource/ExternalDataSource';
import {ExternalTableSummary} from '../Info/ExternalTable/ExternalTable';
import {SchemaTree} from '../Schema/SchemaTree/SchemaTree';
import {SchemaViewer} from '../Schema/SchemaViewer/SchemaViewer';
import {TENANT_INFO_TABS, TENANT_SCHEMA_TAB, TenantTabsGroups} from '../TenantPages';
Expand Down Expand Up @@ -137,65 +133,148 @@ export function ObjectSummary({
};

const renderObjectOverview = () => {
const startTimeInMilliseconds = Number(currentSchemaData?.CreateStep);
const createdAt = startTimeInMilliseconds
? formatDateTime(startTimeInMilliseconds)
: 'unknown';
const createdAtLabel = 'Created At';

// verbose mapping to guarantee a correct render for new path types
// TS will error when a new type is added but not mapped here
const pathTypeToComponent: Record<EPathType, (() => React.ReactNode) | undefined> = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about not to delete this mapping? I think it's rather useful when add a new type.
In the past it was a headache to remember all places where we need to add info about new type.

Copy link
Contributor Author

@walborn walborn Jun 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For old version we are creating a new component for any type separately. But I've rewrote the logic to have common info and adding addition info for certain type.

May be it is possible to rewrite with pathTypeToInfo function with Record<>, but I don't understand the meaning of this

if (!currentSchemaData) {
return undefined;
}
const {CreateStep, PathType, PathSubType, PathId, PathVersion} = currentSchemaData;

const overview: InfoViewerItem[] = [];

overview.push({label: i18n('summary.type'), value: PathType?.replace(/^EPathType/, '')});

if (PathSubType !== EPathSubType.EPathSubTypeEmpty) {
overview.push({
label: i18n('summary.subtype'),
value: PathSubType?.replace(/^EPathSubType/, ''),
});
}

overview.push({label: i18n('summary.id'), value: PathId});

overview.push({label: i18n('summary.version'), value: PathVersion});

overview.push({
label: i18n('summary.created'),
value: formatDateTime(CreateStep, ''),
});

const {PathDescription} = currentObjectData;
const title = getEntityName(PathDescription);

const getPathTypeOverview: Record<EPathType, (() => InfoViewerItem[]) | undefined> = {
[EPathType.EPathTypeInvalid]: undefined,
[EPathType.EPathTypeDir]: undefined,
[EPathType.EPathTypeTable]: undefined,
[EPathType.EPathTypeTable]: () => [
{
label: i18n('summary.partitions'),
value: PathDescription?.TablePartitions?.length,
},
],
[EPathType.EPathTypeSubDomain]: undefined,
[EPathType.EPathTypeTableIndex]: undefined,
[EPathType.EPathTypeExtSubDomain]: undefined,
[EPathType.EPathTypeColumnStore]: undefined,
[EPathType.EPathTypeColumnTable]: undefined,
[EPathType.EPathTypeCdcStream]: () => <CDCStreamOverview data={currentObjectData} />,
[EPathType.EPathTypePersQueueGroup]: () => (
<PersQueueGroupOverview data={currentObjectData} />
),
[EPathType.EPathTypeExternalTable]: () => (
<ExternalTableSummary data={currentObjectData} />
),
[EPathType.EPathTypeExternalDataSource]: () => (
<ExternalDataSourceSummary data={currentObjectData} />
),
[EPathType.EPathTypeExtSubDomain]: () => [
{
label: i18n('summary.paths'),
value: PathDescription?.DomainDescription?.PathsInside,
},
{
label: i18n('summary.shards'),
value: PathDescription?.DomainDescription?.ShardsInside,
},
],
[EPathType.EPathTypeColumnStore]: () => [
{
label: i18n('summary.partitions'),
value: PathDescription?.ColumnStoreDescription?.ColumnShards?.length,
},
],
[EPathType.EPathTypeColumnTable]: () => [
{
label: i18n('summary.partitions'),
value: PathDescription?.ColumnTableDescription?.Sharding?.ColumnShards?.length,
},
],
[EPathType.EPathTypeCdcStream]: () => {
const {Mode, Format} = PathDescription?.CdcStreamDescription || {};

return [
{
label: i18n('summary.mode'),
value: Mode?.replace(/^ECdcStreamMode/, ''),
},
{
label: i18n('summary.format'),
value: Format?.replace(/^ECdcStreamFormat/, ''),
},
];
},
[EPathType.EPathTypePersQueueGroup]: () => {
const pqGroup = PathDescription?.PersQueueGroup;
const value = pqGroup?.PQTabletConfig?.PartitionConfig?.LifetimeSeconds;

return [
{
label: i18n('summary.partitions'),
value: pqGroup?.Partitions?.length,
},
{
label: i18n('summary.retention'),
value: value && formatSecondsToHours(value),
},
];
},
[EPathType.EPathTypeExternalTable]: () => {
const pathToDataSource = createExternalUILink({
...queryParams,
schema: PathDescription?.ExternalTableDescription?.DataSourcePath,
});

const {SourceType, DataSourcePath} =
PathDescription?.ExternalTableDescription || {};

const dataSourceName = DataSourcePath?.match(/([^/]*)\/*$/)?.[1] || '';

return [
{label: i18n('summary.source-type'), value: SourceType},
{
label: i18n('summary.data-source'),
value: DataSourcePath && (
<span title={DataSourcePath}>
<LinkWithIcon title={dataSourceName || ''} url={pathToDataSource} />
</span>
),
},
];
},
[EPathType.EPathTypeExternalDataSource]: () => [
{
label: i18n('summary.source-type'),
value: PathDescription?.ExternalDataSourceDescription?.SourceType,
},
],
[EPathType.EPathTypeView]: undefined,
[EPathType.EPathTypeReplication]: () => (
<InfoViewer
info={[
{
label: createdAtLabel,
value: createdAt,
},
{
label: 'State',
value: (
<AsyncReplicationState
state={
currentObjectData?.PathDescription?.ReplicationDescription
?.State
}
/>
),
},
]}
/>
),
[EPathType.EPathTypeReplication]: () => {
const state = PathDescription?.ReplicationDescription?.State;

if (!state) {
return [];
}

return [
{
label: i18n('summary.state'),
value: <AsyncReplicationState state={state} />,
},
];
},
};

let component =
currentSchemaData?.PathType && pathTypeToComponent[currentSchemaData.PathType]?.();

if (!component) {
component = <InfoViewer info={[{label: createdAtLabel, value: createdAt}]} />;
}
const pathTypeOverview = (PathType && getPathTypeOverview[PathType]?.()) || [];
overview.push(...pathTypeOverview);

return component;
// filter all empty values in according this requirement
// https://github.com/ydb-platform/ydb-embedded-ui/issues/906
return <InfoViewer title={title} info={overview.filter((i) => i.value)} />;
};

const renderTabContent = () => {
Expand Down
19 changes: 14 additions & 5 deletions src/containers/Tenant/i18n/en.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
{
"page.title": "Database",

"pages.query": "Query",
"pages.diagnostics": "Diagnostics",

"acl.owner": "Owner",
"acl.empty": "No Acl data",

"summary.navigation": "Navigation",
"summary.showPreview": "Show preview",
"summary.source-type": "Source Type",
"summary.data-source": "Data Source",
"summary.copySchemaPath": "Copy schema path",

"summary.type": "Type",
"summary.subtype": "SubType",
"summary.id": "Id",
"summary.version": "Version",
"summary.created": "Created",
"summary.partitions": "Partitions count",
"summary.paths": "Paths",
"summary.shards": "Shards",
"summary.state": "State",
"summary.mode": "Mode",
"summary.format": "Format",
"summary.retention": "Retention",
"actions.copied": "The path is copied to the clipboard",
"actions.notCopied": "Couldn’t copy the path",

"actions.copyPath": "Copy path",
"actions.openPreview": "Open preview",
"actions.createTable": "Create table...",
Expand Down
Loading
Loading