Skip to content

Commit 3ea4aaa

Browse files
committed
Merge branch 'main' into kkdras.4002
2 parents cd98491 + 6fbc75f commit 3ea4aaa

124 files changed

Lines changed: 506 additions & 312 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
# See: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
44

55
# Global owners - these users will be requested for review on all PRs
6-
* @astandrik @Raubzeug @adameat @kkdras
6+
* @astandrik @Raubzeug @kkdras

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "18.0.0"
2+
".": "18.1.0"
33
}

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
# Changelog
22

3+
## [18.1.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v18.0.1...v18.1.0) (2026-07-10)
4+
5+
6+
### Features
7+
8+
* enable navigation v2 by default ([#4098](https://github.com/ydb-platform/ydb-embedded-ui/issues/4098)) ([228b8cf](https://github.com/ydb-platform/ydb-embedded-ui/commit/228b8cf6580a6ed8e29e27901df3d94795950813))
9+
10+
11+
### Bug Fixes
12+
13+
* **HeaderBreadcrumbs:** layout ([#4100](https://github.com/ydb-platform/ydb-embedded-ui/issues/4100)) ([0414ef6](https://github.com/ydb-platform/ydb-embedded-ui/commit/0414ef6b06a41f61b3b38d41272d242643d33325))
14+
* hide link to pDisk for database users ([#4111](https://github.com/ydb-platform/ydb-embedded-ui/issues/4111)) ([584e747](https://github.com/ydb-platform/ydb-embedded-ui/commit/584e7475211d463549efd1bc4e0dc922e98ac59c))
15+
* remove PostgreSQL query mode ([#4099](https://github.com/ydb-platform/ydb-embedded-ui/issues/4099)) ([38254a6](https://github.com/ydb-platform/ydb-embedded-ui/commit/38254a6220a36879c3d139ca6a8db355c6658229))
16+
17+
## [18.0.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v18.0.0...v18.0.1) (2026-07-10)
18+
19+
20+
### Bug Fixes
21+
22+
* **HomePage:** block databases if meta/whoami error ([#4101](https://github.com/ydb-platform/ydb-embedded-ui/issues/4101)) ([2ddb653](https://github.com/ydb-platform/ydb-embedded-ui/commit/2ddb653b1a474770c57b7c77f46066658c53259a))
23+
324
## [18.0.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v17.2.0...v18.0.0) (2026-07-08)
425

526

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ydb-embedded-ui",
3-
"version": "18.0.0",
3+
"version": "18.1.0",
44
"files": [
55
"dist"
66
],

src/components/LinkToSchemaObject/__test__/LinkToSchemaObject.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {LinkToSchemaObject} from '../LinkToSchemaObject';
1111

1212
jest.mock('../../../containers/Tenant/Diagnostics/DiagnosticsPages', () => ({
1313
useDiagnosticsPageLinkGetter: () => (_tab: string, params?: {schema?: string}) => {
14-
return `/tenant?schema=${encodeURIComponent(params?.schema ?? '')}`;
14+
return `/database?schema=${encodeURIComponent(params?.schema ?? '')}`;
1515
},
1616
}));
1717

@@ -79,7 +79,7 @@ describe('LinkToSchemaObject', () => {
7979

8080
expect(screen.getByRole('link', {name: 'Table'})).toHaveAttribute(
8181
'href',
82-
'/tenant?schema=%2FRoot%2FTable',
82+
'/database?schema=%2FRoot%2FTable',
8383
);
8484
});
8585
});

src/components/VDiskInfo/VDiskInfo.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
import {createVDiskDeveloperUILink, useHasDeveloperUi} from '../../utils/developerUI/developerUI';
1414
import {getDataSeverityColor} from '../../utils/disks/helpers';
1515
import type {PreparedVDisk} from '../../utils/disks/types';
16+
import {useIsViewerUser} from '../../utils/hooks/useIsUserAllowedToMakeChanges';
1617
import {bytesToSpeed} from '../../utils/utils';
1718
import {InternalLink} from '../InternalLink';
1819
import {LinkWithIcon} from '../LinkWithIcon/LinkWithIcon';
@@ -45,6 +46,7 @@ export function VDiskInfo<T extends PreparedVDisk>({
4546
wrap,
4647
}: VDiskInfoProps<T>) {
4748
const hasDeveloperUi = useHasDeveloperUi();
49+
const isViewerUser = useIsViewerUser();
4850

4951
const getVDiskPagePath = useVDiskPagePath();
5052

@@ -174,7 +176,8 @@ export function VDiskInfo<T extends PreparedVDisk>({
174176
rightColumn.push({name: vDiskInfoKeyset('slot-id'), content: VDiskSlotId});
175177
}
176178
if (!isNil(PDiskId)) {
177-
const pDiskPath = isNil(NodeId) ? undefined : getPDiskPagePath(PDiskId, NodeId);
179+
const pDiskPath =
180+
isViewerUser && !isNil(NodeId) ? getPDiskPagePath(PDiskId, NodeId) : undefined;
178181

179182
const content = pDiskPath ? <InternalLink to={pDiskPath}>{PDiskId}</InternalLink> : PDiskId;
180183

Lines changed: 60 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,77 @@
1-
import {render, screen} from '@testing-library/react';
2-
import {MemoryRouter} from 'react-router-dom';
1+
import {screen, waitFor} from '@testing-library/react';
2+
import {Router} from 'react-router-dom';
3+
import {QueryParamProvider} from 'use-query-params';
4+
import {ReactRouter5Adapter} from 'use-query-params/adapters/react-router-5';
35

6+
import {configureStore} from '../../../store';
47
import type {PreparedVDisk} from '../../../utils/disks/types';
8+
import {renderWithStore} from '../../../utils/tests/providers';
59
import {VDiskInfo} from '../VDiskInfo';
610

7-
jest.mock('../../../routes', () => ({
8-
getPDiskPagePath: (pDiskId: string | number, nodeId: string | number) =>
9-
`/pdisk-page?nodeId=${nodeId}&pDiskId=${pDiskId}`,
10-
useVDiskPagePath: () => () => '/vdisk-page',
11-
}));
11+
function renderWithWhoami({
12+
data,
13+
isViewerAllowed = true,
14+
withVDiskPageLink,
15+
}: {
16+
data: PreparedVDisk;
17+
isViewerAllowed?: boolean;
18+
withVDiskPageLink?: boolean;
19+
}) {
20+
const whoami = jest.fn().mockResolvedValue({IsViewerAllowed: isViewerAllowed});
21+
const api = {
22+
viewer: {
23+
whoami,
24+
},
25+
};
1226

13-
jest.mock('../../../utils/developerUI/developerUI', () => ({
14-
useHasDeveloperUi: () => false,
15-
}));
27+
const storeConfiguration = configureStore({api: api as never});
28+
29+
renderWithStore(
30+
<Router history={storeConfiguration.history}>
31+
<QueryParamProvider adapter={ReactRouter5Adapter}>
32+
<VDiskInfo data={data} withVDiskPageLink={withVDiskPageLink} />
33+
</QueryParamProvider>
34+
</Router>,
35+
{storeConfiguration},
36+
);
37+
38+
return {whoami};
39+
}
1640

1741
describe('VDiskInfo', () => {
1842
test('renders VDisk page link as an internal link', () => {
19-
render(
20-
<MemoryRouter>
21-
<VDiskInfo
22-
data={{NodeId: 1, StringifiedId: '1-2-3-4-5'} as PreparedVDisk}
23-
withVDiskPageLink
24-
/>
25-
</MemoryRouter>,
26-
);
43+
renderWithWhoami({
44+
data: {NodeId: 1, StringifiedId: '1-2-3-4-5'} as PreparedVDisk,
45+
withVDiskPageLink: true,
46+
});
2747

2848
const link = screen.getByRole('link', {name: /VDisk page/});
2949

30-
expect(link).toHaveAttribute('href', '/vdisk-page');
50+
expect(link).toHaveAttribute('href', '/vDisk?nodeId=1&vDiskId=1-2-3-4-5');
3151
expect(link).not.toHaveAttribute('target', '_blank');
3252
});
33-
test('renders PDisk id as an internal link when PDiskId and NodeId are defined', () => {
34-
render(
35-
<MemoryRouter>
36-
<VDiskInfo data={{NodeId: 1, PDiskId: 2} as PreparedVDisk} />
37-
</MemoryRouter>,
38-
);
3953

40-
const link = screen.getByRole('link', {name: '2'});
54+
test('renders PDisk id as an internal link when whoami allows viewer access', async () => {
55+
const {whoami} = renderWithWhoami({
56+
data: {NodeId: 1, PDiskId: 2} as PreparedVDisk,
57+
isViewerAllowed: true,
58+
});
59+
60+
const link = await screen.findByRole('link', {name: '2'});
61+
62+
expect(whoami).toHaveBeenCalledWith({database: undefined});
63+
expect(link).toHaveAttribute('href', '/pDisk?nodeId=1&pDiskId=2');
64+
});
65+
66+
test('renders PDisk id as plain text when whoami denies viewer access', async () => {
67+
const {whoami} = renderWithWhoami({
68+
data: {NodeId: 1, PDiskId: 2} as PreparedVDisk,
69+
isViewerAllowed: false,
70+
});
71+
72+
await waitFor(() => expect(whoami).toHaveBeenCalledWith({database: undefined}));
4173

42-
expect(link).toHaveAttribute('href', '/pdisk-page?nodeId=1&pDiskId=2');
74+
expect(screen.getByText('2')).toBeVisible();
75+
expect(screen.queryByRole('link', {name: '2'})).not.toBeInTheDocument();
4376
});
4477
});

src/containers/Header/Header.scss

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,23 @@
1212

1313
.g-breadcrumbs__item_current {
1414
height: min-content;
15+
16+
font-weight: var(--g-text-body-font-weight, inherit);
1517
}
1618

1719
&__breadcrumbs {
1820
display: flex;
1921
flex-grow: 1;
22+
23+
.g-breadcrumbs__divider {
24+
padding: 0 var(--g-spacing-1);
25+
}
26+
27+
&_has-home-item {
28+
> .g-breadcrumbs__item:first-child .g-breadcrumbs__divider {
29+
display: none;
30+
}
31+
}
2032
}
2133

2234
&__breadcrumbs-item {
@@ -29,6 +41,12 @@
2941
&_active {
3042
color: var(--g-color-text-primary);
3143
}
44+
45+
&_home {
46+
margin-right: 6px;
47+
48+
color: var(--g-color-text-primary);
49+
}
3250
}
3351

3452
&__breadcrumbs-icon {

src/containers/Header/HeaderBreadcrumbs.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,21 @@ interface HeaderBreadcrumbsProps {
1212
}
1313

1414
export function HeaderBreadcrumbs({breadcrumbItems, endContent}: HeaderBreadcrumbsProps) {
15+
const hasHomeItem = Boolean(breadcrumbItems[0]?.isHome);
16+
1517
return (
16-
<Breadcrumbs className={b('breadcrumbs')} endContent={endContent}>
18+
<Breadcrumbs
19+
className={b('breadcrumbs', {'has-home-item': hasHomeItem})}
20+
endContent={endContent}
21+
>
1722
{breadcrumbItems.map((item, index) => {
18-
const {icon, text, link} = item;
23+
const {icon, text, link, isHome} = item;
1924
const isLast = index === breadcrumbItems.length - 1;
2025

2126
return (
2227
<Breadcrumbs.Item
2328
key={index}
24-
className={b('breadcrumbs-item', {active: isLast})}
29+
className={b('breadcrumbs-item', {active: isLast, home: isHome})}
2530
disabled={isLast}
2631
>
2732
<BreadcrumbLink icon={icon} text={text} link={isLast ? undefined : link} />

0 commit comments

Comments
 (0)