Skip to content

Commit

Permalink
feat: info and summary tabs for external objects (#493)
Browse files Browse the repository at this point in the history
  • Loading branch information
artemmufazalov authored Aug 4, 2023
1 parent f823378 commit 88d9041
Show file tree
Hide file tree
Showing 16 changed files with 273 additions and 14 deletions.
6 changes: 4 additions & 2 deletions src/components/InfoViewer/formatters/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import {formatDateTime} from '../../../utils';

import {createInfoFormatter} from '../utils';

import i18n from '../i18n';

export const formatCommonItem = createInfoFormatter<TDirEntry>({
values: {
PathType: (value) => value?.substring('EPathType'.length),
CreateStep: formatDateTime,
},
labels: {
PathType: 'Type',
CreateStep: 'Created',
PathType: i18n('common.type'),
CreateStep: i18n('common.created'),
},
});
4 changes: 4 additions & 0 deletions src/components/InfoViewer/i18n/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"common.created": "Created",
"common.type": "Type"
}
11 changes: 11 additions & 0 deletions src/components/InfoViewer/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {i18n, Lang} from '../../../utils/i18n';

import en from './en.json';
import ru from './ru.json';

const COMPONENT = 'ydb-components-info-viewer';

i18n.registerKeyset(Lang.En, COMPONENT, en);
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);

export default i18n.keyset(COMPONENT);
4 changes: 4 additions & 0 deletions src/components/InfoViewer/i18n/ru.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"common.created": "Создано",
"common.type": "Тип"
}
7 changes: 5 additions & 2 deletions src/containers/Tenant/Diagnostics/Overview/Overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ import {
isPathTypeWithTopic,
} from '../../utils/schema';

import {ExternalTableInfo} from '../../Info/ExternalTable/ExternalTable';
import {ExternalDataSourceInfo} from '../../Info/ExternalDataSource/ExternalDataSource';

