mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
Merge branch 'devel' into CB-3555-view-byte-type-data-decoded
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
.bodyContent {
|
||||
composes: theme-background-surface theme-text-on-surface theme-typography from global;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
padding: 0 !important;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
composes: theme-background-surface theme-text-on-surface theme-typography from global;
|
||||
height: var(--app-height);
|
||||
display: flex;
|
||||
padding: 0 !important;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import { DNDProvider } from '@cloudbeaver/core-ui';
|
||||
import { useAppVersion } from '@cloudbeaver/core-version';
|
||||
|
||||
import style from './Body.m.css';
|
||||
import { useAppHeight } from './useAppHeight';
|
||||
|
||||
export const Body = observer(function Body() {
|
||||
// const serverConfigLoader = useResource(Body, ServerConfigResource, undefined);
|
||||
@@ -42,6 +43,8 @@ export const Body = observer(function Body() {
|
||||
document.documentElement.dataset.backendVersion = backendVersion;
|
||||
});
|
||||
|
||||
useAppHeight();
|
||||
|
||||
return (
|
||||
<DNDProvider>
|
||||
<Loader suspense>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2023 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { useLayoutEffect } from 'react';
|
||||
|
||||
import { throttle } from '@cloudbeaver/core-utils';
|
||||
|
||||
// we need it because 100vh cuts the bottom of the page on mobile devices
|
||||
const handleBodyHeight = throttle(() => {
|
||||
const doc = document.documentElement;
|
||||
doc.style.setProperty('--app-height', `${window.innerHeight}px`);
|
||||
}, 50);
|
||||
|
||||
export function useAppHeight() {
|
||||
useLayoutEffect(() => {
|
||||
handleBodyHeight();
|
||||
window.addEventListener('resize', handleBodyHeight);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleBodyHeight);
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
&.small {
|
||||
min-width: 404px;
|
||||
min-height: 262px;
|
||||
max-height: max(100vh - 48px, 262px);
|
||||
max-height: max(var(--app-height) - 48px, 262px);
|
||||
|
||||
&.fixedSize {
|
||||
width: 404px;
|
||||
@@ -34,7 +34,7 @@
|
||||
&.medium {
|
||||
min-width: 576px;
|
||||
min-height: 374px;
|
||||
max-height: max(100vh - 48px, 374px);
|
||||
max-height: max(var(--app-height) - 48px, 374px);
|
||||
|
||||
&.fixedSize {
|
||||
width: 576px;
|
||||
@@ -47,7 +47,7 @@
|
||||
&.large {
|
||||
min-width: 720px;
|
||||
min-height: 468px;
|
||||
max-height: max(100vh - 48px, 468px);
|
||||
max-height: max(var(--app-height) - 48px, 468px);
|
||||
|
||||
&.fixedSize {
|
||||
width: 720px;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
overflow: auto;
|
||||
|
||||
&.root {
|
||||
height: 100vh;
|
||||
height: var(--app-height);
|
||||
}
|
||||
}
|
||||
.errorInnerBlock {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.loader {
|
||||
height: 100vh;
|
||||
}
|
||||
height: var(--app-height);
|
||||
}
|
||||
|
||||
@@ -26,20 +26,21 @@ $mdc-theme-extra-property-values: (
|
||||
|
||||
$mdc-theme-property-values: map-merge($mdc-theme-property-values, $mdc-theme-extra-property-values);
|
||||
|
||||
$theme-class: "theme-#{$theme-name}";
|
||||
$theme-class: 'theme-#{$theme-name}';
|
||||
$theme-form-element-radius: 3px !default;
|
||||
$theme-group-element-radius: 4px !default;
|
||||
$theme-menu-bar-small-action-radius: 3px !default;
|
||||
$app-height: 100vh !default;
|
||||
|
||||
@mixin css-variables {
|
||||
.theme-form-element-radius {
|
||||
border-radius: $theme-form-element-radius;
|
||||
}
|
||||
|
||||
|
||||
.theme-group-element-radius {
|
||||
border-radius: $theme-group-element-radius;
|
||||
}
|
||||
|
||||
|
||||
.theme-menu-bar-small-action-radius {
|
||||
border-radius: $theme-menu-bar-small-action-radius;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2023 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
export function formatNumber(n: number, d: number) {
|
||||
if (n < 1000) {
|
||||
return n.toString();
|
||||
}
|
||||
|
||||
const numStr = n.toString();
|
||||
const exponent = numStr.length - (numStr.length % 3);
|
||||
|
||||
const power = Math.pow(10, d);
|
||||
const rounded = Math.round((n * power) / Math.pow(10, exponent)) / power;
|
||||
|
||||
const units = ' kMBTPE';
|
||||
const unit = units[exponent / 3];
|
||||
|
||||
return rounded + unit;
|
||||
}
|
||||
@@ -70,3 +70,4 @@ export * from './removeMetadataFromBase64';
|
||||
export * from './renamePathName';
|
||||
export * from './removeLineBreak';
|
||||
export * from './replaceSubstring';
|
||||
export * from './formatNumber';
|
||||
|
||||
+32
-1
@@ -6,7 +6,38 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
.staticImage {
|
||||
.hasMoreIndicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
background-color: var(--theme-primary);
|
||||
color: var(--theme-on-primary);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.staticImage,
|
||||
.hasMoreIndicator {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.menu {
|
||||
flex-direction: row !important;
|
||||
}
|
||||
|
||||
.menuItem {
|
||||
cursor: auto !important;
|
||||
}
|
||||
|
||||
.menuButton {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
+41
-5
@@ -7,14 +7,18 @@
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { Fragment } from 'react';
|
||||
import { Menu, MenuButton, MenuItem, useMenuState } from 'reakit';
|
||||
import styled from 'reshadow';
|
||||
|
||||
import { AUTH_PROVIDER_LOCAL_ID } from '@cloudbeaver/core-authentication';
|
||||
import { PlaceholderComponent, s, StaticImage, useS, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { BASE_DROPDOWN_STYLES, PlaceholderComponent, s, StaticImage, useS, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import type { ObjectOrigin } from '@cloudbeaver/core-sdk';
|
||||
|
||||
import type { IUserDetailsInfoProps } from '../UsersAdministrationService';
|
||||
import style from './UserCredentialsList.m.css';
|
||||
|
||||
const MAX_VISIBLE_CREDENTIALS = 3;
|
||||
|
||||
interface IUserCredentialsProps {
|
||||
origin: ObjectOrigin;
|
||||
className?: string;
|
||||
@@ -32,11 +36,43 @@ export const UserCredentials = observer<IUserCredentialsProps>(function UserCred
|
||||
});
|
||||
|
||||
export const UserCredentialsList: PlaceholderComponent<IUserDetailsInfoProps> = observer(function UserCredentialsList({ user }) {
|
||||
return (
|
||||
const styles = useS(style);
|
||||
const translate = useTranslate();
|
||||
const menu = useMenuState({
|
||||
placement: 'top',
|
||||
gutter: 8,
|
||||
});
|
||||
|
||||
const visibleCredentials = user.origins.slice(0, MAX_VISIBLE_CREDENTIALS);
|
||||
|
||||
return styled(BASE_DROPDOWN_STYLES)(
|
||||
<Fragment key="user-credentials-list">
|
||||
{user.origins.map(origin => (
|
||||
<UserCredentials key={origin.type + origin.subType} origin={origin} />
|
||||
{visibleCredentials.map(origin => (
|
||||
<UserCredentials key={`${origin.type}${origin.subType ?? ''}`} origin={origin} />
|
||||
))}
|
||||
</Fragment>
|
||||
|
||||
{user.origins.length > MAX_VISIBLE_CREDENTIALS && (
|
||||
<>
|
||||
<MenuButton {...menu} className={s(styles, { menuButton: true })}>
|
||||
<div className={s(styles, { hasMoreIndicator: true })}>
|
||||
<span>+{user.origins.length - MAX_VISIBLE_CREDENTIALS}</span>
|
||||
</div>
|
||||
</MenuButton>
|
||||
|
||||
<Menu className={s(styles, { menu: true })} {...menu} modal>
|
||||
{user.origins.slice(MAX_VISIBLE_CREDENTIALS).map(origin => {
|
||||
const isLocal = origin.type === AUTH_PROVIDER_LOCAL_ID;
|
||||
const title = isLocal ? translate('authentication_administration_user_local') : origin.displayName;
|
||||
|
||||
return (
|
||||
<MenuItem key={`${origin.type}${origin.subType ?? ''}`} className={s(styles, { menuItem: true })} title={title}>
|
||||
<UserCredentials origin={origin} />
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
</>
|
||||
)}
|
||||
</Fragment>,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.wrapper {
|
||||
min-height: 520px !important;
|
||||
max-height: max(100vh - 48px, 520px) !important;
|
||||
max-height: max(var(--app-height) - 48px, 520px) !important;
|
||||
}
|
||||
.submittingForm {
|
||||
overflow: auto;
|
||||
|
||||
@@ -17,5 +17,10 @@ export {
|
||||
interpolateRound,
|
||||
axisBottom,
|
||||
axisLeft,
|
||||
scaleOrdinal,
|
||||
pie,
|
||||
arc,
|
||||
schemeTableau10,
|
||||
sum,
|
||||
} from 'd3';
|
||||
export type { Selection, ZoomBehavior, Line, DragBehavior, SubjectPosition } from 'd3';
|
||||
export type { Selection, ZoomBehavior, Line, DragBehavior, SubjectPosition, PieArcDatum, ScaleOrdinal } from 'd3';
|
||||
|
||||
Reference in New Issue
Block a user