CB-3860 migrate dialog to css modules (#1994)

* CB-3860 migrate dialog to css modules

* CB-3860 refactor all dialogs styles

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
This commit is contained in:
alex
2023-09-13 16:39:27 +03:00
committed by GitHub
co-authored by mr-anton-t
parent 7ea8befbe4
commit 320d7e84ee
63 changed files with 838 additions and 895 deletions
@@ -0,0 +1,3 @@
.fill {
flex: 1;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* 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 style from './Fill.m.css';
import { s } from './s';
import { useS } from './useS';
interface Props {
className?: string;
}
export const Fill: React.FC<Props> = function Fill({ className }) {
const styles = useS(style);
return <div className={s(styles, { fill: true }, className)} />;
};
+1
View File
@@ -119,6 +119,7 @@ export * from './FormControls/Checkboxes/useCheckboxState';
export * from './FormControls/BASE_DROPDOWN_STYLES';
export * from './FormControls/FormBox';
export * from './FormControls/Filter';
export * from './Fill';
export * from './Containers/Container';
export * from './Containers/Group';
@@ -0,0 +1,61 @@
.body {
flex: 1;
box-sizing: content-box;
display: flex;
max-height: 100%;
overflow: auto;
padding-top: 0px;
padding-right: 0px;
flex-shrink: 0;
padding: 24px;
&.noBodyPadding {
padding: 0px;
}
padding-top: 0px;
padding-right: 0px;
&.noBodyPadding + footer {
padding-top: 24px;
}
&.noBodyPadding .dialogBodyOverflowBox {
padding-right: 0px;
}
&.noOverflow .dialogBodyContent {
overflow: auto;
}
}
.dialogBodyOverflow {
composes: branding-overflow from global;
position: sticky;
bottom: 0;
left: 0;
flex-shrink: 0;
width: 100%;
height: 24px;
pointer-events: none;
}
.dialogBodyOverflowBox {
position: relative;
flex: 1;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow: auto;
word-break: break-word;
white-space: pre-wrap;
padding-right: 24px;
}
.dialogBodyContent {
flex: 1;
position: relative;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
@@ -6,13 +6,11 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { use } from 'reshadow';
import { useStyles } from '@cloudbeaver/core-blocks';
import { s, useS } from '@cloudbeaver/core-blocks';
import type { ComponentStyle } from '@cloudbeaver/core-theming';
import { dialogStyles } from '../styles';
import { commonDialogBaseStyle, commonDialogThemeStyle } from './styles';
import styles from './CommonDialogBody.m.css';
interface Props {
noBodyPadding?: boolean;
@@ -23,12 +21,14 @@ interface Props {
}
export const CommonDialogBody = observer<Props>(function CommonDialogBody({ noBodyPadding, noOverflow, className, children, style }) {
return styled(useStyles(commonDialogThemeStyle, commonDialogBaseStyle, dialogStyles, style))(
<dialog-body className={className} {...use({ 'no-padding': noBodyPadding, 'no-overflow': noOverflow })}>
<dialog-body-overflow-box>
<dialog-body-content>{children}</dialog-body-content>
{!noOverflow && <dialog-body-overflow />}
</dialog-body-overflow-box>
</dialog-body>,
const computedStyles = useS(styles, style);
return (
<div className={s(computedStyles, { body: true, noBodyPadding, noOverflow }, className)}>
<div className={s(computedStyles, { dialogBodyOverflowBox: true })}>
<div className={s(computedStyles, { dialogBodyContent: true })}>{children}</div>
{!noOverflow && <div className={s(computedStyles, { dialogBodyOverflow: true })} />}
</div>
</div>
);
});
@@ -0,0 +1,11 @@
.footer {
flex-shrink: 0;
padding: 0 24px 24px 24px;
display: flex;
z-index: 0;
box-sizing: border-box;
&:empty {
display: none;
}
}
@@ -6,13 +6,11 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled from 'reshadow';
import { useStyles } from '@cloudbeaver/core-blocks';
import { s, useS } from '@cloudbeaver/core-blocks';
import type { ComponentStyle } from '@cloudbeaver/core-theming';
import { dialogStyles } from '../styles';
import { commonDialogBaseStyle, commonDialogThemeStyle } from './styles';
import styles from './CommonDialogFooter.m.css';
interface Props {
className?: string;
@@ -21,5 +19,7 @@ interface Props {
}
export const CommonDialogFooter = observer<Props>(function CommonDialogFooter({ children, className, style }) {
return styled(useStyles(commonDialogThemeStyle, commonDialogBaseStyle, dialogStyles, style))(<footer className={className}>{children}</footer>);
const computedStyles = useS(styles, style);
return <footer className={s(computedStyles, { footer: true }, className)}>{children}</footer>;
});
@@ -0,0 +1,58 @@
.header {
position: relative;
display: grid;
grid-template-columns: max-content 1fr;
flex-shrink: 0;
padding: 24px;
&.noPadding {
padding: 0px;
}
}
.headerTitleContainer {
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
min-height: 24px;
overflow: hidden;
}
.headerTitle {
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.iconContainer {
display: flex;
align-items: center;
justify-content: center;
}
.icon {
width: 24px;
height: 24px;
margin-right: 16px;
&.bigIcon {
width: 40px;
height: 40px;
}
}
.subTitle {
composes: theme-typography--caption from global;
grid-column: 2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.reject {
cursor: pointer;
width: 18px;
height: 18px;
flex-shrink: 0;
}
@@ -6,13 +6,11 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { use } from 'reshadow';
import { Icon, IconOrImage, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
import { Icon, IconOrImage, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
import type { ComponentStyle } from '@cloudbeaver/core-theming';
import { dialogStyles } from '../styles';
import { commonDialogBaseStyle, commonDialogThemeStyle } from './styles';
import styles from './CommonDialogHeader.m.css';
interface Props {
title?: string;
@@ -38,19 +36,22 @@ export const CommonDialogHeader = observer<Props>(function CommonDialogHeader({
style,
}) {
const translate = useTranslate();
const computedStyles = useS(styles, style);
return styled(useStyles(commonDialogThemeStyle, commonDialogBaseStyle, dialogStyles, style))(
<header title={tooltip} className={className}>
<icon-container>{icon && <IconOrImage {...use({ bigIcon })} icon={icon} viewBox={viewBox} />}</icon-container>
<header-title>
<h3>{translate(title)}</h3>
return (
<header title={tooltip} className={s(computedStyles, { header: true }, className)}>
<div className={s(computedStyles, { iconContainer: true })}>
{icon && <IconOrImage className={s(computedStyles, { icon: true, bigIcon })} icon={icon} viewBox={viewBox} />}
</div>
<div className={s(computedStyles, { headerTitleContainer: true })}>
<h3 className={s(computedStyles, { headerTitle: true })}>{translate(title)}</h3>
{onReject && (
<reject>
<div className={s(computedStyles, { reject: true })}>
<Icon name="cross" viewBox="0 0 16 16" onClick={onReject} />
</reject>
</div>
)}
</header-title>
{subTitle && <sub-title>{typeof subTitle === 'string' ? translate(subTitle) : subTitle}</sub-title>}
</header>,
</div>
{subTitle && <div className={s(computedStyles, { subTitle: true })}>{typeof subTitle === 'string' ? translate(subTitle) : subTitle}</div>}
</header>
);
});
@@ -0,0 +1,64 @@
.container {
box-sizing: border-box;
display: flex;
outline: none;
}
.dialog {
composes: theme-background-surface theme-text-on-surface theme-elevation-z10 from global;
border-radius: 0.25rem;
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
margin: 0;
border: none;
height: auto;
max-height: 100%;
max-width: 748px;
padding: 0px;
&.small {
min-width: 404px;
min-height: 262px;
max-height: max(100vh - 48px, 262px);
&.fixedSize {
width: 404px;
height: 262px;
}
&.fixedWidth {
width: 404px;
}
}
&.medium {
min-width: 576px;
min-height: 374px;
max-height: max(100vh - 48px, 374px);
&.fixedSize {
width: 576px;
height: 374px;
}
&.fixedWidth {
width: 576px;
}
}
&.large {
min-width: 720px;
min-height: 468px;
max-height: max(100vh - 48px, 468px);
&.fixedSize {
width: 720px;
height: 468px;
}
&.fixedWidth {
width: 720px;
}
}
}
.loader {
height: 100%;
}
@@ -8,14 +8,12 @@
import { observer } from 'mobx-react-lite';
import { forwardRef, useContext, useEffect } from 'react';
import { Dialog, useDialogState } from 'reakit/Dialog';
import styled, { use } from 'reshadow';
import { Loader, useStyles } from '@cloudbeaver/core-blocks';
import { Loader, s, useS } from '@cloudbeaver/core-blocks';
import type { ComponentStyle } from '@cloudbeaver/core-theming';
import { DialogContext } from '../DialogContext';
import { dialogStyles } from '../styles';
import { commonDialogBaseStyle, commonDialogThemeStyle } from './styles';
import styles from './CommonDialogWrapper.m.css';
export interface CommonDialogWrapperProps {
size?: 'small' | 'medium' | 'large';
@@ -29,6 +27,7 @@ export interface CommonDialogWrapperProps {
export const CommonDialogWrapper = observer<CommonDialogWrapperProps, HTMLDivElement>(
forwardRef(function CommonDialogWrapper({ size = 'medium', fixedSize, fixedWidth, 'aria-label': ariaLabel, className, children, style }, ref) {
const computedStyles = useS(styles, style);
const context = useContext(DialogContext);
const dialogState = useDialogState({ visible: true });
@@ -38,12 +37,28 @@ export const CommonDialogWrapper = observer<CommonDialogWrapperProps, HTMLDivEle
}
});
return styled(useStyles(commonDialogThemeStyle, commonDialogBaseStyle, dialogStyles, style))(
<Dialog {...dialogState} ref={ref} aria-label={ariaLabel} visible={context.visible} hideOnClickOutside={false} modal={false}>
<dialog className={className} {...use({ size, fixedSize, fixedWidth })}>
<Loader suspense>{children}</Loader>
return (
<Dialog
{...dialogState}
ref={ref}
aria-label={ariaLabel}
className={s(computedStyles, { container: true })}
visible={context.visible}
hideOnClickOutside={false}
modal={false}
>
<dialog
className={s(
computedStyles,
{ dialog: true, small: size === 'small', medium: size === 'medium', large: size === 'large', fixedSize, fixedWidth },
className,
)}
>
<Loader className={s(computedStyles, { loader: true })} suspense>
{children}
</Loader>
</dialog>
</Dialog>,
</Dialog>
);
}),
);
@@ -1,210 +0,0 @@
/*
* 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 { css } from 'reshadow';
import type { ThemeSelector } from '@cloudbeaver/core-theming';
export const commonDialogThemeStyle: ThemeSelector = async theme => {
let styles: any;
switch (theme) {
case 'dark':
styles = await import('./themes/dark.module.scss');
break;
default:
styles = await import('./themes/light.module.scss');
break;
}
return [styles.default];
};
export const commonDialogContainerStyles = css`
error,
dialog {
composes: theme-background-surface theme-text-on-surface theme-elevation-z10 from global;
border-radius: 0.25rem;
}
`;
export const commonDialogBaseStyle = [
commonDialogContainerStyles,
css`
dialog {
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
margin: 0;
border: none;
height: auto;
max-height: 100%;
max-width: 748px;
padding: 0px;
&[|size='small'] {
min-width: 404px;
min-height: 262px;
max-height: max(100vh - 48px, 262px);
&[|fixedSize] {
width: 404px;
height: 262px;
}
&[|fixedWidth] {
width: 404px;
}
}
&[|size='medium'] {
min-width: 576px;
min-height: 374px;
max-height: max(100vh - 48px, 374px);
&[|fixedSize] {
width: 576px;
height: 374px;
}
&[|fixedWidth] {
width: 576px;
}
}
&[|size='large'] {
min-width: 720px;
min-height: 468px;
max-height: max(100vh - 48px, 468px);
&[|fixedSize] {
width: 720px;
height: 468px;
}
&[|fixedWidth] {
width: 720px;
}
}
}
header,
dialog-body,
footer {
flex-shrink: 0;
padding: 24px;
&[|no-padding] {
padding: 0px;
}
}
dialog-body {
padding-top: 0px;
padding-right: 0px;
}
footer {
padding-top: 0px;
}
header {
position: relative;
display: grid;
grid-template-columns: max-content 1fr;
}
header-title {
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
min-height: 24px;
overflow: hidden;
}
icon-container {
display: flex;
align-items: center;
justify-content: center;
}
IconOrImage {
width: 24px;
height: 24px;
margin-right: 16px;
&[|bigIcon] {
width: 40px;
height: 40px;
}
}
dialog-body {
flex: 1;
box-sizing: content-box;
display: flex;
max-height: 100%;
overflow: auto;
}
dialog-body-overflow-box {
position: relative;
flex: 1;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow: auto;
word-break: break-word;
white-space: pre-wrap;
padding-right: 24px;
}
dialog-body-content {
flex: 1;
position: relative;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
Loader {
height: 100%;
}
dialog-body[|no-padding] + footer {
padding-top: 24px;
}
dialog-body[|no-padding] dialog-body-overflow-box {
padding-right: 0;
}
dialog-body[|no-overflow] dialog-body-content {
overflow: auto;
}
dialog-body-overflow {
composes: branding-overflow from global;
position: sticky;
bottom: 0;
left: 0;
flex-shrink: 0;
width: 100%;
height: 24px;
pointer-events: none;
}
h3 {
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
sub-title {
composes: theme-typography--caption from global;
grid-column: 2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
reject {
cursor: pointer;
width: 18px;
height: 18px;
flex-shrink: 0;
}
footer {
display: flex;
z-index: 0;
box-sizing: border-box;
&:empty {
display: none;
}
}
`,
];
@@ -1,15 +0,0 @@
/*
* 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.
*/
@mixin base-common-dialog() {
:global(.#{$theme-class}) {
dialog-body-overflow {
background-image: linear-gradient(to top, $mdc-theme-surface, rgba($mdc-theme-surface, 0));
}
}
}
@@ -1,12 +0,0 @@
/*
* 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 "@cloudbeaver/core-theming/src/styles/theme-dark";
@import "base-common-dialog";
@include base-common-dialog;
@@ -1,12 +0,0 @@
/*
* 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 "@cloudbeaver/core-theming/src/styles/theme-light";
@import "base-common-dialog";
@include base-common-dialog;
@@ -0,0 +1,4 @@
.footer {
align-items: center;
gap: 16px;
}
@@ -5,9 +5,7 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import styled, { css } from 'reshadow';
import { Button, Translate, useFocus, useStyles } from '@cloudbeaver/core-blocks';
import { Button, Fill, s, Translate, useFocus, useS } from '@cloudbeaver/core-blocks';
import type { TLocalizationToken } from '@cloudbeaver/core-localization';
import { CommonDialogBody } from './CommonDialog/CommonDialogBody';
@@ -15,17 +13,7 @@ import { CommonDialogFooter } from './CommonDialog/CommonDialogFooter';
import { CommonDialogHeader } from './CommonDialog/CommonDialogHeader';
import { CommonDialogWrapper } from './CommonDialog/CommonDialogWrapper';
import type { DialogComponent, DialogueStateResult } from './CommonDialogService';
const style = css`
CommonDialogFooter {
align-items: center;
gap: 16px;
}
fill {
flex: 1;
}
`;
import style from './ConfirmationDialog.m.css';
export interface ConfirmationDialogPayload {
icon?: string;
@@ -46,20 +34,21 @@ export const ConfirmationDialog: DialogComponent<ConfirmationDialogPayload, Dial
rejectDialog,
className,
}) {
const styles = useS(style);
const [focusedRef] = useFocus<HTMLDivElement>({ focusFirstChild: true });
const { icon, title, subTitle, bigIcon, viewBox, message, confirmActionText, cancelActionText } = payload;
return styled(useStyles(style))(
return (
<CommonDialogWrapper ref={focusedRef} size="small" className={className} fixedWidth>
<CommonDialogHeader title={title} subTitle={subTitle} icon={icon} viewBox={viewBox} bigIcon={bigIcon} onReject={rejectDialog} />
<CommonDialogBody>
<Translate token={message} />
</CommonDialogBody>
<CommonDialogFooter>
<CommonDialogFooter className={s(styles, { footer: true })}>
<Button type="button" mod={['outlined']} onClick={rejectDialog}>
<Translate token={cancelActionText || 'ui_processing_cancel'} />
</Button>
<fill />
<Fill />
{payload.extraStatus !== undefined && (
<Button type="button" mod={['outlined']} onClick={() => resolveDialog(payload.extraStatus)}>
<Translate token={cancelActionText || 'ui_no'} />
@@ -69,6 +58,6 @@ export const ConfirmationDialog: DialogComponent<ConfirmationDialogPayload, Dial
<Translate token={confirmActionText || 'ui_processing_ok'} />
</Button>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
};
@@ -0,0 +1,35 @@
.loader {
height: 100%;
}
.backdrop {
box-sizing: border-box;
background-color: rgba(0, 0, 0, 0.48);
/*backdrop-filter: blur(4px);
background-color: rgba(221, 221, 221, 0.25);*/
position: fixed;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
z-index: 999;
display: flex;
overflow: auto;
}
.innerBox {
display: flex;
margin: auto;
padding: 24px;
flex-direction: column;
align-items: center;
& > :not(:last-child) {
display: none;
}
}
.error {
composes: theme-background-surface theme-text-on-surface theme-elevation-z10 from global;
border-radius: 0.25rem;
}
@@ -8,18 +8,16 @@
import { observer } from 'mobx-react-lite';
import { useLayoutEffect, useMemo, useRef } from 'react';
import { DialogBackdrop } from 'reakit/Dialog';
import styled from 'reshadow';
import { ErrorBoundary, Loader, useObjectRef, useStyles } from '@cloudbeaver/core-blocks';
import { ErrorBoundary, Loader, s, useObjectRef, useS } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { commonDialogContainerStyles } from './CommonDialog/styles';
import { CommonDialogService, DialogInternal } from './CommonDialogService';
import { DialogContext, IDialogContext } from './DialogContext';
import { dialogStyles } from './styles';
import style from './DialogsPortal.m.css';
export const DialogsPortal = observer(function DialogsPortal() {
const styles = useStyles(dialogStyles);
const styles = useS(style);
const commonDialogService = useService(CommonDialogService);
const focusedElementRef = useRef<HTMLElement | null>(null);
@@ -81,12 +79,12 @@ export const DialogsPortal = observer(function DialogsPortal() {
};
}, [activeDialog]);
return styled(styles)(
<Loader suspense overlay>
<DialogBackdrop visible={!!activeDialog} onMouseDown={state.backdropClick}>
<inner-box>
return (
<Loader className={s(styles, { loader: true })} suspense overlay>
<DialogBackdrop className={s(styles, { backdrop: true })} visible={!!activeDialog} onMouseDown={state.backdropClick}>
<div className={s(styles, { innerBox: true })}>
{commonDialogService.dialogs.map((dialog, i, arr) => (
<ErrorBoundary key={dialog.id} styles={commonDialogContainerStyles} remount onClose={state.reject}>
<ErrorBoundary key={dialog.id} className={s(styles, { error: true })} remount onClose={state.reject}>
<NestedDialog
key={dialog.id}
visible={i === arr.length - 1}
@@ -96,9 +94,9 @@ export const DialogsPortal = observer(function DialogsPortal() {
/>
</ErrorBoundary>
))}
</inner-box>
</div>
</DialogBackdrop>
</Loader>,
</Loader>
);
});
@@ -0,0 +1,3 @@
.footer {
align-items: center;
}
@@ -8,9 +8,8 @@
import { observable } from 'mobx';
import { observer } from 'mobx-react-lite';
import { useEffect } from 'react';
import styled, { css } from 'reshadow';
import { Button, Container, InputField, SubmittingForm, useFocus, useObservableRef, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, Container, Fill, InputField, s, SubmittingForm, useFocus, useObservableRef, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { throttleAsync } from '@cloudbeaver/core-utils';
import { CommonDialogBody } from './CommonDialog/CommonDialogBody';
@@ -18,16 +17,7 @@ import { CommonDialogFooter } from './CommonDialog/CommonDialogFooter';
import { CommonDialogHeader } from './CommonDialog/CommonDialogHeader';
import { CommonDialogWrapper } from './CommonDialog/CommonDialogWrapper';
import type { DialogComponent } from './CommonDialogService';
const style = css`
CommonDialogFooter {
align-items: center;
}
fill {
flex: 1;
}
`;
import style from './RenameDialog.m.css';
interface IRenameDialogState {
value: string;
@@ -59,6 +49,7 @@ export const RenameDialog: DialogComponent<RenameDialogPayload, string> = observ
}) {
const translate = useTranslate();
const [focusedRef] = useFocus<HTMLFormElement>({ focusFirstChild: true });
const styles = useS(style);
const { icon, subTitle, bigIcon, viewBox, value, objectName, create, confirmActionText } = payload;
let { title } = payload;
@@ -102,7 +93,7 @@ export const RenameDialog: DialogComponent<RenameDialogPayload, string> = observ
const errorMessage = state.valid ? ' ' : translate(state.message ?? 'ui_rename_taken_or_invalid');
return styled(useStyles(style))(
return (
<CommonDialogWrapper size="small" className={className} fixedWidth>
<CommonDialogHeader title={title} subTitle={subTitle} icon={icon} viewBox={viewBox} bigIcon={bigIcon} onReject={rejectDialog} />
<CommonDialogBody>
@@ -114,15 +105,15 @@ export const RenameDialog: DialogComponent<RenameDialogPayload, string> = observ
</Container>
</SubmittingForm>
</CommonDialogBody>
<CommonDialogFooter>
<CommonDialogFooter className={s(styles, { footer: true })}>
<Button type="button" mod={['outlined']} onClick={rejectDialog}>
{translate('ui_processing_cancel')}
</Button>
<fill />
<Fill />
<Button type="button" mod={['unelevated']} disabled={!state.valid} onClick={() => resolveDialog(state.value)}>
{translate(confirmActionText || (create ? 'ui_create' : 'ui_rename'))}
</Button>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -1,43 +0,0 @@
/*
* 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 { css } from 'reshadow';
export const dialogStyles = css`
DialogBackdrop {
box-sizing: border-box;
background-color: rgba(0, 0, 0, 0.48);
/*backdrop-filter: blur(4px);
background-color: rgba(221, 221, 221, 0.25);*/
position: fixed;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
z-index: 999;
display: flex;
overflow: auto;
}
inner-box {
display: flex;
margin: auto;
padding: 24px;
flex-direction: column;
align-items: center;
& > :not(:last-child) {
display: none;
}
}
Dialog {
box-sizing: border-box;
display: flex;
outline: none;
}
`;
@@ -0,0 +1,27 @@
.code,
.message {
display: block;
white-space: pre-wrap;
}
.textarea {
min-height: 270px !important;
}
.message {
overflow: auto;
max-height: 96px;
}
.property {
padding: 8px 16px;
}
.errorDetails {
border: solid 1px;
}
.footer {
align-items: center;
justify-content: flex-end;
gap: 24px;
}
.errorInfoContainer {
display: flex;
flex-direction: column;
}
@@ -7,47 +7,51 @@
*/
import { observer } from 'mobx-react-lite';
import { useCallback, useMemo } from 'react';
import styled from 'reshadow';
import { Button, Iframe, Textarea, useClipboard, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, Iframe, s, Textarea, useClipboard, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs';
import style from './ErrorDetailsDialog.m.css';
import { ErrorModel, IErrorInfo } from './ErrorModel';
import { styles } from './styles';
function DisplayErrorInfo({ error }: { error: IErrorInfo }) {
return styled(useStyles(styles))(
const styles = useS(style);
return (
<>
<property>{error.isHtml ? <Iframe srcDoc={error.message} /> : <message>{error.message}</message>}</property>
<property className={s(styles, { property: true })}>
{error.isHtml ? <Iframe srcDoc={error.message} /> : <message className={s(styles, { message: true })}>{error.message}</message>}
</property>
{error.stackTrace && (
<property>
<Textarea value={error.stackTrace} style={styles} readOnly embedded />
<property className={s(styles, { property: true })}>
<Textarea className={s(styles, { textarea: true })} value={error.stackTrace} readOnly embedded />
</property>
)}
</>,
</>
);
}
export const ErrorDetailsDialog: DialogComponent<Error | string, null> = observer(function ErrorDetailsDialog(props) {
const translate = useTranslate();
const styles = useS(style);
const error = useMemo(() => new ErrorModel({ error: props.payload }), [props.payload]);
const copy = useClipboard();
const copyHandler = useCallback(() => copy(error.textToCopy, true), [error, copy]);
return styled(useStyles(styles))(
return (
<CommonDialogWrapper size="large">
<CommonDialogHeader title="core_eventsLog_dbeaverErrorDetails" icon="/icons/error_icon.svg" bigIcon onReject={props.rejectDialog} />
<CommonDialogBody>
{error.errors.map((error, id) => (
<div key={id}>
<div key={id} className={s(styles, { errorInfoContainer: true })}>
{id > 0 && <hr />}
<DisplayErrorInfo error={error} />
</div>
))}
</CommonDialogBody>
<CommonDialogFooter>
<CommonDialogFooter className={s(styles, { footer: true })}>
{error.textToCopy && (
<Button type="button" mod={['outlined']} onClick={copyHandler}>
{translate('ui_copy_to_clipboard')}
@@ -57,6 +61,6 @@ export const ErrorDetailsDialog: DialogComponent<Error | string, null> = observe
{translate('ui_close')}
</Button>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -1,34 +0,0 @@
/*
* 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 { css } from 'reshadow';
export const styles = css`
code,
message {
display: block;
white-space: pre-wrap;
}
textarea {
min-height: 270px !important;
}
message {
overflow: auto;
max-height: 96px;
}
property {
padding: 8px 16px;
}
error-details {
border: solid 1px;
}
CommonDialogFooter {
align-items: center;
justify-content: flex-end;
gap: 24px;
}
`;
@@ -0,0 +1,10 @@
.textarea {
width: 100% !important;
min-height: 250px;
box-sizing: border-box;
}
.footer {
align-items: center;
justify-content: flex-end;
gap: 24px;
}
@@ -7,9 +7,8 @@
*/
import { observer } from 'mobx-react-lite';
import { ChangeEvent, useCallback, useEffect, useRef, useState } from 'react';
import styled, { css } from 'reshadow';
import { Button, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
import {
CommonDialogBody,
CommonDialogFooter,
@@ -19,24 +18,14 @@ import {
DialogComponentProps,
} from '@cloudbeaver/core-dialogs';
const styles = css`
textarea {
width: 100% !important;
min-height: 250px;
box-sizing: border-box;
}
CommonDialogFooter {
align-items: center;
justify-content: flex-end;
gap: 24px;
}
`;
import style from './EditorDialog.m.css';
export const EditorDialog: DialogComponent<string, string> = observer(function EditorDialog({
payload,
resolveDialog,
rejectDialog,
}: DialogComponentProps<string, string>) {
const styles = useS(style);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const [value, setValue] = useState(payload);
const handleChange = useCallback((event: ChangeEvent<HTMLTextAreaElement>) => setValue(event.target.value), []);
@@ -47,13 +36,13 @@ export const EditorDialog: DialogComponent<string, string> = observer(function E
setTimeout(() => textareaRef.current?.focus(), 100);
}, []);
return styled(useStyles(styles))(
return (
<CommonDialogWrapper>
<CommonDialogHeader title="app_shared_inlineEditor_dialog_title" onReject={rejectDialog} />
<CommonDialogBody>
<textarea ref={textareaRef} value={value} onChange={handleChange} />
<textarea ref={textareaRef} className={s(styles, { textarea: true })} value={value} onChange={handleChange} />
</CommonDialogBody>
<CommonDialogFooter>
<CommonDialogFooter className={s(styles, { footer: true })}>
<Button type="button" mod={['outlined']} onClick={rejectDialog}>
{translate('app_shared_inlineEditor_dialog_cancel')}
</Button>
@@ -61,6 +50,6 @@ export const EditorDialog: DialogComponent<string, string> = observer(function E
{translate('app_shared_inlineEditor_dialog_apply')}
</Button>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
+4 -3
View File
@@ -19,9 +19,10 @@ interface Props extends Omit<TabListOptions, keyof TabStateReturn> {
'aria-label'?: string;
style?: ComponentStyle;
childrenFirst?: boolean;
className?: string;
}
export const TabList = observer<React.PropsWithChildren<Props>>(function TabList({ style, children, childrenFirst, ...props }) {
export const TabList = observer<React.PropsWithChildren<Props>>(function TabList({ style, className, children, childrenFirst, ...props }) {
const state = useContext(TabsContext);
if (!state) {
@@ -31,7 +32,7 @@ export const TabList = observer<React.PropsWithChildren<Props>>(function TabList
if (state.container) {
const displayed = state.container.getDisplayed(state.props);
return (
<BaseTabList {...props} {...state.state} area-label={props['aria-label'] ?? state.container.areaLabel}>
<BaseTabList {...props} {...state.state} className={className} area-label={props['aria-label'] ?? state.container.areaLabel}>
{childrenFirst && children}
{displayed
.map(
@@ -61,7 +62,7 @@ export const TabList = observer<React.PropsWithChildren<Props>>(function TabList
}
return (
<BaseTabList {...props} {...state.state}>
<BaseTabList {...props} className={className} {...state.state}>
{children}
</BaseTabList>
);
@@ -0,0 +1,40 @@
.wrapper {
min-height: 520px !important;
max-height: max(100vh - 48px, 520px) !important;
}
.submittingForm {
overflow: auto;
margin: auto;
}
.submittingForm,
.authProviderForm {
flex: 1;
display: flex;
flex-direction: column;
}
.tabList {
composes: theme-background-surface theme-text-on-surface from global;
justify-content: center;
position: sticky;
top: 0;
z-index: 1;
}
.tab {
&:global([aria-selected='true']) {
font-weight: 500 !important;
}
}
.authProviderForm {
flex-direction: column;
padding: 18px 24px;
}
.configurationsList {
overflow: auto;
margin-top: 12px;
margin-bottom: 12px;
max-height: 400px;
}
.errorMessage {
composes: theme-background-secondary theme-text-on-secondary from global;
flex: 1;
}
@@ -6,10 +6,21 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import styled from 'reshadow';
import { AuthProvider, AuthProviderConfiguration, UserInfoResource } from '@cloudbeaver/core-authentication';
import { ErrorMessage, getComputed, Link, SubmittingForm, TextPlaceholder, useErrorDetails, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
import {
ErrorMessage,
getComputed,
Link,
s,
SubmittingForm,
TextPlaceholder,
useErrorDetails,
useS,
useStyles,
useTranslate,
} from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import {
CommonDialogBody,
@@ -23,60 +34,19 @@ import { BASE_TAB_STYLES, Tab, TabList, TabsState, TabTitle, UNDERLINE_TAB_BIG_S
import { AuthenticationService } from '../AuthenticationService';
import type { IAuthOptions } from '../IAuthOptions';
import style from './AuthDialog.m.css';
import { AuthDialogFooter } from './AuthDialogFooter';
import { AuthProviderForm } from './AuthProviderForm/AuthProviderForm';
import { ConfigurationsList } from './AuthProviderForm/ConfigurationsList';
import { FEDERATED_AUTH } from './FEDERATED_AUTH';
import { getAuthProviderTabId, useAuthDialogState } from './useAuthDialogState';
const styles = css`
CommonDialogWrapper {
min-height: 520px !important;
max-height: max(100vh - 48px, 520px) !important;
}
SubmittingForm {
overflow: auto;
margin: auto;
}
SubmittingForm,
AuthProviderForm {
flex: 1;
display: flex;
flex-direction: column;
}
TabList {
composes: theme-background-surface theme-text-on-surface from global;
justify-content: center;
position: sticky;
top: 0;
z-index: 1;
}
Tab {
&:global([aria-selected='true']) {
font-weight: 500 !important;
}
}
AuthProviderForm {
flex-direction: column;
padding: 18px 24px;
}
ConfigurationsList {
overflow: auto;
margin-top: 12px;
margin-bottom: 12px;
max-height: 400px;
}
ErrorMessage {
composes: theme-background-secondary theme-text-on-secondary from global;
flex: 1;
}
`;
export const AuthDialog: DialogComponent<IAuthOptions, null> = observer(function AuthDialog({
payload: { providerId, configurationId, linkUser = false, accessRequest = false },
options,
rejectDialog,
}) {
const styles = useS(style);
const dialogData = useAuthDialogState(accessRequest, providerId, configurationId);
const errorDetails = useErrorDetails(dialogData.exception);
const authenticationService = useService(AuthenticationService);
@@ -171,14 +141,14 @@ export const AuthDialog: DialogComponent<IAuthOptions, null> = observer(function
);
}
return styled(useStyles(BASE_TAB_STYLES, styles, UNDERLINE_TAB_STYLES, UNDERLINE_TAB_BIG_STYLES))(
return styled(useStyles(BASE_TAB_STYLES, UNDERLINE_TAB_STYLES, UNDERLINE_TAB_BIG_STYLES))(
<TabsState
currentTabId={state.tabId}
onChange={tabData => {
state.setTabId(tabData.tabId);
}}
>
<CommonDialogWrapper size="large" aria-label={translate('authentication_login_dialog_title')}>
<CommonDialogWrapper className={s(styles, { wrapper: true })} size="large" aria-label={translate('authentication_login_dialog_title')}>
<CommonDialogHeader
title={dialogTitle}
tooltip={tooltip}
@@ -188,7 +158,7 @@ export const AuthDialog: DialogComponent<IAuthOptions, null> = observer(function
/>
<CommonDialogBody noBodyPadding>
{showTabs && (
<TabList aria-label="Auth providers">
<TabList className={s(styles, { tabList: true })} aria-label="Auth providers">
{dialogData.providers
.map(provider => {
if (provider.configurable) {
@@ -200,6 +170,7 @@ export const AuthDialog: DialogComponent<IAuthOptions, null> = observer(function
tabId={tabId}
title={configuration.displayName}
disabled={dialogData.authenticating}
className={s(styles, { tab: true })}
onClick={() => {
state.setActiveProvider(provider, configuration);
}}
@@ -215,6 +186,7 @@ export const AuthDialog: DialogComponent<IAuthOptions, null> = observer(function
tabId={provider.id}
title={provider.description || provider.label}
disabled={dialogData.authenticating}
className={s(styles, { tab: true })}
onClick={() => {
state.setActiveProvider(provider, null);
}}
@@ -229,6 +201,7 @@ export const AuthDialog: DialogComponent<IAuthOptions, null> = observer(function
key={FEDERATED_AUTH}
tabId={FEDERATED_AUTH}
title={translate('authentication_auth_federated')}
className={s(styles, { tab: true })}
disabled={dialogData.authenticating}
onClick={() => {
state.setActiveProvider(null, null);
@@ -246,11 +219,14 @@ export const AuthDialog: DialogComponent<IAuthOptions, null> = observer(function
activeConfiguration={state.activeConfiguration}
providers={dialogData.federatedProviders}
authTask={dialogData.authTask}
className={s(styles, { configurationsList: true })}
login={login}
onClose={rejectDialog}
/>
) : (
<SubmittingForm onSubmit={() => login(linkUser)}>{renderForm(state.activeProvider, state.activeConfiguration)}</SubmittingForm>
<SubmittingForm className={s(styles, { submittingForm: true })} onSubmit={() => login(linkUser)}>
{renderForm(state.activeProvider, state.activeConfiguration)}
</SubmittingForm>
)}
</CommonDialogBody>
{!federate && (
@@ -258,6 +234,7 @@ export const AuthDialog: DialogComponent<IAuthOptions, null> = observer(function
<AuthDialogFooter authAvailable={!dialogData.configure} isAuthenticating={dialogData.authenticating} onLogin={() => login(linkUser)}>
{errorDetails.name && (
<ErrorMessage
className={s(styles, { errorMessage: true })}
text={errorDetails.message || errorDetails.name}
hasDetails={errorDetails.hasDetails}
onShowDetails={errorDetails.open}
@@ -6,19 +6,13 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { Loader } from '@cloudbeaver/core-blocks';
import { Loader, s, useS } from '@cloudbeaver/core-blocks';
import { CommonDialogBody, CommonDialogHeader, CommonDialogWrapper } from '@cloudbeaver/core-dialogs';
import type { IDriver } from './Driver';
import { DriverSelector } from './DriverSelector';
const styles = css`
DriverSelector {
flex: 1;
}
`;
import styles from './DriverSelectorDialog.m.css';
interface IProps {
title: string;
@@ -29,13 +23,15 @@ interface IProps {
}
export const DriverSelectorDialog = observer<IProps>(function DriverSelectorDialog({ title, drivers, isLoading, onSelect, onClose }) {
return styled(styles)(
const style = useS(styles);
return (
<CommonDialogWrapper size="large" fixedSize>
<CommonDialogHeader title={title} onReject={onClose} />
<CommonDialogBody noBodyPadding noOverflow>
{isLoading && <Loader />}
{!isLoading && <DriverSelector drivers={drivers} onSelect={onSelect} />}
{!isLoading && <DriverSelector className={s(style, { driverSelector: true })} drivers={drivers} onSelect={onSelect} />}
</CommonDialogBody>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -0,0 +1,18 @@
.submittingForm,
.center {
display: flex;
flex: 1;
margin: auto;
}
.center {
box-sizing: border-box;
flex-direction: column;
align-items: center;
justify-content: center;
}
.connectionAuthenticationFormLoader {
align-content: center;
}
.errorMessage {
composes: theme-background-secondary theme-text-on-secondary from global;
}
@@ -6,39 +6,19 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { ErrorMessage, Loader, SubmittingForm, useAdministrationSettings, useFocus, useTranslate } from '@cloudbeaver/core-blocks';
import { ErrorMessage, Loader, s, SubmittingForm, useAdministrationSettings, useFocus, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { useController } from '@cloudbeaver/core-di';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs';
import { ConnectionAuthenticationFormLoader } from '@cloudbeaver/plugin-connections';
import { ConnectionController, ConnectionStep } from './ConnectionController';
import style from './ConnectionDialog.m.css';
import { ConnectionDialogFooter } from './ConnectionDialogFooter';
import { TemplateConnectionSelector } from './TemplateConnectionSelector/TemplateConnectionSelector';
const styles = css`
SubmittingForm,
center {
display: flex;
flex: 1;
margin: auto;
}
center {
box-sizing: border-box;
flex-direction: column;
align-items: center;
justify-content: center;
}
ConnectionAuthenticationFormLoader {
align-content: center;
}
ErrorMessage {
composes: theme-background-secondary theme-text-on-secondary from global;
}
`;
export const ConnectionDialog: DialogComponent<null, null> = observer(function ConnectionDialog({ rejectDialog }) {
const styles = useS(style);
const [focusedRef] = useFocus<HTMLFormElement>({ focusFirstChild: true });
const controller = useController(ConnectionController, rejectDialog);
const translate = useTranslate();
@@ -50,7 +30,7 @@ export const ConnectionDialog: DialogComponent<null, null> = observer(function C
subtitle = controller.template.name;
}
return styled(styles)(
return (
<CommonDialogWrapper size="large" fixedSize>
<CommonDialogHeader
title="basicConnection_connectionDialog_newConnection"
@@ -69,9 +49,11 @@ export const ConnectionDialog: DialogComponent<null, null> = observer(function C
)}
{controller.step === ConnectionStep.Connection &&
(!controller.authModel ? (
<center>{controller.isConnecting && translate('basicConnection_connectionDialog_connecting_message')}</center>
<center className={s(styles, { center: true })}>
{controller.isConnecting && translate('basicConnection_connectionDialog_connecting_message')}
</center>
) : (
<SubmittingForm ref={focusedRef} onSubmit={controller.onConnect}>
<SubmittingForm ref={focusedRef} className={s(styles, { submittingForm: true })} onSubmit={controller.onConnect}>
<ConnectionAuthenticationFormLoader
config={controller.config}
authModelId={controller.authModel.id}
@@ -79,6 +61,7 @@ export const ConnectionDialog: DialogComponent<null, null> = observer(function C
formId={controller.template?.id}
allowSaveCredentials={credentialsSavingEnabled}
disabled={controller.isConnecting}
className={s(styles, { connectionAuthenticationFormLoader: true })}
/>
</SubmittingForm>
))}
@@ -86,7 +69,12 @@ export const ConnectionDialog: DialogComponent<null, null> = observer(function C
{controller.step === ConnectionStep.Connection && (
<CommonDialogFooter>
{controller.responseMessage && (
<ErrorMessage text={controller.responseMessage} hasDetails={controller.hasDetails} onShowDetails={controller.onShowDetails} />
<ErrorMessage
text={controller.responseMessage}
className={s(styles, { errorMessage: true })}
hasDetails={controller.hasDetails}
onShowDetails={controller.onShowDetails}
/>
)}
<ConnectionDialogFooter
isConnecting={controller.isConnecting}
@@ -95,6 +83,6 @@ export const ConnectionDialog: DialogComponent<null, null> = observer(function C
/>
</CommonDialogFooter>
)}
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -0,0 +1,13 @@
.submittingForm {
overflow: auto;
margin: auto;
flex: 1;
display: flex;
flex-direction: column;
}
.connectionAuthenticationFormLoader {
align-content: center;
}
.button {
margin-left: auto;
}
@@ -6,31 +6,15 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { Button, SubmittingForm, useFocus, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, s, SubmittingForm, useFocus, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { useDBDriver } from '@cloudbeaver/core-connections';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs';
import type { ConnectionConfig } from '@cloudbeaver/core-sdk';
import style from './ConnectionAuthenticationDialog.m.css';
import { ConnectionAuthenticationFormLoader } from './ConnectionAuthenticationFormLoader';
const styles = css`
SubmittingForm {
overflow: auto;
margin: auto;
flex: 1;
display: flex;
flex-direction: column;
}
ConnectionAuthenticationFormLoader {
align-content: center;
}
Button {
margin-left: auto;
}
`;
interface Payload {
config: ConnectionConfig;
authModelId: string | null;
@@ -44,10 +28,11 @@ export const ConnectionAuthenticationDialog: DialogComponent<Payload> = observer
resolveDialog,
}) {
const translate = useTranslate();
const styles = useS(style);
const [focusedRef] = useFocus<HTMLFormElement>({ focusFirstChild: true });
const { driver } = useDBDriver(payload.driverId || '');
return styled(useStyles(styles))(
return (
<CommonDialogWrapper size="large">
<CommonDialogHeader
title="connections_connection_credentials_provisioning"
@@ -56,21 +41,22 @@ export const ConnectionAuthenticationDialog: DialogComponent<Payload> = observer
onReject={rejectDialog}
/>
<CommonDialogBody>
<SubmittingForm ref={focusedRef} onSubmit={() => resolveDialog()}>
<SubmittingForm ref={focusedRef} className={s(styles, { submittingForm: true })} onSubmit={() => resolveDialog()}>
<ConnectionAuthenticationFormLoader
config={payload.config}
authModelId={payload.authModelId}
networkHandlers={payload.networkHandlers}
formId={payload.config.connectionId || payload.driverId}
className={s(styles, { connectionAuthenticationFormLoader: true })}
hideFeatures={['nonSecuredProperty']}
/>
</SubmittingForm>
</CommonDialogBody>
<CommonDialogFooter>
<Button mod={['unelevated']} onClick={() => resolveDialog()}>
<Button mod={['unelevated']} className={s(styles, { button: true })} onClick={() => resolveDialog()}>
{translate('ui_apply')}
</Button>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -0,0 +1,14 @@
.submittingForm {
overflow: auto;
margin: auto;
flex: 1;
display: flex;
flex-direction: column;
}
.connectionAuthenticationFormLoader {
align-content: center;
}
.errorMessage {
composes: theme-background-secondary theme-text-on-secondary from global;
flex: 1;
}
@@ -6,34 +6,17 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { ErrorMessage, Loader, SubmittingForm, useAdministrationSettings, useFocus, useStyles } from '@cloudbeaver/core-blocks';
import { ErrorMessage, Loader, s, SubmittingForm, useAdministrationSettings, useFocus, useS } from '@cloudbeaver/core-blocks';
import { IConnectionInfoParams, useConnectionInfo, useDBDriver } from '@cloudbeaver/core-connections';
import { useController } from '@cloudbeaver/core-di';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs';
import { ConnectionAuthenticationFormLoader } from '../ConnectionAuthentication/ConnectionAuthenticationFormLoader';
import style from './DatabaseAuthDialog.m.css';
import { DBAuthDialogController } from './DBAuthDialogController';
import { DBAuthDialogFooter } from './DBAuthDialogFooter';
const styles = css`
SubmittingForm {
overflow: auto;
margin: auto;
flex: 1;
display: flex;
flex-direction: column;
}
ConnectionAuthenticationFormLoader {
align-content: center;
}
ErrorMessage {
composes: theme-background-secondary theme-text-on-secondary from global;
flex: 1;
}
`;
interface Payload {
connection: IConnectionInfoParams;
networkHandlers: string[];
@@ -43,6 +26,7 @@ interface Payload {
export const DatabaseAuthDialog: DialogComponent<Payload> = observer(function DatabaseAuthDialog({ payload, options, rejectDialog, resolveDialog }) {
const connection = useConnectionInfo(payload.connection);
const controller = useController(DBAuthDialogController, payload.connection, payload.networkHandlers, resolveDialog);
const styles = useS(style);
const { driver } = useDBDriver(connection.connectionInfo?.driverId || '');
const { credentialsSavingEnabled } = useAdministrationSettings();
@@ -54,7 +38,7 @@ export const DatabaseAuthDialog: DialogComponent<Payload> = observer(function Da
authModelId = connection.connectionInfo?.authModel || driver?.defaultAuthModel || null;
}
return styled(useStyles(styles))(
return (
<CommonDialogWrapper size="large">
<CommonDialogHeader
title="connections_database_authentication"
@@ -63,7 +47,7 @@ export const DatabaseAuthDialog: DialogComponent<Payload> = observer(function Da
onReject={options?.persistent ? undefined : rejectDialog}
/>
<CommonDialogBody>
<SubmittingForm ref={focusedRef} onSubmit={controller.login}>
<SubmittingForm ref={focusedRef} className={s(styles, { submittingForm: true })} onSubmit={controller.login}>
{!connection.isLoaded() || connection.isLoading() || !controller.configured ? (
<Loader />
) : (
@@ -74,6 +58,7 @@ export const DatabaseAuthDialog: DialogComponent<Payload> = observer(function Da
networkHandlers={payload.networkHandlers}
formId={`${payload.connection.projectId}:${payload.connection.connectionId}`}
allowSaveCredentials={credentialsSavingEnabled}
className={s(styles, { connectionAuthenticationFormLoader: true })}
disabled={controller.isAuthenticating}
hideFeatures={['nonSecuredProperty']}
/>
@@ -83,10 +68,15 @@ export const DatabaseAuthDialog: DialogComponent<Payload> = observer(function Da
<CommonDialogFooter>
<DBAuthDialogFooter isAuthenticating={controller.isAuthenticating} onLogin={controller.login}>
{controller.error.responseMessage && (
<ErrorMessage text={controller.error.responseMessage} hasDetails={controller.error.hasDetails} onShowDetails={controller.showDetails} />
<ErrorMessage
className={s(styles, { errorMessage: true })}
text={controller.error.responseMessage}
hasDetails={controller.error.hasDetails}
onShowDetails={controller.showDetails}
/>
)}
</DBAuthDialogFooter>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -0,0 +1,14 @@
.propertiesTable {
flex: 1;
overflow: hidden;
padding: 12px 0;
}
.errorMessage {
composes: theme-background-secondary theme-text-on-secondary from global;
position: sticky;
bottom: 0;
padding: 8px 24px;
}
.tabList {
margin: 0 10px;
}
@@ -7,41 +7,17 @@
*/
import { observer } from 'mobx-react-lite';
import { useState } from 'react';
import styled, { css } from 'reshadow';
import styled from 'reshadow';
import { ErrorMessage, IProperty, PropertiesTable, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
import { ErrorMessage, IProperty, PropertiesTable, s, useS, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper } from '@cloudbeaver/core-dialogs';
import type { DataTransferOutputSettings, DataTransferProcessorInfo, GQLErrorCatcher } from '@cloudbeaver/core-sdk';
import { ITabData, Tab, TabList, TabsState, TabTitle, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui';
import { OutputOptionsForm } from './OutputOptionsForm';
import style from './ProcessorConfigureDialog.m.css';
import { ProcessorConfigureDialogFooter } from './ProcessorConfigureDialogFooter';
const styles = css`
PropertiesTable {
flex: 1;
overflow: hidden;
padding: 12px 0;
}
message {
margin: auto;
}
ErrorMessage {
composes: theme-background-secondary theme-text-on-secondary from global;
position: sticky;
bottom: 0;
padding: 8px 24px;
}
TabList {
margin: 0 10px;
}
ObjectPropertyInfoForm {
margin: 12px 0;
}
`;
interface Props {
processor: DataTransferProcessorInfo;
properties: IProperty[];
@@ -73,6 +49,8 @@ export const ProcessorConfigureDialog = observer<Props>(function ProcessorConfig
onExport,
}) {
const translate = useTranslate();
const styles = useS(style);
const title = `${translate('data_transfer_dialog_configuration_title')} (${processor.name})`;
const [currentTabId, setCurrentTabId] = useState(SETTINGS_TABS.EXTRACTION);
@@ -92,13 +70,13 @@ export const ProcessorConfigureDialog = observer<Props>(function ProcessorConfig
}
}
return styled(useStyles(UNDERLINE_TAB_STYLES, styles))(
return styled(useStyles(UNDERLINE_TAB_STYLES))(
<CommonDialogWrapper size="large" fixedSize>
<CommonDialogHeader title={title} onReject={onClose} />
<CommonDialogBody noOverflow noBodyPadding>
{!processor.isBinary ? (
<TabsState currentTabId={currentTabId} onChange={handleTabChange}>
<TabList aria-label="Export Settings tabs">
<TabList className={s(styles, { tabList: true })} aria-label="Export Settings tabs">
<Tab tabId={SETTINGS_TABS.EXTRACTION} style={UNDERLINE_TAB_STYLES}>
<TabTitle>{translate('data_transfer_format_settings')}</TabTitle>
</Tab>
@@ -109,12 +87,19 @@ export const ProcessorConfigureDialog = observer<Props>(function ProcessorConfig
</TabsState>
) : null}
{currentTabId === SETTINGS_TABS.EXTRACTION ? (
<PropertiesTable properties={properties} propertiesState={processorProperties} />
<PropertiesTable className={s(styles, { propertiesTable: true })} properties={properties} propertiesState={processorProperties} />
) : (
<OutputOptionsForm outputSettings={outputSettings} />
)}
{error.responseMessage && <ErrorMessage text={error.responseMessage} hasDetails={error.hasDetails} onShowDetails={onShowDetails} />}
{error.responseMessage && (
<ErrorMessage
className={s(styles, { errorMessage: true })}
text={error.responseMessage}
hasDetails={error.hasDetails}
onShowDetails={onShowDetails}
/>
)}
</CommonDialogBody>
<CommonDialogFooter>
<ProcessorConfigureDialogFooter
@@ -0,0 +1,21 @@
.exportProcessorList {
flex: 1;
}
.exportObject {
composes: theme-typography--body2 from global;
flex-shrink: 0;
padding: 16px 24px;
padding-top: 0;
max-height: 50px;
overflow: hidden;
& pre {
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: initial;
}
}
.pre {
composes: theme-typography--caption from global;
}
@@ -6,38 +6,14 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { Loader } from '@cloudbeaver/core-blocks';
import { Loader, s, useS } from '@cloudbeaver/core-blocks';
import { CommonDialogBody, CommonDialogHeader, CommonDialogWrapper } from '@cloudbeaver/core-dialogs';
import type { DataTransferProcessorInfo } from '@cloudbeaver/core-sdk';
import type { IExportContext } from '../IExportContext';
import { ExportProcessorList } from './ExportProcessorList/ExportProcessorList';
const styles = css`
ExportProcessorList {
flex: 1;
}
export-object {
composes: theme-typography--body2 from global;
flex-shrink: 0;
padding: 16px 24px;
padding-top: 0;
max-height: 50px;
overflow: hidden;
& pre {
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: initial;
}
}
pre {
composes: theme-typography--caption from global;
}
`;
import style from './ProcessorSelectDialog.m.css';
interface Props {
context: IExportContext;
@@ -48,18 +24,22 @@ interface Props {
}
export const ProcessorSelectDialog = observer<Props>(function ProcessorSelectDialog({ context, processors, isLoading, onSelect, onClose }) {
return styled(styles)(
const styles = useS(style);
return (
<CommonDialogWrapper size="large" fixedSize>
<CommonDialogHeader title="data_transfer_dialog_title" onReject={onClose} subTitle={context.name} />
<CommonDialogHeader title="data_transfer_dialog_title" subTitle={context.name} onReject={onClose} />
<CommonDialogBody noBodyPadding noOverflow>
{context.query && (
<export-object>
<pre title={context.query}>{context.query}</pre>
</export-object>
<div className={s(styles, { exportObject: true })}>
<pre className={s(styles, { pre: true })} title={context.query}>
{context.query}
</pre>
</div>
)}
{isLoading && <Loader />}
{!isLoading && <ExportProcessorList processors={processors} onSelect={onSelect} />}
{!isLoading && <ExportProcessorList className={s(styles, { exportProcessorList: true })} processors={processors} onSelect={onSelect} />}
</CommonDialogBody>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -0,0 +1,5 @@
.footer {
align-items: center;
justify-content: flex-end;
gap: 24px;
}
@@ -7,9 +7,8 @@
*/
import { observer } from 'mobx-react-lite';
import { useCallback, useEffect, useRef, useState } from 'react';
import styled, { css } from 'reshadow';
import { Button, InputField, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, InputField, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import {
CommonDialogBody,
@@ -21,13 +20,7 @@ import {
} from '@cloudbeaver/core-dialogs';
import { ClipboardService } from '@cloudbeaver/core-ui';
export const dialogStyle = css`
CommonDialogFooter {
align-items: center;
justify-content: flex-end;
gap: 24px;
}
`;
import style from './FilterCustomValueDialog.m.css';
interface IPayload {
inputTitle: string;
@@ -40,6 +33,7 @@ export const FilterCustomValueDialog: DialogComponent<IPayload, string | number>
rejectDialog,
}: DialogComponentProps<IPayload, string | number>) {
const clipboardService = useService(ClipboardService);
const styles = useS(style);
const inputRef = useRef<HTMLInputElement | null>(null);
const [value, setValue] = useState<string | number>(payload.defaultValue);
@@ -60,7 +54,7 @@ export const FilterCustomValueDialog: DialogComponent<IPayload, string | number>
inputRef.current?.focus();
}, []);
return styled(dialogStyle)(
return (
<CommonDialogWrapper size="small">
<CommonDialogHeader title="data_grid_table_context_menu_filter_dialog_title" onReject={rejectDialog} />
<CommonDialogBody noOverflow>
@@ -68,7 +62,7 @@ export const FilterCustomValueDialog: DialogComponent<IPayload, string | number>
{payload.inputTitle}
</InputField>
</CommonDialogBody>
<CommonDialogFooter>
<CommonDialogFooter className={s(styles, { footer: true })}>
{clipboardService.clipboardAvailable && clipboardService.state !== 'denied' && (
<Button type="button" mod={['outlined']} onClick={getValueFromClipboard}>
{translate('ui_clipboard')}
@@ -81,6 +75,6 @@ export const FilterCustomValueDialog: DialogComponent<IPayload, string | number>
{translate('ui_processing_ok')}
</Button>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -0,0 +1,19 @@
.footerContainer {
display: flex;
width: min-content;
flex: 1;
align-items: center;
justify-content: flex-end;
gap: 24px;
}
.buttons {
flex: 1;
display: flex;
gap: 24px;
}
.wrapper {
display: flex;
height: 100%;
width: 100%;
overflow: auto;
}
@@ -7,38 +7,13 @@
*/
import { observer } from 'mobx-react-lite';
import { useRef } from 'react';
import styled, { css } from 'reshadow';
import { Button, Container, FieldCheckbox, Group, InputField, SubmittingForm, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, Container, FieldCheckbox, Fill, Group, InputField, s, SubmittingForm, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponentProps } from '@cloudbeaver/core-dialogs';
import style from './AutoRefreshSettingsDialog.m.css';
import type { IAutoRefreshSettings } from './IAutoRefreshSettings';
const styles = css`
footer-container {
display: flex;
width: min-content;
flex: 1;
align-items: center;
justify-content: flex-end;
gap: 24px;
}
buttons {
flex: 1;
display: flex;
gap: 24px;
}
wrapper {
display: flex;
height: 100%;
width: 100%;
overflow: auto;
}
fill {
flex: 1;
}
`;
interface Payload {
settings: IAutoRefreshSettings;
}
@@ -49,6 +24,7 @@ export const AutoRefreshSettingsDialog = observer<DialogComponentProps<Payload>>
payload,
}) {
const translate = useTranslate();
const styles = useS(style);
const formRef = useRef<HTMLFormElement>(null);
function resolve() {
@@ -61,11 +37,11 @@ export const AutoRefreshSettingsDialog = observer<DialogComponentProps<Payload>>
}
}
return styled(styles)(
return (
<CommonDialogWrapper size="small">
<CommonDialogHeader title="data_viewer_auto_refresh_settings" icon="/icons/settings_cog_m.svg" onReject={rejectDialog} />
<CommonDialogBody noBodyPadding noOverflow>
<wrapper>
<div className={s(styles, { wrapper: true })}>
<SubmittingForm ref={formRef} onSubmit={() => resolve()}>
<Container>
<Group form gap>
@@ -79,21 +55,21 @@ export const AutoRefreshSettingsDialog = observer<DialogComponentProps<Payload>>
</Group>
</Container>
</SubmittingForm>
</wrapper>
</div>
</CommonDialogBody>
<CommonDialogFooter>
<footer-container>
<buttons>
<div className={s(styles, { footerContainer: true })}>
<div className={s(styles, { buttons: true })}>
<Button mod={['outlined']} onClick={() => rejectDialog()}>
{translate('ui_processing_cancel')}
</Button>
<fill />
<Fill />
<Button mod={['unelevated']} onClick={() => resolve()}>
{translate('ui_processing_ok')}
</Button>
</buttons>
</footer-container>
</div>
</div>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -0,0 +1,17 @@
.button {
margin-left: auto;
}
.container {
composes: theme-typography--body2 from global;
gap: 32px;
}
.group {
gap: 16px;
}
.groupTitle,
.group {
padding: 0 !important;
}
.groupTitle {
font-weight: bold;
}
@@ -5,45 +5,24 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import styled, { css } from 'reshadow';
import { Button, Container, Group, GroupTitle, Link, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, Container, Group, GroupTitle, Link, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs';
import { Shortcut } from './Shortcut';
import { DATA_VIEWER_SHORTCUTS, NAVIGATION_TREE_SHORTCUTS, SQL_EDITOR_SHORTCUTS } from './SHORTCUTS_DATA';
const style = css`
Button {
margin-left: auto;
}
Container {
composes: theme-typography--body2 from global;
gap: 32px;
}
Group {
gap: 16px;
}
GroupTitle,
Group {
padding: 0 !important;
}
GroupTitle {
font-weight: bold;
}
`;
import style from './ShortcutsDialog.m.css';
export const ShortcutsDialog: DialogComponent<null> = function ShortcutsDialog({ rejectDialog }) {
const translate = useTranslate();
const styles = useStyles(style);
const styles = useS(style);
return styled(styles)(
return (
<CommonDialogWrapper size="large">
<CommonDialogHeader title={translate('shortcuts_title')} onReject={rejectDialog} />
<CommonDialogBody>
<Container wrap overflow>
<Group overflow>
<GroupTitle>
<Container className={s(styles, { container: true })} wrap overflow>
<Group className={s(styles, { group: true })} overflow>
<GroupTitle className={s(styles, { groupTitle: true })}>
<Link href="https://dbeaver.com/docs/cloudbeaver/Data-editor/" target="_blank" wrapper indicator>
Data Viewer
</Link>
@@ -52,8 +31,8 @@ export const ShortcutsDialog: DialogComponent<null> = function ShortcutsDialog({
<Shortcut key={shortcut.label} shortcut={shortcut} />
))}
</Group>
<Group overflow>
<GroupTitle>
<Group className={s(styles, { group: true })} overflow>
<GroupTitle className={s(styles, { groupTitle: true })}>
<Link href="https://dbeaver.com/docs/cloudbeaver/SQL-Editor/" target="_blank" wrapper indicator>
SQL Editor
</Link>
@@ -62,8 +41,8 @@ export const ShortcutsDialog: DialogComponent<null> = function ShortcutsDialog({
<Shortcut key={shortcut.label} shortcut={shortcut} />
))}
</Group>
<Group overflow>
<GroupTitle>
<Group className={s(styles, { group: true })} overflow>
<GroupTitle className={s(styles, { groupTitle: true })}>
<Link href="https://dbeaver.com/docs/cloudbeaver/Database-Navigator/" target="_blank" wrapper indicator>
Navigation Tree
</Link>
@@ -75,10 +54,10 @@ export const ShortcutsDialog: DialogComponent<null> = function ShortcutsDialog({
</Container>
</CommonDialogBody>
<CommonDialogFooter>
<Button type="button" mod={['outlined']} onClick={rejectDialog}>
<Button className={s(styles, { button: true })} type="button" mod={['outlined']} onClick={rejectDialog}>
{translate('ui_close')}
</Button>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
};
@@ -15,7 +15,3 @@
flex-direction: row;
overflow-x: auto;
}
.fill {
flex: 1;
}
@@ -11,6 +11,7 @@ import styled from 'reshadow';
import {
ACTION_ICON_BUTTON_STYLES,
Fill,
IconButton,
IconButtonStyles,
PlaceholderElement,
@@ -77,7 +78,7 @@ export const ElementsTreeTools = observer<React.PropsWithChildren<Props>>(functi
onClick={() => setOpen(!opened)}
/>
)}
<div className={s(styles, { fill: true })} />
<Fill />
<ElementsTreeToolsMenu tree={tree} />
<IconButton
name="/icons/refresh_sm.svg#root"
@@ -0,0 +1,3 @@
.footer {
align-items: center;
}
@@ -8,17 +8,19 @@
import { observable } from 'mobx';
import { observer } from 'mobx-react-lite';
import { useEffect } from 'react';
import styled, { css } from 'reshadow';
import {
Button,
Container,
Fill,
InputField,
s,
SubmittingForm,
Translate,
useFocus,
useObservableRef,
useResource,
useS,
useTranslate,
} from '@cloudbeaver/core-blocks';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs';
@@ -26,15 +28,7 @@ import { ProjectInfo, ProjectInfoResource } from '@cloudbeaver/core-projects';
import { createPath, throttleAsync } from '@cloudbeaver/core-utils';
import { ProjectSelect } from '@cloudbeaver/plugin-projects';
const style = css`
CommonDialogFooter {
align-items: center;
}
fill {
flex: 1;
}
`;
import style from './FolderDialog.m.css';
interface IFolderDialogState {
value: string;
@@ -78,6 +72,7 @@ export const FolderDialog: DialogComponent<FolderDialogPayload, IFolderDialogRes
rejectDialog,
className,
}) {
const styles = useS(style);
const translate = useTranslate();
const [focusedRef] = useFocus<HTMLFormElement>({ focusFirstChild: true });
@@ -157,7 +152,7 @@ export const FolderDialog: DialogComponent<FolderDialogPayload, IFolderDialogRes
const errorMessage = state.valid ? ' ' : translate(state.message ?? 'ui_rename_taken_or_invalid');
const subTitle = createPath(projectInfoLoader.data?.name ?? state.projectId, state.folder);
return styled(style)(
return (
<CommonDialogWrapper size="small" className={className} fixedWidth>
<CommonDialogHeader subTitle={subTitle} title={title} icon={icon} viewBox={viewBox} bigIcon={bigIcon} onReject={rejectDialog} />
<CommonDialogBody>
@@ -177,15 +172,15 @@ export const FolderDialog: DialogComponent<FolderDialogPayload, IFolderDialogRes
</Container>
</SubmittingForm>
</CommonDialogBody>
<CommonDialogFooter>
<CommonDialogFooter className={s(styles, { footer: true })}>
<Button type="button" mod={['outlined']} onClick={rejectDialog}>
<Translate token="ui_processing_cancel" />
</Button>
<fill />
<Fill />
<Button type="button" mod={['unelevated']} disabled={!state.valid} onClick={resolveHandler}>
<Translate token={confirmActionText || (create ? 'ui_create' : 'ui_rename')} />
</Button>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -7,18 +7,11 @@
*/
import { action, observable } from 'mobx';
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { Button, Container, InputField, SubmittingForm, Translate, useFocus, useObservableRef, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, Container, Fill, InputField, SubmittingForm, Translate, useFocus, useObservableRef, useTranslate } from '@cloudbeaver/core-blocks';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs';
import { ProjectSelect } from '@cloudbeaver/plugin-projects';
const style = css`
fill {
flex: 1;
}
`;
export interface ISaveScriptDialogResult {
name: string;
projectId: string | null;
@@ -86,7 +79,7 @@ export const SaveScriptDialog: DialogComponent<Payload, ISaveScriptDialogResult>
const errorMessage = state.valid ? ' ' : translate(state.message ?? 'ui_rename_taken_or_invalid');
return styled(style)(
return (
<CommonDialogWrapper size="small" className={className} fixedWidth>
<CommonDialogHeader title={translate('plugin_resource_manager_scripts_save_script')} icon="/icons/sql_script_m.svg" onReject={rejectDialog} />
<CommonDialogBody>
@@ -121,11 +114,11 @@ export const SaveScriptDialog: DialogComponent<Payload, ISaveScriptDialogResult>
<Button type="button" mod={['outlined']} onClick={rejectDialog}>
<Translate token="ui_processing_cancel" />
</Button>
<fill />
<Fill />
<Button type="button" mod={['unelevated']} disabled={!state.valid} onClick={state.submit}>
<Translate token="ui_processing_save" />
</Button>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -0,0 +1,8 @@
.text {
margin: 0;
}
.footer {
align-items: center;
justify-content: flex-end;
gap: 24px;
}
@@ -6,38 +6,29 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { Button, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs';
import { RouterService } from '@cloudbeaver/core-routing';
const styles = css`
p {
margin: 0;
}
CommonDialogFooter {
align-items: center;
justify-content: flex-end;
gap: 24px;
}
`;
import style from './ServerNodeChangedDialog.m.css';
export const ServerNodeChangedDialog: DialogComponent<null, null> = observer(function ServerNodeChangedDialog({ rejectDialog }) {
const styles = useS(style);
const routerService = useService(RouterService);
const translate = useTranslate();
function reload() {
routerService.reload();
}
return styled(styles)(
return (
<CommonDialogWrapper size="small" fixedSize>
<CommonDialogHeader title="app_root_server_node_changed_title" onReject={rejectDialog} />
<CommonDialogBody noOverflow>
<p>{translate('app_root_server_node_changed_message')}</p>
<p className={s(styles, { text: true })}>{translate('app_root_server_node_changed_message')}</p>
</CommonDialogBody>
<CommonDialogFooter>
<CommonDialogFooter className={s(styles, { footer: true })}>
<Button type="button" mod={['outlined']} onClick={rejectDialog}>
{translate('ui_processing_cancel')}
</Button>
@@ -45,6 +36,6 @@ export const ServerNodeChangedDialog: DialogComponent<null, null> = observer(fun
{translate('ui_processing_reload')}
</Button>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -6,42 +6,33 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { Button, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs';
import { RouterService } from '@cloudbeaver/core-routing';
const styles = css`
p {
margin: 0;
}
CommonDialogFooter {
align-items: center;
justify-content: flex-end;
gap: 24px;
}
`;
import style from '../ServerNodeChangedDialog/ServerNodeChangedDialog.m.css';
export const SessionExpiredDialog: DialogComponent<null, null> = observer(function SessionExpiredDialog({ rejectDialog }) {
const styles = useS(style);
const routerService = useService(RouterService);
const translate = useTranslate();
function reload() {
routerService.reload();
}
return styled(styles)(
return (
<CommonDialogWrapper size="small" fixedSize>
<CommonDialogHeader title="app_root_session_expired_title" onReject={rejectDialog} />
<CommonDialogBody noOverflow>
<p>{translate('app_root_session_expired_message')}</p>
<p className={s(styles, { text: true })}>{translate('app_root_session_expired_message')}</p>
</CommonDialogBody>
<CommonDialogFooter>
<CommonDialogFooter className={s(styles, { footer: true })}>
<Button type="button" mod={['unelevated']} onClick={reload}>
{translate('ui_processing_reload')}
</Button>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -6,35 +6,27 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { Button, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs';
const styles = css`
p {
margin: 0;
}
CommonDialogFooter {
align-items: center;
justify-content: flex-end;
}
`;
import style from '../ServerNodeChangedDialog/ServerNodeChangedDialog.m.css';
export const SessionExpireWarningDialog: DialogComponent<null, null> = observer(function SessionExpireWarningDialog({ rejectDialog }) {
const translate = useTranslate();
const styles = useS(style);
return styled(styles)(
return (
<CommonDialogWrapper size="small" fixedSize>
<CommonDialogHeader title="app_root_session_expire_warning_title" onReject={rejectDialog} />
<CommonDialogBody noOverflow>
<p>{translate('app_root_session_expire_warning_message')}</p>
<p className={s(styles, { text: true })}>{translate('app_root_session_expire_warning_message')}</p>
</CommonDialogBody>
<CommonDialogFooter>
<CommonDialogFooter className={s(styles, { footer: true })}>
<Button type="button" mod={['unelevated']} onClick={rejectDialog}>
{translate('app_root_session_expire_warning_button')}
</Button>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -0,0 +1,9 @@
.footer {
align-items: center;
}
.container {
width: 100%;
display: flex;
gap: 16px;
}
@@ -5,48 +5,34 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import styled, { css } from 'reshadow';
import { Button, Translate } from '@cloudbeaver/core-blocks';
import { Button, Fill, s, Translate, useS } from '@cloudbeaver/core-blocks';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponent } from '@cloudbeaver/core-dialogs';
const style = css`
CommonDialogFooter {
align-items: center;
}
container {
width: 100%;
display: flex;
gap: 16px;
}
fill {
flex: 1;
}
`;
import style from './ScriptImportDialog.m.css';
export const ScriptImportDialog: DialogComponent<null, boolean> = function ScriptImportDialog({ resolveDialog, rejectDialog, className }) {
return styled(style)(
const styles = useS(style);
return (
<CommonDialogWrapper size="small" className={className} fixedWidth>
<CommonDialogHeader title="ui_changes_might_be_lost" onReject={rejectDialog} />
<CommonDialogBody>
<Translate token="sql_editor_upload_script_unsaved_changes_dialog_message" />
</CommonDialogBody>
<CommonDialogFooter>
<container>
<CommonDialogFooter className={s(styles, { footer: true })}>
<div className={s(styles, { container: true })}>
<Button type="button" mod={['outlined']} onClick={rejectDialog}>
<Translate token="ui_processing_cancel" />
</Button>
<fill />
<Fill />
<Button type="button" mod={['outlined']} onClick={() => resolveDialog(false)}>
<Translate token="ui_no" />
</Button>
<Button type="button" mod={['unelevated']} onClick={() => resolveDialog(true)}>
<Translate token="ui_yes" />
</Button>
</container>
</div>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
};
@@ -0,0 +1,14 @@
.wrapper {
display: flex;
align-items: center;
height: 100%;
width: 100%;
overflow: auto;
}
.sqlCodeEditorLoader {
height: 100%;
width: 100%;
}
.footer {
gap: 24px;
}
@@ -6,9 +6,8 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { Button, useClipboard, useResource, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, Fill, s, useClipboard, useResource, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { ConnectionDialectResource, ConnectionExecutionContextService, createConnectionParam } from '@cloudbeaver/core-connections';
import { useService } from '@cloudbeaver/core-di';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponentProps } from '@cloudbeaver/core-dialogs';
@@ -16,25 +15,7 @@ import { useCodemirrorExtensions } from '@cloudbeaver/plugin-codemirror6';
import type { IDatabaseDataModel } from '@cloudbeaver/plugin-data-viewer';
import { SQLCodeEditorLoader, useSqlDialectExtension } from '@cloudbeaver/plugin-sql-editor-new';
const styles = css`
wrapper {
display: flex;
align-items: center;
height: 100%;
width: 100%;
overflow: auto;
}
SQLCodeEditorLoader {
height: 100%;
width: 100%;
}
fill {
flex: 1;
}
CommonDialogFooter {
gap: 24px;
}
`;
import style from './ScriptPreviewDialog.m.css';
interface Payload {
script: string;
@@ -44,6 +25,7 @@ interface Payload {
export const ScriptPreviewDialog = observer<DialogComponentProps<Payload>>(function ScriptPreviewDialog({ rejectDialog, payload }) {
const translate = useTranslate();
const copy = useClipboard();
const styles = useS(style);
const connectionExecutionContextService = useService(ConnectionExecutionContextService);
const context = connectionExecutionContextService.get(payload.model.source.executionContext?.context?.id ?? '');
@@ -62,19 +44,25 @@ export const ScriptPreviewDialog = observer<DialogComponentProps<Payload>>(funct
rejectDialog();
};
return styled(styles)(
return (
<CommonDialogWrapper size="large">
<CommonDialogHeader title="data_viewer_script_preview_dialog_title" icon="sql-script" onReject={rejectDialog} />
<CommonDialogBody noBodyPadding noOverflow>
<wrapper>
<SQLCodeEditorLoader value={payload.script} extensions={extensions} lineNumbers readonly />
</wrapper>
<div className={s(styles, { wrapper: true })}>
<SQLCodeEditorLoader
className={s(styles, { sqlCodeEditorLoader: true })}
value={payload.script}
extensions={extensions}
lineNumbers
readonly
/>
</div>
</CommonDialogBody>
<CommonDialogFooter>
<CommonDialogFooter className={s(styles, { footer: true })}>
<Button mod={['unelevated']} onClick={apply}>
{translate('ui_apply')}
</Button>
<fill />
<Fill />
<Button mod={['outlined']} onClick={() => copy(payload.script, true)}>
{translate('ui_copy_to_clipboard')}
</Button>
@@ -82,6 +70,6 @@ export const ScriptPreviewDialog = observer<DialogComponentProps<Payload>>(funct
{translate('ui_close')}
</Button>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});
@@ -0,0 +1,28 @@
.footerContainer {
display: flex;
width: min-content;
flex: 1;
align-items: center;
justify-content: flex-end;
gap: 24px;
}
.buttons {
flex: 0 0 auto;
display: flex;
gap: 24px;
}
.errorMessage {
composes: theme-background-secondary theme-text-on-secondary from global;
flex: 1;
}
.wrapper {
display: flex;
align-items: center;
height: 100%;
width: 100%;
overflow: auto;
}
.sqlCodeEditorLoader {
height: 100%;
width: 100%;
}
@@ -8,9 +8,8 @@
import { computed, observable } from 'mobx';
import { observer } from 'mobx-react-lite';
import { useEffect } from 'react';
import styled, { css } from 'reshadow';
import { Button, ErrorMessage, Loader, useClipboard, useErrorDetails, useObservableRef, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, ErrorMessage, Loader, s, useClipboard, useErrorDetails, useObservableRef, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { ConnectionInfoResource, createConnectionParam } from '@cloudbeaver/core-connections';
import { useService } from '@cloudbeaver/core-di';
import { CommonDialogBody, CommonDialogFooter, CommonDialogHeader, CommonDialogWrapper, DialogComponentProps } from '@cloudbeaver/core-dialogs';
@@ -19,39 +18,9 @@ import { useCodemirrorExtensions } from '@cloudbeaver/plugin-codemirror6';
import { SqlDialectInfoService } from '@cloudbeaver/plugin-sql-editor';
import { SQLCodeEditorLoader, useSqlDialectExtension } from '@cloudbeaver/plugin-sql-editor-new';
import style from './GeneratedSqlDialog.m.css';
import { SqlGeneratorsResource } from './SqlGeneratorsResource';
const styles = css`
footer-container {
display: flex;
width: min-content;
flex: 1;
align-items: center;
justify-content: flex-end;
gap: 24px;
}
buttons {
flex: 0 0 auto;
display: flex;
gap: 24px;
}
ErrorMessage {
composes: theme-background-secondary theme-text-on-secondary from global;
flex: 1;
}
wrapper {
display: flex;
align-items: center;
height: 100%;
width: 100%;
overflow: auto;
}
SQLCodeEditorLoader {
height: 100%;
width: 100%;
}
`;
interface Payload {
generatorId: string;
pathId: string;
@@ -60,6 +29,7 @@ interface Payload {
export const GeneratedSqlDialog = observer<DialogComponentProps<Payload>>(function GeneratedSqlDialog({ rejectDialog, payload }) {
const translate = useTranslate();
const copy = useClipboard();
const styles = useS(style);
const sqlDialectInfoService = useService(SqlDialectInfoService);
const sqlGeneratorsResource = useService(SqlGeneratorsResource);
@@ -119,31 +89,36 @@ export const GeneratedSqlDialog = observer<DialogComponentProps<Payload>>(functi
});
});
return styled(styles)(
return (
<CommonDialogWrapper size="large">
<CommonDialogHeader title="app_shared_sql_generators_dialog_title" icon="sql-script" onReject={rejectDialog} />
<CommonDialogBody noOverflow noBodyPadding>
<wrapper>
<div className={s(styles, { wrapper: true })}>
<Loader loading={state.loading}>
{() => styled(styles)(<SQLCodeEditorLoader value={state.query} extensions={extensions} readonly />)}
{() => <SQLCodeEditorLoader className={s(styles, { sqlCodeEditorLoader: true })} value={state.query} extensions={extensions} readonly />}
</Loader>
</wrapper>
</div>
</CommonDialogBody>
<CommonDialogFooter>
<footer-container>
<div className={s(styles, { footerContainer: true })}>
{state.error.responseMessage && (
<ErrorMessage text={state.error.responseMessage} hasDetails={error.hasDetails} onShowDetails={error.open} />
<ErrorMessage
className={s(styles, { errorMessage: true })}
text={state.error.responseMessage}
hasDetails={error.hasDetails}
onShowDetails={error.open}
/>
)}
<buttons>
<div className={s(styles, { buttons: true })}>
<Button mod={['outlined']} onClick={() => copy(state.query, true)}>
{translate('ui_copy_to_clipboard')}
</Button>
<Button mod={['unelevated']} onClick={rejectDialog}>
{translate('ui_close')}
</Button>
</buttons>
</footer-container>
</div>
</div>
</CommonDialogFooter>
</CommonDialogWrapper>,
</CommonDialogWrapper>
);
});