import {TopicInfo} from './TopicInfo';
import {ChangefeedInfo} from './ChangefeedInfo';
import {TableInfo} from './TableInfo';
Expand Down Expand Up @@ -124,8 +127,8 @@ function Overview({type, tenantName}: OverviewProps) {
<ChangefeedInfo data={data} topic={additionalData?.[0]} />
),
[EPathType.EPathTypePersQueueGroup]: () => <TopicInfo data={data} />,
[EPathType.EPathTypeExternalTable]: undefined,
[EPathType.EPathTypeExternalDataSource]: undefined,
[EPathType.EPathTypeExternalTable]: () => <ExternalTableInfo data={data} />,
[EPathType.EPathTypeExternalDataSource]: () => <ExternalDataSourceInfo data={data} />,
};

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.ydb-external-data-source-info {
&__location {
max-width: var(--tenant-object-info-max-value-width);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import block from 'bem-cn-lite';

import type {TEvDescribeSchemeResult} from '../../../../types/api/schema';
import {useTypedSelector} from '../../../../utils/hooks';

import {InfoViewer, InfoViewerItem} from '../../../../components/InfoViewer';
import {formatCommonItem} from '../../../../components/InfoViewer/formatters';
import EntityStatus from '../../../../components/EntityStatus/EntityStatus';
import {ResponseError} from '../../../../components/Errors/ResponseError';

import {getEntityName} from '../../utils';

import i18n from '../i18n';
import './ExternalDataSource.scss';

const b = block('ydb-external-data-source-info');

const prepareExternalDataSourceSummary = (data: TEvDescribeSchemeResult): InfoViewerItem[] => {
return [
{
label: i18n('external-objects.source-type'),
value: data.PathDescription?.ExternalDataSourceDescription?.SourceType,
},
formatCommonItem('CreateStep', data.PathDescription?.Self?.CreateStep),
];
};

const prepareExternalDataSourceInfo = (data: TEvDescribeSchemeResult): InfoViewerItem[] => {
const {Location, Auth} = data.PathDescription?.ExternalDataSourceDescription || {};

return [
...prepareExternalDataSourceSummary(data),
{
label: i18n('external-objects.location'),
value: (
<EntityStatus
name={Location}
showStatus={false}
hasClipboardButton
clipboardButtonAlwaysVisible
className={b('location')}
/>
),
},
{
label: i18n('external-objects.auth-method'),
value: Auth?.ServiceAccount
? i18n('external-objects.auth-method.service-account')
: i18n('external-objects.auth-method.none'),
},
];
};

interface ExternalDataSourceProps {
data?: TEvDescribeSchemeResult;
prepareData: (data: TEvDescribeSchemeResult) => InfoViewerItem[];
}

const ExternalDataSource = ({data, prepareData}: ExternalDataSourceProps) => {
const entityName = getEntityName(data?.PathDescription);

const {error: schemaError} = useTypedSelector((state) => state.schema);

if (schemaError) {
return <ResponseError error={schemaError} />;
}

if (!data) {
return <div className="error">No {entityName} data</div>;
}

return <InfoViewer title={entityName} info={prepareData(data)} />;
};

export const ExternalDataSourceInfo = ({data}: {data?: TEvDescribeSchemeResult}) => {
return <ExternalDataSource data={data} prepareData={prepareExternalDataSourceInfo} />;
};

export const ExternalDataSourceSummary = ({data}: {data?: TEvDescribeSchemeResult}) => {
return <ExternalDataSource data={data} prepareData={prepareExternalDataSourceSummary} />;
};
5 changes: 5 additions & 0 deletions src/containers/Tenant/Info/ExternalTable/ExternalTable.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.ydb-external-table-info {
&__location {
max-width: var(--tenant-object-info-max-value-width);
}
}
103 changes: 103 additions & 0 deletions src/containers/Tenant/Info/ExternalTable/ExternalTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import {useLocation} from 'react-router';
import block from 'bem-cn-lite';

import type {TEvDescribeSchemeResult} from '../../../../types/api/schema';
import {useTypedSelector} from '../../../../utils/hooks';
import {createHref, parseQuery} from '../../../../routes';
import {formatCommonItem} from '../../../../components/InfoViewer/formatters';
import {InfoViewer, InfoViewerItem} from '../../../../components/InfoViewer';
import {ExternalLinkWithIcon} from '../../../../components/ExternalLinkWithIcon/ExternalLinkWithIcon';
import EntityStatus from '../../../../components/EntityStatus/EntityStatus';
import {ResponseError} from '../../../../components/Errors/ResponseError';

import {getEntityName} from '../../utils';

import i18n from '../i18n';
import './ExternalTable.scss';

const b = block('ydb-external-table-info');

const prepareExternalTableSummary = (
data: TEvDescribeSchemeResult,
pathToDataSource: string,
): InfoViewerItem[] => {
const {CreateStep} = data.PathDescription?.Self || {};
const {SourceType, DataSourcePath} = data.PathDescription?.ExternalTableDescription || {};

const dataSourceName = DataSourcePath?.split('/').pop();

return [
{label: i18n('external-objects.source-type'), value: SourceType},
formatCommonItem('CreateStep', CreateStep),
{
label: i18n('external-objects.data-source'),
value: DataSourcePath && (
<span title={DataSourcePath}>
<ExternalLinkWithIcon title={dataSourceName || ''} url={pathToDataSource} />
</span>
),
},
];
};

const prepareExternalTableInfo = (
data: TEvDescribeSchemeResult,
pathToDataSource: string,
): InfoViewerItem[] => {
const location = data.PathDescription?.ExternalTableDescription?.Location;

return [
...prepareExternalTableSummary(data, pathToDataSource),
{
label: i18n('external-objects.location'),
value: (
<EntityStatus
name={location}
showStatus={false}
hasClipboardButton
clipboardButtonAlwaysVisible
className={b('location')}
/>
),
},
];
};

interface ExternalTableProps {
data?: TEvDescribeSchemeResult;
prepareData: (data: TEvDescribeSchemeResult, pathToDataSource: string) => InfoViewerItem[];
}

const ExternalTable = ({data, prepareData}: ExternalTableProps) => {
const location = useLocation();
const query = parseQuery(location);

// embedded version could be located in some folder (e.g. host/some_folder/app_router_path)
// window.location has the full pathname, while location from router ignores path to project
const pathToDataSource = createHref(window.location.pathname, undefined, {
...query,
schema: data?.PathDescription?.ExternalTableDescription?.DataSourcePath,
});

const entityName = getEntityName(data?.PathDescription);

const {error: schemaError} = useTypedSelector((state) => state.schema);

if (schemaError) {
return <ResponseError error={schemaError} />;
}

if (!data) {
return <div className="error">No {entityName} data</div>;
}

return <InfoViewer title={entityName} info={prepareData(data, pathToDataSource)} />;
};

export const ExternalTableInfo = ({data}: {data?: TEvDescribeSchemeResult}) => {
return <ExternalTable data={data} prepareData={prepareExternalTableInfo} />;
};

export const ExternalTableSummary = ({data}: {data?: TEvDescribeSchemeResult}) => {
return <ExternalTable data={data} prepareData={prepareExternalTableSummary} />;
};
8 changes: 8 additions & 0 deletions src/containers/Tenant/Info/i18n/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"external-objects.source-type": "Source Type",
"external-objects.data-source": "Data Source",
"external-objects.location": "Location",
"external-objects.auth-method": "Auth Method",
"external-objects.auth-method.none": "None",
"external-objects.auth-method.service-account": "Service Account"
}
11 changes: 11 additions & 0 deletions src/containers/Tenant/Info/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {i18n, Lang} from '../../../../utils/i18n';

import en from './en.json';
import ru from './ru.json';

const COMPONENT = 'ydb-tenant-objects-info';

i18n.registerKeyset(Lang.En, COMPONENT, en);
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);

