Skip to content

Commit 49d26f7

Browse files
Merge branch 'main' into fix-streaming
2 parents faec50a + bff31a0 commit 49d26f7

File tree

14 files changed

+703
-194
lines changed

14 files changed

+703
-194
lines changed

package-lock.json

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

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@
166166
"react-dom": "$react-dom",
167167
"redux": "$redux",
168168
"typescript": "$typescript",
169-
"monaco-editor": "$monaco-editor"
169+
"monaco-editor": "$monaco-editor",
170+
"canvas": "^2.11.2"
170171
}
171172
}

rsbuild.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ export default defineConfig({
8383
sourceMap: {
8484
js: process.env.GENERATE_SOURCEMAP !== 'false' ? 'source-map' : false,
8585
},
86+
// Inline CSS in development to prevent FOUC
87+
injectStyles: process.env.NODE_ENV === 'development',
8688
},
8789
html: {
8890
template: './public/index.html',

src/containers/Authentication/Authentication.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,11 @@
8686
top: 40px;
8787
right: 40px;
8888
}
89+
&__general-error {
90+
width: 100%;
91+
height: var(--g-text-body-1-line-height);
92+
margin-top: var(--g-spacing-1);
93+
94+
color: var(--g-color-text-danger);
95+
}
8996
}

src/containers/Authentication/Authentication.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {basename} from '../../store';
99
import {authenticationApi} from '../../store/reducers/authentication/authentication';
1010
import {useLoginWithDatabase} from '../../store/reducers/capabilities/hooks';
1111
import {cn} from '../../utils/cn';
12+
import {prepareCommonErrorMessage} from '../../utils/errors';
1213
import {useMetaAuth} from '../../utils/hooks/useMetaAuth';
1314

