mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
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:
@@ -0,0 +1,3 @@
|
||||
.fill {
|
||||
flex: 1;
|
||||
}
|
||||
@@ -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)} />;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
`,
|
||||
];
|
||||
-15
@@ -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;
|
||||
}
|
||||
`;
|
||||
+27
@@ -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;
|
||||
}
|
||||
+16
-12
@@ -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>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -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}
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
.driverSelector {
|
||||
flex: 1;
|
||||
}
|
||||
+7
-11
@@ -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>
|
||||
);
|
||||
});
|
||||
|
||||
+18
@@ -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;
|
||||
}
|
||||
+16
-28
@@ -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>
|
||||
);
|
||||
});
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
.submittingForm {
|
||||
overflow: auto;
|
||||
margin: auto;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.connectionAuthenticationFormLoader {
|
||||
align-content: center;
|
||||
}
|
||||
.button {
|
||||
margin-left: auto;
|
||||
}
|
||||
+8
-22
@@ -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>
|
||||
);
|
||||
});
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
.footer {
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 24px;
|
||||
}
|
||||
+6
-12
@@ -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>
|
||||
);
|
||||
});
|
||||
|
||||
+19
@@ -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;
|
||||
}
|
||||
+12
-36
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
-4
@@ -15,7 +15,3 @@
|
||||
flex-direction: row;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.fill {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
+2
-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;
|
||||
}
|
||||
+7
-16
@@ -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>
|
||||
);
|
||||
});
|
||||
|
||||
+7
-15
@@ -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>
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user