export default i18n.keyset(COMPONENT);
8 changes: 8 additions & 0 deletions src/containers/Tenant/Info/i18n/ru.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"external-objects.source-type": "Тип источника",
"external-objects.data-source": "Источник",
"external-objects.location": "Расположение",
"external-objects.auth-method": "Авторизация",
"external-objects.auth-method.none": "Нет",
"external-objects.auth-method.service-account": "Сервисный аккаунт"
}
8 changes: 4 additions & 4 deletions src/containers/Tenant/ObjectSummary/ObjectSummary.scss
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@
&__info-controls {
display: flex;
gap: 4px;

.yc-button__text {
margin: 0 6px;
}
}

&__info-action-button {
Expand Down Expand Up @@ -148,8 +152,4 @@
background-color: transparent;
}
}

.yc-button__text {
margin: 0 6px;
}
}
13 changes: 10 additions & 3 deletions src/containers/Tenant/ObjectSummary/ObjectSummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import {
import {SchemaTree} from '../Schema/SchemaTree/SchemaTree';
import {SchemaViewer} from '../Schema/SchemaViewer/SchemaViewer';
import {Acl} from '../Acl/Acl';
import {ExternalTableSummary} from '../Info/ExternalTable/ExternalTable';
import {ExternalDataSourceSummary} from '../Info/ExternalDataSource/ExternalDataSource';

import {TenantTabsGroups, TENANT_INFO_TABS, TENANT_SCHEMA_TAB} from '../TenantPages';
import {
Expand All @@ -50,9 +52,10 @@ import {
} from '../utils/paneVisibilityToggleHelpers';
import {isColumnEntityType, isExternalTable, isIndexTable, isTableType} from '../utils/schema';

import './ObjectSummary.scss';
import i18n from '../i18n';

import './ObjectSummary.scss';

const b = cn('object-summary');

const getInitialIsSummaryCollapsed = () => {
Expand Down Expand Up @@ -197,8 +200,12 @@ export function ObjectSummary({
[EPathType.EPathTypePersQueueGroup]: () => (
<PersQueueGroupOverview data={currentObjectData} />
),
[EPathType.EPathTypeExternalTable]: undefined,
[EPathType.EPathTypeExternalDataSource]: undefined,
[EPathType.EPathTypeExternalTable]: () => (
<ExternalTableSummary data={currentObjectData} />
),
[EPathType.EPathTypeExternalDataSource]: () => (
<ExternalDataSourceSummary data={currentObjectData} />
),
};

let component =
Expand Down
10 changes: 7 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './containers/App/App';
import {Provider} from 'react-redux';

import '@gravity-ui/uikit/styles/styles.scss';

import App from './containers/App/App';
import configureStore from './store';
import reportWebVitals from './reportWebVitals';
import '@gravity-ui/uikit/styles/styles.scss';
import HistoryContext from './contexts/HistoryContext';

import './styles/constants.scss';
import './index.css';

const {store, history} = configureStore();
window.store = store;

Expand Down
3 changes: 3 additions & 0 deletions src/styles/constants.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:root {
--tenant-object-info-max-value-width: 300px;
}

0 comments on commit 88d9041

Please sign in to comment.