1415
import {isDatabaseError, isPasswordError, isUserError} from './utils';
@@ -68,23 +69,28 @@ function Authentication({closable = false}: AuthenticationProps) {
6869
const [loginError, setLoginError] = React.useState('');
6970
const [passwordError, setPasswordError] = React.useState('');
7071
const [databaseError, setDatabaseError] = React.useState('');
72+
const [generalError, setGeneralError] = React.useState('');
7173
const [showPassword, setShowPassword] = React.useState(false);
7274

7375
const onLoginUpdate = (value: string) => {
7476
setLogin(value);
7577
setLoginError('');
78+
setGeneralError('');
7679
};
7780
const onDatabaseUpdate = (value: string) => {
7881
setDatabase(value);
7982
setDatabaseError('');
83+
setGeneralError('');
8084
};
8185

8286
const onPassUpdate = (value: string) => {
8387
setPass(value);
8488
setPasswordError('');
89+
setGeneralError('');
8590
};
8691

8792
const onLoginClick = () => {
93+
setGeneralError('');
8894
authenticate({user: login, password, database, useMeta})
8995
.unwrap()
9096
.then(() => {
@@ -93,6 +99,8 @@ function Authentication({closable = false}: AuthenticationProps) {
9399
}
94100
})
95101
.catch((error) => {
102+
const isInputError =
103+
isUserError(error) || isPasswordError(error) || isDatabaseError(error);
96104
if (isUserError(error)) {
97105
setLoginError(error.data.error);
98106
}
@@ -102,6 +110,11 @@ function Authentication({closable = false}: AuthenticationProps) {
102110
if (isDatabaseError(error)) {
103111
setDatabaseError(error.data.error);
104112
}
113+
114+
if (!isInputError) {
115+
const message = prepareCommonErrorMessage(error);
116+
setGeneralError(message);
117+
}
105118
});
106119
};
107120

@@ -184,6 +197,8 @@ function Authentication({closable = false}: AuthenticationProps) {
184197
>
185198
Sign in
186199
</Button>
200+
{/* always preserve place for general error to prevent container height jumping */}
201+
<div className={b('general-error')}>{generalError}</div>
187202
</form>
188203
{closable && history.length > 1 && (
189204
<Button onClick={onClose} className={b('close')}>

src/containers/Clusters/columns.tsx

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,18 @@ import {
1414

1515
import {EntityStatus} from '../../components/EntityStatusNew/EntityStatus';
1616
import {VersionsBar} from '../../components/VersionsBar/VersionsBar';
17-
import {getClusterPath} from '../../routes';
1817
import type {PreparedCluster} from '../../store/reducers/clusters/types';
1918
import {EFlag} from '../../types/api/enums';
2019
import {uiFactory} from '../../uiFactory/uiFactory';
2120
import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
2221
import {formatNumber, formatStorageValuesToTb} from '../../utils/dataFormatters/dataFormatters';
23-
import {createDeveloperUIMonitoringPageHref} from '../../utils/developerUI/developerUI';
2422
import {getCleanBalancerValue} from '../../utils/parseBalancer';
2523
import {clusterTabsIds} from '../Cluster/utils';
2624

2725
import {COLUMNS_NAMES, COLUMNS_TITLES} from './constants';
2826
import i18n from './i18n';
2927
import {b} from './shared';
28+
import {calculateClusterPath} from './utils';
3029
export const CLUSTERS_COLUMNS_WIDTH_LS_KEY = 'clustersTableColumnsWidth';
3130

3231
const EMPTY_CELL = <span className={b('empty-cell')}>{EMPTY_DATA_PLACEHOLDER}</span>;
@@ -144,23 +143,13 @@ interface ClusterNameProps {
144143
}
145144

146145
function ClusterName({row}: ClusterNameProps) {
147-
const {
148-
name: clusterName,
149-
use_embedded_ui: useEmbeddedUi,
150-
preparedBackend: backend,
151-
settings,
152-
} = row;
153-
const clusterPath =
154-
useEmbeddedUi && backend
155-
? createDeveloperUIMonitoringPageHref(backend)
156-
: getClusterPath(
157-
{environment: settings?.auth_service},
158-
{backend, clusterName},
159-
{withBasename: true},
160-
);
146+
const clusterPath = calculateClusterPath(row);
147+
161148
return (
162149
<div className={b('cluster-name')}>
163-
<ExternalLink href={clusterPath}>{row.title || row.name}</ExternalLink>
150+
<ExternalLink href={clusterPath} target={row.clusterDomain ? '_blank' : undefined}>
151+
{row.title || row.name}
152+
</ExternalLink>
164153
</div>
165154
);
166155
}
@@ -358,26 +347,17 @@ interface VersionsProps {
358347
}
359348

360349
function Versions({row}: VersionsProps) {
361-
const {
362-
preparedVersions,
363-
name: clusterName,
364-
preparedBackend: backend,
365-
settings,
366-
use_embedded_ui: useEmbeddedUi,
367-
} = row;
350+
const {preparedVersions} = row;
368351
if (!preparedVersions.length) {
369352
return null;
370353
}
371-
const clusterPath =
372-
useEmbeddedUi && backend
373-
? createDeveloperUIMonitoringPageHref(backend)
374-
: getClusterPath(
375-
{activeTab: clusterTabsIds.versions, environment: settings?.auth_service},
376-
{backend, clusterName},
377-
{withBasename: true},
378-
);
354+
const clusterPath = calculateClusterPath(row, clusterTabsIds.versions);
379355
return (
380-
<ExternalLink className={b('cluster-versions')} href={clusterPath}>
356+
<ExternalLink
357+
className={b('cluster-versions')}
358+
href={clusterPath}
359+
target={row.clusterDomain ? '_blank' : undefined}
360+
>
381361
<VersionsBar preparedVersions={preparedVersions} />
382362
</ExternalLink>
383363
);

src/containers/Clusters/utils.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {getClusterPath} from '../../routes';
2+
import type {PreparedCluster} from '../../store/reducers/clusters/types';
3+
import {createDeveloperUIMonitoringPageHref} from '../../utils/developerUI/developerUI';
4+
import type {ClusterTab} from '../Cluster/utils';
5+
6+
export function calculateClusterPath(row: PreparedCluster, activeTab?: ClusterTab): string {
7+
const {
8+
use_embedded_ui: useEmbeddedUi,
9+
preparedBackend: backend,
10+
name: clusterName,
11+
clusterDomain,
12+
settings,
13+
} = row;
14+
15+
if (useEmbeddedUi && backend) {
16+
return createDeveloperUIMonitoringPageHref(backend);
17+
}
18+
19+
return getClusterPath(
20+
{
21+
activeTab,
22+
environment: settings?.auth_service,
23+
},
24+
{backend, clusterName},
25+
{withBasename: true},
26+
clusterDomain,
27+
);
28+
}

src/routes.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export function createHref(
7171
params?: Record<string, string | number | undefined>,
7272
query: Query = {},
7373
options: CreateHrefOptions = {},
74+
domain = '',
7475
) {
7576
let extendedQuery = query;
7677
let extendedParams = params ?? {};
@@ -103,9 +104,10 @@ export function createHref(
103104
if (options.withBasename && basename) {
104105
// For SPA links react-router adds basename itself
105106
// It is needed for external links - <a> or uikit <Link>
106-
return normalizePathSlashes(`${basename}/${compiledRoute}`);
107+
return normalizePathSlashes(`${domain}${basename}/${compiledRoute}`);
107108
}
108-
return compiledRoute;
109+
110+
return `${domain}${compiledRoute}`;
109111
}
110112

111113
// embedded version could be located in some folder (e.g. host/some_folder/app_router_path)
@@ -150,8 +152,9 @@ export const getClusterPath = (
150152
params?: {activeTab?: ClusterTab; environment?: string},
151153
query = {},
152154
options?: CreateHrefOptions,
155+
domain?: string,
153156
) => {
154-
return createHref(routes.cluster, params, query, options);
157+
return createHref(routes.cluster, params, query, options, domain);
155158
};
156159

157160
export const getTenantPath = (query: TenantQuery, options?: CreateHrefOptions) => {

src/store/reducers/capabilities/capabilities.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ export const capabilitiesApi = api.injectEndpoints({
3030
} catch (error) {
3131
// If capabilities endpoint is not available, there will be an error
3232
// That means no new features are available
33-
return {error};
33+
// Serialize the error to make it Redux-compatible
34+
const serializedError =
35+
error instanceof Error ? {message: error.message, name: error.name} : error;
36+
return {error: serializedError};
3437
}
3538
},
3639
}),

src/store/reducers/cluster/parseFields.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ export function parseLoggingUrls(
6969

7070
const settingsSchema = z.object({
7171
use_meta_proxy: z.boolean().optional(),
72+
cluster_domain: z.string().optional(),
7273
});
7374

7475
export function parseSettingsField(

0 commit comments

Comments
 (0)