mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-10-13 16:18:51 +08:00
Merge branch 'devel' into CB-4356-create-smart-tabs-switchingng-for-forms
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
import { css } from 'reshadow';
|
||||
|
||||
// TODO in cloudeaver-ee remove all reshadow styles connected to this
|
||||
export const ADMINISTRATION_TOOLS_PANEL_STYLES = css`
|
||||
ToolsPanel {
|
||||
composes: theme-background-surface theme-text-on-surface theme-border-color-background from global;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
.message {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: var(--theme-group-element-radius);
|
||||
height: 50px;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.errorIcon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.messageBody {
|
||||
composes: theme-typography--body2 from global;
|
||||
max-height: 100%;
|
||||
line-height: 1.2;
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
-webkit-line-clamp: 2;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.messageActions {
|
||||
margin-left: 16px;
|
||||
}
|
||||
@@ -6,43 +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 { Button } from './Button';
|
||||
import { IconOrImage } from './IconOrImage';
|
||||
import { useTranslate } from './localization/useTranslate';
|
||||
import { useS } from './useS';
|
||||
|
||||
const styles = css`
|
||||
message {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: var(--theme-group-element-radius);
|
||||
height: 50px;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
IconOrImage {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
message-body {
|
||||
composes: theme-typography--body2 from global;
|
||||
max-height: 100%;
|
||||
line-height: 1.2;
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
-webkit-line-clamp: 2;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
message-actions {
|
||||
margin-left: 16px;
|
||||
}
|
||||
`;
|
||||
import styles from './ErrorMessage.m.css';
|
||||
import { s } from './s';
|
||||
|
||||
interface Props {
|
||||
hasDetails?: boolean;
|
||||
@@ -53,18 +23,19 @@ interface Props {
|
||||
|
||||
export const ErrorMessage = observer<Props>(function ErrorMessage({ text, className, hasDetails, onShowDetails }) {
|
||||
const translate = useTranslate();
|
||||
const style = useS(styles);
|
||||
|
||||
return styled(styles)(
|
||||
<message className={className}>
|
||||
<IconOrImage icon="/icons/error_icon_sm.svg" />
|
||||
<message-body title={text}>{text}</message-body>
|
||||
<message-actions>
|
||||
return (
|
||||
<div className={s(style, { message: true }, className)}>
|
||||
<IconOrImage className={s(style, { errorIcon: true })} icon="/icons/error_icon_sm.svg" />
|
||||
<div className={s(style, { messageBody: true })} title={text}>{text}</div>
|
||||
<div className={s(style, { messageActions: true })}>
|
||||
{hasDetails && (
|
||||
<Button type="button" mod={['outlined']} onClick={onShowDetails}>
|
||||
{translate('ui_errors_details')}
|
||||
</Button>
|
||||
)}
|
||||
</message-actions>
|
||||
</message>,
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { use } from 'reshadow';
|
||||
|
||||
import { IconButton } from '../IconButton';
|
||||
import { useTranslate } from '../localization/useTranslate';
|
||||
@@ -67,7 +66,6 @@ export const ItemListSearch: React.FC<IProps> = function ItemListSearch({ value,
|
||||
autoComplete="off"
|
||||
disabled={disabled}
|
||||
onChange={event => changeHandler(event.target.value)}
|
||||
{...use({ mod: 'surface' })}
|
||||
/>
|
||||
<div className={s(styles, { actionButton: true })}>
|
||||
{!onSearch && inputValue ? (
|
||||
|
||||
@@ -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 { useEffect, useRef } from 'react';
|
||||
import styled from 'reshadow';
|
||||
|
||||
import { Icon } from '../Icon';
|
||||
import styles from './loading-screen.css';
|
||||
|
||||
const FADE_IN_DELAY = 300;
|
||||
|
||||
function LoadingScreen() {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
const appContainer = document.querySelector('#__next')!;
|
||||
const loadingNode = appContainer.appendChild(ref.current!.cloneNode(true));
|
||||
setTimeout(() => (loadingNode as any).classList.add(styles.fadeIn));
|
||||
setTimeout(() => appContainer.removeChild(loadingNode), FADE_IN_DELAY);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return styled(styles)(
|
||||
<div ref={ref}>
|
||||
<Icon name="logo" viewBox="0 0 1755.6533 681.13202" />
|
||||
</div>,
|
||||
);
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
:global(html) {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
background-color: #ffffff;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.fadeIn {
|
||||
transition: opacity 0.3s ease;
|
||||
opacity: 0;
|
||||
animation: none;
|
||||
}
|
||||
|
||||
Icon {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
div::before {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
z-index: 1;
|
||||
width: 500%;
|
||||
margin-left: -250%;
|
||||
animation: wave 1.3s linear infinite;
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
rgba(255, 255, 255, 0) 46%,
|
||||
rgba(255, 255, 255, 0.35) 50%,
|
||||
rgba(255, 255, 255, 0) 54%
|
||||
)
|
||||
50% 50%;
|
||||
}
|
||||
|
||||
@keyframes wave {
|
||||
0% {
|
||||
transform: translate3d(-30%, 0, 0);
|
||||
}
|
||||
100% {
|
||||
transform: translate3d(30%, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { Icon } from '../Icon';
|
||||
import { s } from '../s';
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
.checkbox {
|
||||
margin-left: -10px;
|
||||
margin-right: -10px;
|
||||
}
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useContext } from 'react';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { EventContext } from '@cloudbeaver/core-events';
|
||||
|
||||
@@ -15,6 +14,9 @@ import { Checkbox } from '../FormControls/Checkboxes/Checkbox';
|
||||
import { EventTableItemSelectionFlag } from './EventTableItemSelectionFlag';
|
||||
import { TableContext } from './TableContext';
|
||||
import { TableItemContext } from './TableItemContext';
|
||||
import { useS } from '../useS';
|
||||
import styles from './TableItemSelect.m.css';
|
||||
import { s } from '../s';
|
||||
|
||||
interface Props {
|
||||
checked?: boolean;
|
||||
@@ -23,17 +25,11 @@ interface Props {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const styles = css`
|
||||
Checkbox {
|
||||
margin-left: -10px;
|
||||
margin-right: -10px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const TableItemSelect = observer<Props>(function TableItemSelect({ checked, disabled, tooltip, className }) {
|
||||
const tableContext = useContext(TableContext);
|
||||
const context = useContext(TableItemContext);
|
||||
const selected = checked ?? context?.isSelected();
|
||||
const style = useS(styles);
|
||||
|
||||
function handleClick(event: React.MouseEvent<HTMLInputElement>) {
|
||||
if (!context) {
|
||||
@@ -48,7 +44,13 @@ export const TableItemSelect = observer<Props>(function TableItemSelect({ checke
|
||||
return null;
|
||||
}
|
||||
|
||||
return styled(styles)(
|
||||
<Checkbox className={className} title={tooltip} disabled={context.selectDisabled || disabled} checked={selected} onClick={handleClick} />,
|
||||
return (
|
||||
<Checkbox
|
||||
className={s(style, { checkbox: true }, className)}
|
||||
title={tooltip}
|
||||
disabled={context.selectDisabled || disabled}
|
||||
checked={selected}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
.toolsPanel {
|
||||
height: 30px;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.primary {
|
||||
composes: theme-background-surface theme-text-on-surface theme-border-color-background from global;
|
||||
}
|
||||
|
||||
.bottomBorder {
|
||||
border-bottom: solid 1px;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
composes: theme-background-secondary theme-text-on-secondary theme-border-color-background from global;
|
||||
overflow: auto;
|
||||
align-items: center;
|
||||
height: initial;
|
||||
min-height: 32px;
|
||||
border-bottom: none;
|
||||
}
|
||||
@@ -9,12 +9,15 @@ import { s } from '../s';
|
||||
import { useS } from '../useS';
|
||||
import style from './ToolsPanel.m.css';
|
||||
|
||||
type TType = 'primary' | 'secondary';
|
||||
interface Props {
|
||||
className?: string;
|
||||
type?: TType;
|
||||
hasBottomBorder?: boolean;
|
||||
}
|
||||
|
||||
export const ToolsPanel: React.FC<React.PropsWithChildren<Props>> = function ToolsPanel({ className, children }) {
|
||||
export const ToolsPanel: React.FC<React.PropsWithChildren<Props>> = function ToolsPanel({ className, children, type = 'primary', hasBottomBorder = false }) {
|
||||
const styles = useS(style);
|
||||
|
||||
return <div className={s(styles, { toolsPanel: true }, className)}>{children}</div>;
|
||||
return <div className={s(styles, { toolsPanel: true, [type]: true, bottomBorder: hasBottomBorder }, className)}>{children}</div>;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
.container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 32px;
|
||||
}
|
||||
@@ -5,39 +5,12 @@
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import styled, { css, use } from 'reshadow';
|
||||
|
||||
import { IconOrImage } from '../IconOrImage';
|
||||
import { s } from '../s';
|
||||
import { useS } from '../useS';
|
||||
import styles from './AppLogo.m.css';
|
||||
|
||||
const styles = css`
|
||||
logo {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
IconOrImage {
|
||||
height: 32px;
|
||||
width: 154px;
|
||||
&[|small] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 480px) {
|
||||
IconOrImage {
|
||||
&[|primary] {
|
||||
display: none;
|
||||
}
|
||||
&[|small] {
|
||||
display: block;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
@@ -45,10 +18,10 @@ interface Props {
|
||||
}
|
||||
|
||||
export const AppLogo: React.FC<Props> = function AppLogo({ title, onClick }) {
|
||||
return styled(styles)(
|
||||
<logo title={title} onClick={onClick}>
|
||||
<IconOrImage icon="/icons/logo.svg" {...use({ primary: true })} />
|
||||
<IconOrImage icon="/icons/logo_sm.svg" {...use({ small: true })} />
|
||||
</logo>,
|
||||
const style = useS(styles);
|
||||
return (
|
||||
<div className={s(style, { container: true })} title={title} onClick={onClick}>
|
||||
<IconOrImage className={s(style, { logo: true })} icon="/icons/logo_sm.svg" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.header {
|
||||
composes: theme-text-on-primary theme-typography--body2 from global;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 48px;
|
||||
padding: 0 8px;
|
||||
background-color: #2a7cb4;
|
||||
z-index: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -5,25 +5,17 @@
|
||||
* 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';
|
||||
|
||||
export const topAppBarStyles = css`
|
||||
header {
|
||||
composes: theme-text-on-primary theme-typography--body2 from global;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 48px;
|
||||
padding: 0 8px;
|
||||
background-color: #2a7cb4;
|
||||
z-index: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
`;
|
||||
import { s } from '../s';
|
||||
import { useS } from '../useS';
|
||||
import styles from './TopAppBar.m.css';
|
||||
|
||||
interface Props extends React.PropsWithChildren {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const TopAppBar: React.FC<Props> = function TopAppBar({ children, className }) {
|
||||
return styled(topAppBarStyles)(<header className={className}>{children}</header>);
|
||||
const style = useS(styles);
|
||||
|
||||
return (<header className={s(style, { header: true }, className)}>{children}</header>);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.loader {
|
||||
height: 100vh;
|
||||
}
|
||||
@@ -7,11 +7,11 @@
|
||||
*/
|
||||
import { Suspense } from 'react';
|
||||
import { createRoot, Root } from 'react-dom/client';
|
||||
import styled from 'reshadow';
|
||||
|
||||
import { Body } from '@cloudbeaver/core-app';
|
||||
import { DisplayError, ErrorBoundary, Loader } from '@cloudbeaver/core-blocks';
|
||||
import { DisplayError, ErrorBoundary, Loader, s } from '@cloudbeaver/core-blocks';
|
||||
import { AppContext, IServiceInjector } from '@cloudbeaver/core-di';
|
||||
import styles from './renderLayout.m.css';
|
||||
|
||||
interface IRender {
|
||||
initRoot(): Root;
|
||||
@@ -46,18 +46,14 @@ export function renderLayout(serviceInjector: IServiceInjector): IRender {
|
||||
},
|
||||
renderApp() {
|
||||
this.initRoot().render(
|
||||
styled`
|
||||
Loader {
|
||||
height: 100vh;
|
||||
}
|
||||
`(
|
||||
(
|
||||
<AppContext app={serviceInjector}>
|
||||
<ErrorBoundary root>
|
||||
<Suspense fallback={<Loader />}>
|
||||
<Suspense fallback={<Loader className={s(styles, { loader: true })} />}>
|
||||
<Body />
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
</AppContext>,
|
||||
</AppContext>
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.container {
|
||||
outline: none;
|
||||
}
|
||||
@@ -8,9 +8,7 @@
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useContext } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { useFocus } from '@cloudbeaver/core-blocks';
|
||||
import { s, useFocus, useS } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { isObjectsEqual } from '@cloudbeaver/core-utils';
|
||||
|
||||
@@ -22,12 +20,7 @@ import type { IView } from './IView';
|
||||
import { parseHotkey } from './parseHotkey';
|
||||
import { useActiveView } from './useActiveView';
|
||||
import { useViewContext } from './useViewContext';
|
||||
|
||||
const styles = css`
|
||||
div {
|
||||
outline: none;
|
||||
}
|
||||
`;
|
||||
import styles from './CaptureView.m.css';
|
||||
|
||||
interface Props {
|
||||
view: IView<any>;
|
||||
@@ -40,6 +33,7 @@ export const CaptureView = observer<React.PropsWithChildren<Props>>(function Cap
|
||||
const actionService = useService(ActionService);
|
||||
const activeView = useActiveView(view);
|
||||
const [ref, state] = useFocus<HTMLDivElement>({ onFocus: activeView.focusView, onBlur: activeView.blurView });
|
||||
const style = useS(styles);
|
||||
|
||||
const actionItems = view.actions
|
||||
.map(action => actionService.getAction(viewContext, action))
|
||||
@@ -85,11 +79,11 @@ export const CaptureView = observer<React.PropsWithChildren<Props>>(function Cap
|
||||
},
|
||||
);
|
||||
|
||||
return styled(styles)(
|
||||
return (
|
||||
<CaptureViewContext.Provider value={viewContext}>
|
||||
<div ref={ref} className={className} tabIndex={0}>
|
||||
<div ref={ref} className={s(style, { container: true }, className)} tabIndex={0}>
|
||||
{children}
|
||||
</div>
|
||||
</CaptureViewContext.Provider>,
|
||||
</CaptureViewContext.Provider>
|
||||
);
|
||||
});
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
.wizardStepper {
|
||||
composes: theme-background-surface theme-text-on-surface theme-border-color-background from global;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
padding: 0 16px;
|
||||
align-items: center;
|
||||
border-bottom: solid 2px;
|
||||
z-index: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.actions {
|
||||
composes: theme-border-color-background from global;
|
||||
border-right: solid 1px;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.actions,
|
||||
.wizardText {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.wizardText {
|
||||
padding: 0 16px;
|
||||
}
|
||||
+9
-41
@@ -6,60 +6,28 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { ConfigurationWizardService } from '@cloudbeaver/core-administration';
|
||||
import { Button, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { Button, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
|
||||
const styles = css`
|
||||
wizard-stepper {
|
||||
composes: theme-background-surface theme-text-on-surface theme-border-color-background from global;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
padding: 0 16px;
|
||||
align-items: center;
|
||||
border-bottom: solid 2px;
|
||||
z-index: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
actions {
|
||||
composes: theme-border-color-background from global;
|
||||
border-right: solid 1px;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
actions,
|
||||
wizard-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
wizard-text {
|
||||
padding: 0 16px;
|
||||
}
|
||||
`;
|
||||
import styles from './WizardStepper.m.css';
|
||||
|
||||
export const WizardStepper = observer(function WizardStepper() {
|
||||
const service = useService(ConfigurationWizardService);
|
||||
const translate = useTranslate();
|
||||
const style = useS(styles);
|
||||
|
||||
return styled(useStyles(styles))(
|
||||
<wizard-stepper>
|
||||
<actions>
|
||||
return (
|
||||
<div className={s(style, { wizardStepper: true })}>
|
||||
<div className={s(style, { actions: true })}>
|
||||
<Button type="button" mod={['outlined']} disabled={service.currentStepIndex === 0} onClick={() => service.back()}>
|
||||
{translate('ui_stepper_back')}
|
||||
</Button>
|
||||
<Button type="button" mod={['unelevated']} onClick={() => service.next()}>
|
||||
{translate(service.currentStepIndex === service.steps.length - 1 ? 'ui_stepper_finish' : 'ui_stepper_next')}
|
||||
</Button>
|
||||
</actions>
|
||||
<wizard-text>{translate(service.currentStep?.configurationWizardOptions?.description || '')}</wizard-text>
|
||||
</wizard-stepper>,
|
||||
</div>
|
||||
<div className={s(style, { wizardText: true })}>{translate(service.currentStep?.configurationWizardOptions?.description || '')}</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
.wizardTitle {
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
}
|
||||
+6
-13
@@ -5,21 +5,14 @@
|
||||
* 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 { Translate } from '@cloudbeaver/core-blocks';
|
||||
|
||||
const styles = css`
|
||||
wizard-title {
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
}
|
||||
`;
|
||||
import { Translate, s, useS } from '@cloudbeaver/core-blocks';
|
||||
import styles from './ConfigurationWizardTitle.m.css';
|
||||
|
||||
export function ConfigurationWizardTitle() {
|
||||
return styled(styles)(
|
||||
<wizard-title as="div">
|
||||
const style = useS(styles);
|
||||
return (
|
||||
<div className={s(style, { wizardTitle : true })}>
|
||||
<Translate token="administration_configuration_wizard_title" />
|
||||
</wizard-title>,
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
.form {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: auto;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.p {
|
||||
white-space: pre-wrap;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.loader {
|
||||
height: 100%;
|
||||
}
|
||||
+13
-30
@@ -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 { ADMINISTRATION_TOOLS_PANEL_STYLES, AdministrationItemContentComponent, ConfigurationWizardService } from '@cloudbeaver/core-administration';
|
||||
import { AdministrationItemContentComponent, ConfigurationWizardService } from '@cloudbeaver/core-administration';
|
||||
import {
|
||||
ColoredContainer,
|
||||
ConfirmationDialog,
|
||||
@@ -21,9 +20,10 @@ import {
|
||||
Placeholder,
|
||||
ToolsAction,
|
||||
ToolsPanel,
|
||||
s,
|
||||
useFocus,
|
||||
useFormValidator,
|
||||
useStyles,
|
||||
useS,
|
||||
useTranslate,
|
||||
} from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
@@ -37,28 +37,11 @@ import { ServerConfigurationNavigatorViewForm } from './Form/ServerConfiguration
|
||||
import { ServerConfigurationSecurityForm } from './Form/ServerConfigurationSecurityForm';
|
||||
import { ServerConfigurationDriversForm } from './ServerConfigurationDriversForm';
|
||||
import { ServerConfigurationService } from './ServerConfigurationService';
|
||||
|
||||
const styles = css`
|
||||
Form {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: auto;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
p {
|
||||
white-space: pre-wrap;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
Loader {
|
||||
height: 100%;
|
||||
}
|
||||
`;
|
||||
import style from './ServerConfigurationPage.m.css';
|
||||
|
||||
export const ServerConfigurationPage: AdministrationItemContentComponent = observer(function ServerConfigurationPage({ configurationWizard }) {
|
||||
const translate = useTranslate();
|
||||
const style = useStyles(styles, ADMINISTRATION_TOOLS_PANEL_STYLES);
|
||||
const styles = useS(style);
|
||||
const [focusedRef, state] = useFocus<HTMLFormElement>({ focusFirstChild: true });
|
||||
const service = useService(ServerConfigurationService);
|
||||
const serverConfigResource = useService(ServerConfigResource);
|
||||
@@ -97,10 +80,10 @@ export const ServerConfigurationPage: AdministrationItemContentComponent = obser
|
||||
}
|
||||
}
|
||||
|
||||
return styled(style)(
|
||||
<Form ref={focusedRef} name="server_config" onChange={handleChange}>
|
||||
return (
|
||||
<Form ref={focusedRef} className={s(styles, { form: true })} name="server_config" onChange={handleChange}>
|
||||
{!configurationWizard && (
|
||||
<ToolsPanel>
|
||||
<ToolsPanel hasBottomBorder>
|
||||
<ToolsAction
|
||||
title={translate('administration_configuration_tools_save_tooltip')}
|
||||
icon="admin-save"
|
||||
@@ -128,14 +111,14 @@ export const ServerConfigurationPage: AdministrationItemContentComponent = obser
|
||||
<h3>{translate('administration_configuration_wizard_configuration_title')}</h3>
|
||||
</GroupItem>
|
||||
<GroupItem>
|
||||
<p>{translate('administration_configuration_wizard_configuration_message')}</p>
|
||||
<p className={s(styles, { p: true })}>{translate('administration_configuration_wizard_configuration_message')}</p>
|
||||
</GroupItem>
|
||||
</Group>
|
||||
)}
|
||||
<Loader state={service}>
|
||||
{() =>
|
||||
styled(style)(
|
||||
<Loader suspense>
|
||||
(
|
||||
<Loader className={s(styles, { loader: true })} suspense>
|
||||
<Container wrap gap grid medium>
|
||||
<ServerConfigurationInfoForm state={service.state} />
|
||||
<Group form gap>
|
||||
@@ -149,11 +132,11 @@ export const ServerConfigurationPage: AdministrationItemContentComponent = obser
|
||||
<ServerConfigurationSecurityForm serverConfig={service.state.serverConfig} />
|
||||
<ServerConfigurationDriversForm serverConfig={service.state.serverConfig} />
|
||||
</Container>
|
||||
</Loader>,
|
||||
</Loader>
|
||||
)
|
||||
}
|
||||
</Loader>
|
||||
</ColoredContainer>
|
||||
</Form>,
|
||||
</Form>
|
||||
);
|
||||
});
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
.error {
|
||||
padding: 24px;
|
||||
}
|
||||
+50
-53
@@ -6,68 +6,63 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { ADMINISTRATION_TOOLS_PANEL_STYLES, AdministrationItemContentComponent } from '@cloudbeaver/core-administration';
|
||||
import { ColoredContainer, Container, Group, Loader, ToolsAction, ToolsPanel, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import type { AdministrationItemContentComponent } from '@cloudbeaver/core-administration';
|
||||
import { ColoredContainer, Container, ExceptionMessageStyles, Group, Loader, SContext, StyleRegistry, ToolsAction, ToolsPanel, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
|
||||
import { AuthConfigurationsTable } from './AuthConfigurationsTable/AuthConfigurationsTable';
|
||||
import { useConfigurationsTable } from './AuthConfigurationsTable/useConfigurationsTable';
|
||||
import { CreateAuthConfiguration } from './CreateAuthConfiguration';
|
||||
import { CreateAuthConfigurationService } from './CreateAuthConfigurationService';
|
||||
import AuthConfigurationsAdministrationStyle from './AuthConfigurationsAdministration.m.css';
|
||||
|
||||
const loaderStyle = css`
|
||||
ExceptionMessage {
|
||||
padding: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
const styles = css`
|
||||
ToolsPanel {
|
||||
border-bottom: none;
|
||||
}
|
||||
`;
|
||||
const registry: StyleRegistry = [[
|
||||
ExceptionMessageStyles,
|
||||
{
|
||||
mode: 'append',
|
||||
styles: [AuthConfigurationsAdministrationStyle],
|
||||
},
|
||||
]];
|
||||
|
||||
export const AuthConfigurationsAdministration: AdministrationItemContentComponent = observer(function AuthConfigurationsAdministration({ sub }) {
|
||||
const translate = useTranslate();
|
||||
const style = useStyles(styles, ADMINISTRATION_TOOLS_PANEL_STYLES);
|
||||
const service = useService(CreateAuthConfigurationService);
|
||||
|
||||
const table = useConfigurationsTable();
|
||||
|
||||
return styled(style)(
|
||||
return (
|
||||
<ColoredContainer wrap gap parent vertical>
|
||||
<Group box keepSize>
|
||||
<ToolsPanel>
|
||||
<ToolsAction
|
||||
title={translate('administration_identity_providers_add_tooltip')}
|
||||
icon="add"
|
||||
viewBox="0 0 24 24"
|
||||
disabled={!!sub || table.processing}
|
||||
onClick={service.create}
|
||||
>
|
||||
{translate('ui_add')}
|
||||
</ToolsAction>
|
||||
<ToolsAction
|
||||
title={translate('administration_identity_providers_refresh_tooltip')}
|
||||
icon="refresh"
|
||||
viewBox="0 0 24 24"
|
||||
disabled={table.processing}
|
||||
onClick={table.update}
|
||||
>
|
||||
{translate('ui_refresh')}
|
||||
</ToolsAction>
|
||||
<ToolsAction
|
||||
title={translate('administration_identity_providers_delete_tooltip')}
|
||||
icon="trash"
|
||||
viewBox="0 0 24 24"
|
||||
disabled={!table.tableState.itemsSelected || table.processing}
|
||||
onClick={table.delete}
|
||||
>
|
||||
{translate('ui_delete')}
|
||||
</ToolsAction>
|
||||
</ToolsPanel>
|
||||
<ToolsPanel>
|
||||
<ToolsAction
|
||||
title={translate('administration_identity_providers_add_tooltip')}
|
||||
icon="add"
|
||||
viewBox="0 0 24 24"
|
||||
disabled={!!sub || table.processing}
|
||||
onClick={service.create}
|
||||
>
|
||||
{translate('ui_add')}
|
||||
</ToolsAction>
|
||||
<ToolsAction
|
||||
title={translate('administration_identity_providers_refresh_tooltip')}
|
||||
icon="refresh"
|
||||
viewBox="0 0 24 24"
|
||||
disabled={table.processing}
|
||||
onClick={table.update}
|
||||
>
|
||||
{translate('ui_refresh')}
|
||||
</ToolsAction>
|
||||
<ToolsAction
|
||||
title={translate('administration_identity_providers_delete_tooltip')}
|
||||
icon="trash"
|
||||
viewBox="0 0 24 24"
|
||||
disabled={!table.tableState.itemsSelected || table.processing}
|
||||
onClick={table.delete}
|
||||
>
|
||||
{translate('ui_delete')}
|
||||
</ToolsAction>
|
||||
</ToolsPanel>
|
||||
</Group>
|
||||
<Container overflow gap>
|
||||
{sub && (
|
||||
@@ -76,15 +71,17 @@ export const AuthConfigurationsAdministration: AdministrationItemContentComponen
|
||||
</Group>
|
||||
)}
|
||||
<Group boxNoOverflow>
|
||||
<Loader style={loaderStyle} loading={table.processing} overlay>
|
||||
<AuthConfigurationsTable
|
||||
configurations={table.configurations}
|
||||
selectedItems={table.tableState.selected}
|
||||
expandedItems={table.tableState.expanded}
|
||||
/>
|
||||
</Loader>
|
||||
<SContext registry={registry}>
|
||||
<Loader loading={table.processing} overlay>
|
||||
<AuthConfigurationsTable
|
||||
configurations={table.configurations}
|
||||
selectedItems={table.tableState.selected}
|
||||
expandedItems={table.tableState.expanded}
|
||||
/>
|
||||
</Loader>
|
||||
</SContext>
|
||||
</Group>
|
||||
</Container>
|
||||
</ColoredContainer>,
|
||||
</ColoredContainer>
|
||||
);
|
||||
});
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
.group {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.group,
|
||||
.container,
|
||||
.tableContainer {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tableContainer {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.grantedConnectionsTableHeader {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.table {
|
||||
composes: theme-background-surface theme-text-on-surface from global;
|
||||
width: 100%;
|
||||
}
|
||||
+13
-38
@@ -8,19 +8,19 @@
|
||||
import { observable } from 'mobx';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useCallback, useState } from 'react';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import {
|
||||
Button,
|
||||
getComputed,
|
||||
getSelectedItems,
|
||||
Group,
|
||||
s,
|
||||
Table,
|
||||
TableBody,
|
||||
TableColumnValue,
|
||||
TableItem,
|
||||
useObjectRef,
|
||||
useStyles,
|
||||
useS,
|
||||
useTranslate,
|
||||
} from '@cloudbeaver/core-blocks';
|
||||
import { Connection, DBDriverResource } from '@cloudbeaver/core-connections';
|
||||
@@ -30,32 +30,7 @@ import { getFilteredConnections } from './getFilteredConnections';
|
||||
import { GrantedConnectionsTableHeader, IFilterState } from './GrantedConnectionsTableHeader/GrantedConnectionsTableHeader';
|
||||
import { GrantedConnectionsTableInnerHeader } from './GrantedConnectionsTableHeader/GrantedConnectionsTableInnerHeader';
|
||||
import { GrantedConnectionsTableItem } from './GrantedConnectionsTableItem';
|
||||
|
||||
const styles = css`
|
||||
Group {
|
||||
position: relative;
|
||||
}
|
||||
Group,
|
||||
container,
|
||||
table-container {
|
||||
height: 100%;
|
||||
}
|
||||
container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
table-container {
|
||||
overflow: auto;
|
||||
}
|
||||
GrantedConnectionsTableHeader {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
Table {
|
||||
composes: theme-background-surface theme-text-on-surface from global;
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
import styles from './ConnectionList.m.css';
|
||||
|
||||
interface Props {
|
||||
connectionList: Connection[];
|
||||
@@ -66,7 +41,7 @@ interface Props {
|
||||
|
||||
export const ConnectionList = observer<Props>(function ConnectionList({ connectionList, grantedSubjects, disabled, onGrant }) {
|
||||
const props = useObjectRef({ onGrant });
|
||||
const style = useStyles(styles);
|
||||
const style = useS(styles);
|
||||
const translate = useTranslate();
|
||||
|
||||
const driversResource = useService(DBDriverResource);
|
||||
@@ -84,17 +59,17 @@ export const ConnectionList = observer<Props>(function ConnectionList({ connecti
|
||||
const connections = getFilteredConnections(connectionList, filterState.filterValue);
|
||||
const keys = connections.map(connection => connection.id);
|
||||
|
||||
return styled(style)(
|
||||
<Group box medium overflow>
|
||||
<container>
|
||||
return (
|
||||
<Group className={s(style, { group: true })} box medium overflow>
|
||||
<div className={s(style, { container: true })}>
|
||||
<GrantedConnectionsTableHeader filterState={filterState} disabled={disabled}>
|
||||
<Button disabled={disabled || !selected} mod={['unelevated']} onClick={grant}>
|
||||
{translate('ui_add')}
|
||||
</Button>
|
||||
</GrantedConnectionsTableHeader>
|
||||
<table-container>
|
||||
<Table keys={keys} selectedItems={selectedSubjects} isItemSelectable={item => !grantedSubjects.includes(item)} size="big">
|
||||
<GrantedConnectionsTableInnerHeader disabled={disabled} />
|
||||
<div className={s(style, { tableContainer: true })}>
|
||||
<Table className={s(style, { table: true })} keys={keys} selectedItems={selectedSubjects} isItemSelectable={item => !grantedSubjects.includes(item)} size="big">
|
||||
<GrantedConnectionsTableInnerHeader className={s(style, { grantedConnectionsTableHeader: true })} disabled={disabled} />
|
||||
<TableBody>
|
||||
{!connections.length && filterState.filterValue && (
|
||||
<TableItem item="tableInfo" selectDisabled>
|
||||
@@ -117,8 +92,8 @@ export const ConnectionList = observer<Props>(function ConnectionList({ connecti
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</table-container>
|
||||
</container>
|
||||
</Group>,
|
||||
</div>
|
||||
</div>
|
||||
</Group>
|
||||
);
|
||||
});
|
||||
|
||||
+4
-14
@@ -6,10 +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 { ADMINISTRATION_TOOLS_PANEL_STYLES, IAdministrationItemSubItem } from '@cloudbeaver/core-administration';
|
||||
import { ColoredContainer, Container, Group, ToolsAction, ToolsPanel, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { ColoredContainer, Container, Group, ToolsAction, ToolsPanel, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
|
||||
import { CreateTeam } from './CreateTeam';
|
||||
@@ -17,26 +15,18 @@ import { CreateTeamService } from './CreateTeamService';
|
||||
import { TeamsTable } from './TeamsTable/TeamsTable';
|
||||
import { useTeamsTable } from './TeamsTable/useTeamsTable';
|
||||
|
||||
const styles = css`
|
||||
ToolsPanel {
|
||||
border-bottom: none;
|
||||
}
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
sub?: IAdministrationItemSubItem;
|
||||
param?: string | null;
|
||||
}
|
||||
|
||||
export const TeamsPage = observer<Props>(function TeamsPage({ sub, param }) {
|
||||
export const TeamsPage = observer<Props>(function TeamsPage({ param }) {
|
||||
const translate = useTranslate();
|
||||
const style = useStyles(styles, ADMINISTRATION_TOOLS_PANEL_STYLES);
|
||||
const service = useService(CreateTeamService);
|
||||
|
||||
const table = useTeamsTable();
|
||||
const create = param === 'create';
|
||||
|
||||
return styled(style)(
|
||||
return (
|
||||
<ColoredContainer vertical wrap gap parent>
|
||||
<Group box keepSize>
|
||||
<ToolsPanel>
|
||||
@@ -80,6 +70,6 @@ export const TeamsPage = observer<Props>(function TeamsPage({ sub, param }) {
|
||||
<TeamsTable teams={table.teams} state={table.state} selectedItems={table.tableState.selected} expandedItems={table.tableState.expanded} />
|
||||
</Group>
|
||||
</Container>
|
||||
</ColoredContainer>,
|
||||
</ColoredContainer>
|
||||
);
|
||||
});
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
.error {
|
||||
padding: 24px;
|
||||
}
|
||||
+30
-26
@@ -6,19 +6,21 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { css } from 'reshadow';
|
||||
|
||||
import type { TeamInfo } from '@cloudbeaver/core-authentication';
|
||||
import { Loader, Table, TableBody, TableColumnHeader, TableHeader, TableSelect, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { ExceptionMessageStyles, Loader, SContext, StyleRegistry, Table, TableBody, TableColumnHeader, TableHeader, TableSelect, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { Team } from './Team';
|
||||
import teamsTableStyle from './TeamsTable.m.css';
|
||||
|
||||
const loaderStyle = css`
|
||||
ExceptionMessage {
|
||||
padding: 24px;
|
||||
}
|
||||
`;
|
||||
const registry: StyleRegistry = [[
|
||||
ExceptionMessageStyles,
|
||||
{
|
||||
mode: 'append',
|
||||
styles: [teamsTableStyle],
|
||||
},
|
||||
]];
|
||||
|
||||
interface Props {
|
||||
teams: TeamInfo[];
|
||||
@@ -32,24 +34,26 @@ export const TeamsTable = observer<Props>(function TeamsTable({ teams, state, se
|
||||
const keys = teams.map(team => team.teamId);
|
||||
|
||||
return (
|
||||
<Loader state={state} style={loaderStyle} overlay>
|
||||
<Table keys={keys} selectedItems={selectedItems} expandedItems={expandedItems} size="big">
|
||||
<TableHeader fixed>
|
||||
<TableColumnHeader min flex centerContent>
|
||||
<TableSelect />
|
||||
</TableColumnHeader>
|
||||
<TableColumnHeader min />
|
||||
<TableColumnHeader>{translate('administration_teams_team_id')}</TableColumnHeader>
|
||||
<TableColumnHeader>{translate('administration_teams_team_name')}</TableColumnHeader>
|
||||
<TableColumnHeader>{translate('administration_teams_team_description')}</TableColumnHeader>
|
||||
<TableColumnHeader />
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{teams.map(team => (
|
||||
<Team key={team.teamId} team={team} />
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Loader>
|
||||
<SContext registry={registry}>
|
||||
<Loader state={state} overlay>
|
||||
<Table keys={keys} selectedItems={selectedItems} expandedItems={expandedItems} size="big">
|
||||
<TableHeader fixed>
|
||||
<TableColumnHeader min flex centerContent>
|
||||
<TableSelect />
|
||||
</TableColumnHeader>
|
||||
<TableColumnHeader min />
|
||||
<TableColumnHeader>{translate('administration_teams_team_id')}</TableColumnHeader>
|
||||
<TableColumnHeader>{translate('administration_teams_team_name')}</TableColumnHeader>
|
||||
<TableColumnHeader>{translate('administration_teams_team_description')}</TableColumnHeader>
|
||||
<TableColumnHeader />
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{teams.map(team => (
|
||||
<Team key={team.teamId} team={team} />
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Loader>
|
||||
</SContext>
|
||||
);
|
||||
});
|
||||
|
||||
+5
-5
@@ -8,7 +8,7 @@
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { ADMINISTRATION_TOOLS_PANEL_STYLES, AdministrationItemContentComponent } from '@cloudbeaver/core-administration';
|
||||
import type { AdministrationItemContentComponent } from '@cloudbeaver/core-administration';
|
||||
import { s, ToolsPanel, useS, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { BASE_TAB_STYLES, ITabData, Tab, TabList, TabPanel, TabsState, TabTitle, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui';
|
||||
@@ -28,7 +28,7 @@ const tabsStyles = css`
|
||||
}
|
||||
`;
|
||||
|
||||
const tabStyle = [ADMINISTRATION_TOOLS_PANEL_STYLES, BASE_TAB_STYLES, tabsStyles, UNDERLINE_TAB_STYLES];
|
||||
const tabStyle = [BASE_TAB_STYLES, tabsStyles, UNDERLINE_TAB_STYLES];
|
||||
|
||||
export const UsersAdministration: AdministrationItemContentComponent = observer(function UsersAdministration({ sub, param }) {
|
||||
const translate = useTranslate();
|
||||
@@ -48,7 +48,7 @@ export const UsersAdministration: AdministrationItemContentComponent = observer(
|
||||
|
||||
return styled(useStyles(tabStyle))(
|
||||
<TabsState selectedId={subName} lazy onChange={openSub}>
|
||||
<ToolsPanel className={s(styles, { tabPanel: true })}>
|
||||
<ToolsPanel className={s(styles, { tabPanel: true })} hasBottomBorder>
|
||||
<TabList className={s(styles, { tabList: true })} aria-label="User Administration pages" style={tabStyle}>
|
||||
<Tab className={s(styles, { tab: true })} tabId={EUsersAdministrationSub.Users} style={tabStyle}>
|
||||
<TabTitle className={s(styles, { tabTitle: true })}>{translate('authentication_administration_item_users')}</TabTitle>
|
||||
@@ -59,10 +59,10 @@ export const UsersAdministration: AdministrationItemContentComponent = observer(
|
||||
</TabList>
|
||||
</ToolsPanel>
|
||||
<TabPanel className={s(styles, { tabPanel: true })} tabId={EUsersAdministrationSub.Users}>
|
||||
<UsersPage sub={sub} param={param} />
|
||||
<UsersPage param={param} />
|
||||
</TabPanel>
|
||||
<TabPanel className={s(styles, { tabPanel: true })} tabId={EUsersAdministrationSub.Teams}>
|
||||
<TeamsPage sub={sub} param={param} />
|
||||
<TeamsPage param={param} />
|
||||
</TabPanel>
|
||||
</TabsState>,
|
||||
);
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
.toolsPanel {
|
||||
border-bottom: none;
|
||||
border-radius: inherit;
|
||||
|
||||
& .menuBar {
|
||||
|
||||
+4
-9
@@ -6,11 +6,8 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import styled from 'reshadow';
|
||||
|
||||
import { ADMINISTRATION_TOOLS_PANEL_STYLES, IAdministrationItemSubItem } from '@cloudbeaver/core-administration';
|
||||
import { AuthRolesResource } from '@cloudbeaver/core-authentication';
|
||||
import { ColoredContainer, Container, Group, Placeholder, useAutoLoad, useResource, useStyles } from '@cloudbeaver/core-blocks';
|
||||
import { ColoredContainer, Container, Group, Placeholder, useAutoLoad, useResource } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
|
||||
import { AdministrationUsersManagementService } from '../../../AdministrationUsersManagementService';
|
||||
@@ -23,12 +20,10 @@ import { UsersTable } from './UsersTable';
|
||||
import { useUsersTable } from './useUsersTable';
|
||||
|
||||
interface Props {
|
||||
sub?: IAdministrationItemSubItem;
|
||||
param?: string | null;
|
||||
}
|
||||
|
||||
export const UsersPage = observer<Props>(function UsersPage({ sub, param }) {
|
||||
const style = useStyles(ADMINISTRATION_TOOLS_PANEL_STYLES);
|
||||
export const UsersPage = observer<Props>(function UsersPage({ param }) {
|
||||
const createUserService = useService(CreateUserService);
|
||||
const authRolesResource = useResource(UsersPage, AuthRolesResource, undefined);
|
||||
const administrationUsersManagementService = useService(AdministrationUsersManagementService);
|
||||
@@ -42,7 +37,7 @@ export const UsersPage = observer<Props>(function UsersPage({ sub, param }) {
|
||||
const loading = authRolesResource.isLoading() || table.loadableState.isLoading();
|
||||
const userManagementDisabled = administrationUsersManagementService.externalUserProviderEnabled;
|
||||
|
||||
return styled(style)(
|
||||
return (
|
||||
<ColoredContainer vertical wrap gap parent>
|
||||
<Group box keepSize>
|
||||
<UsersAdministrationToolsPanel onUpdate={table.update} />
|
||||
@@ -73,6 +68,6 @@ export const UsersPage = observer<Props>(function UsersPage({ sub, param }) {
|
||||
/>
|
||||
</Group>
|
||||
</Container>
|
||||
</ColoredContainer>,
|
||||
</ColoredContainer>
|
||||
);
|
||||
});
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
.groupItem {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.error {
|
||||
padding: 24px;
|
||||
}
|
||||
+28
-30
@@ -6,20 +6,23 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { ADMINISTRATION_TOOLS_PANEL_STYLES, AdministrationItemContentProps } from '@cloudbeaver/core-administration';
|
||||
import type { AdministrationItemContentProps } from '@cloudbeaver/core-administration';
|
||||
import {
|
||||
ColoredContainer,
|
||||
Container,
|
||||
ExceptionMessageStyles,
|
||||
Group,
|
||||
GroupItem,
|
||||
GroupTitle,
|
||||
Loader,
|
||||
SContext,
|
||||
StyleRegistry,
|
||||
ToolsAction,
|
||||
ToolsPanel,
|
||||
s,
|
||||
useResource,
|
||||
useStyles,
|
||||
useS,
|
||||
useTranslate,
|
||||
} from '@cloudbeaver/core-blocks';
|
||||
import { ConnectionInfoActiveProjectKey, ConnectionInfoResource, DBDriverResource } from '@cloudbeaver/core-connections';
|
||||
@@ -30,22 +33,15 @@ import { ConnectionsAdministrationController } from './ConnectionsAdministration
|
||||
import { ConnectionsTable } from './ConnectionsTable/ConnectionsTable';
|
||||
import { CreateConnection } from './CreateConnection/CreateConnection';
|
||||
import { CreateConnectionService } from './CreateConnectionService';
|
||||
import ConnectionsAdministrationStyle from './ConnectionsAdministration.m.css';
|
||||
|
||||
const loaderStyle = css`
|
||||
ExceptionMessage {
|
||||
padding: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
const styles = css`
|
||||
GroupItem {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
ToolsPanel {
|
||||
border-bottom: none;
|
||||
}
|
||||
`;
|
||||
const registry: StyleRegistry = [[
|
||||
ExceptionMessageStyles,
|
||||
{
|
||||
mode: 'append',
|
||||
styles: [ConnectionsAdministrationStyle],
|
||||
},
|
||||
]];
|
||||
|
||||
export const ConnectionsAdministration = observer<AdministrationItemContentProps>(function ConnectionsAdministration({
|
||||
sub,
|
||||
@@ -55,7 +51,7 @@ export const ConnectionsAdministration = observer<AdministrationItemContentProps
|
||||
const service = useService(CreateConnectionService);
|
||||
const controller = useController(ConnectionsAdministrationController);
|
||||
const translate = useTranslate();
|
||||
const style = useStyles(styles, ADMINISTRATION_TOOLS_PANEL_STYLES);
|
||||
const style = useS(ConnectionsAdministrationStyle);
|
||||
|
||||
useResource(ConnectionsAdministration, ConnectionInfoResource, {
|
||||
key: ConnectionInfoActiveProjectKey,
|
||||
@@ -63,7 +59,7 @@ export const ConnectionsAdministration = observer<AdministrationItemContentProps
|
||||
});
|
||||
useResource(ConnectionsAdministration, DBDriverResource, CachedMapAllKey);
|
||||
|
||||
return styled(style)(
|
||||
return (
|
||||
<ColoredContainer vertical wrap parent gap>
|
||||
<Group box keepSize>
|
||||
<ToolsPanel>
|
||||
@@ -100,7 +96,7 @@ export const ConnectionsAdministration = observer<AdministrationItemContentProps
|
||||
{configurationWizard && (
|
||||
<Group gap>
|
||||
<GroupTitle>{translate('connections_administration_configuration_wizard_title')}</GroupTitle>
|
||||
<GroupItem>{translate('connections_administration_configuration_wizard_message')}</GroupItem>
|
||||
<GroupItem className={s(style, { groupItem: true })}>{translate('connections_administration_configuration_wizard_message')}</GroupItem>
|
||||
</Group>
|
||||
)}
|
||||
{sub && (
|
||||
@@ -109,16 +105,18 @@ export const ConnectionsAdministration = observer<AdministrationItemContentProps
|
||||
</Group>
|
||||
)}
|
||||
<Group boxNoOverflow>
|
||||
<Loader style={loaderStyle} loading={controller.isProcessing} overlay>
|
||||
<ConnectionsTable
|
||||
keys={controller.keys}
|
||||
connections={controller.connections}
|
||||
selectedItems={controller.selectedItems}
|
||||
expandedItems={controller.expandedItems}
|
||||
/>
|
||||
</Loader>
|
||||
<SContext registry={registry}>
|
||||
<Loader loading={controller.isProcessing} overlay>
|
||||
<ConnectionsTable
|
||||
keys={controller.keys}
|
||||
connections={controller.connections}
|
||||
selectedItems={controller.selectedItems}
|
||||
expandedItems={controller.expandedItems}
|
||||
/>
|
||||
</Loader>
|
||||
</SContext>
|
||||
</Group>
|
||||
</Container>
|
||||
</ColoredContainer>,
|
||||
</ColoredContainer>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -20,13 +20,6 @@ import { TableFooterMenu } from './TableFooterMenu/TableFooterMenu';
|
||||
import { TableFooterRowCount } from './TableFooterRowCount';
|
||||
|
||||
const tableFooterStyles = css`
|
||||
ToolsPanel {
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
overflow: auto;
|
||||
min-height: 32px;
|
||||
height: initial;
|
||||
}
|
||||
count input,
|
||||
count placeholder {
|
||||
height: 26px;
|
||||
@@ -103,7 +96,7 @@ export const TableFooter = observer<Props>(function TableFooter({ resultIndex, m
|
||||
const disabled = getComputed(() => model.isLoading() || model.isDisabled(resultIndex));
|
||||
|
||||
return styled(tableFooterStyles)(
|
||||
<ToolsPanel>
|
||||
<ToolsPanel type="secondary">
|
||||
{/* <reload aria-disabled={disabled} onClick={() => model.refresh()}>
|
||||
<IconOrImage icon='reload' viewBox="0 0 16 16" />
|
||||
</reload> */}
|
||||
@@ -130,6 +123,6 @@ export const TableFooter = observer<Props>(function TableFooter({ resultIndex, m
|
||||
{model.source.requestInfo.requestMessage} - {model.source.requestInfo.requestDuration}ms
|
||||
</time>
|
||||
)}
|
||||
</ToolsPanel>,
|
||||
</ToolsPanel>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.group {
|
||||
list-style-position: inside;
|
||||
height: 100%;
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.reactMarkdown > * {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -7,44 +7,32 @@
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { Container, Group, GroupItem, GroupTitle, useResource, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { Container, Group, GroupItem, GroupTitle, s, useResource, useS, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { VersionResource } from '@cloudbeaver/core-version';
|
||||
import styles from './VersionInfo.m.css';
|
||||
|
||||
interface Props {
|
||||
item: string;
|
||||
}
|
||||
|
||||
const style = css`
|
||||
Group {
|
||||
list-style-position: inside;
|
||||
height: 100%;
|
||||
max-height: 300px;
|
||||
}
|
||||
ReactMarkdown > * {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
export const VersionInfo = observer<Props>(function VersionInfo({ item }) {
|
||||
const translate = useTranslate();
|
||||
const styles = useStyles(style);
|
||||
const style = useS(styles);
|
||||
const versionResource = useResource(VersionInfo, VersionResource, item);
|
||||
|
||||
const version = versionResource.tryGetData;
|
||||
|
||||
return styled(styles)(
|
||||
return (
|
||||
<Container wrap gap overflow large>
|
||||
<Group gap overflow>
|
||||
<Group className={s(style, { group: true })} gap overflow>
|
||||
<GroupTitle>{version ? `Release notes ${version.number} - ${version.date}` : translate('version_update_version_no_info')}</GroupTitle>
|
||||
{version && (
|
||||
<GroupItem>
|
||||
<ReactMarkdown>{version.releaseNotes}</ReactMarkdown>
|
||||
<ReactMarkdown className={s(style, { reactMarkdown: true })}>{version.releaseNotes}</ReactMarkdown>
|
||||
</GroupItem>
|
||||
)}
|
||||
</Group>
|
||||
</Container>,
|
||||
</Container>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
.group {
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
.instruction {
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.h4 {
|
||||
margin: 0;
|
||||
}
|
||||
@@ -7,37 +7,26 @@
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useEffect, useState } from 'react';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { Combobox, Container, Group, GroupItem, GroupTitle, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { Combobox, Container, Group, GroupItem, GroupTitle, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { ServerConfigResource } from '@cloudbeaver/core-root';
|
||||
import { IVersion, VersionResource } from '@cloudbeaver/core-version';
|
||||
import { VersionUpdateService } from '@cloudbeaver/core-version-update';
|
||||
|
||||
import { VersionInfo } from './VersionInfo';
|
||||
import styles from './VersionSelector.m.css';
|
||||
|
||||
interface Props {
|
||||
versions: IVersion[];
|
||||
}
|
||||
|
||||
const style = css`
|
||||
Group {
|
||||
list-style-position: inside;
|
||||
}
|
||||
Instruction {
|
||||
white-space: pre-line;
|
||||
}
|
||||
h4 {
|
||||
margin: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
export const VersionSelector = observer<Props>(function VersionSelector({ versions }) {
|
||||
const versionUpdateService = useService(VersionUpdateService);
|
||||
const versionResource = useService(VersionResource);
|
||||
const serverConfigResource = useService(ServerConfigResource);
|
||||
const translate = useTranslate();
|
||||
const style = useS(styles);
|
||||
|
||||
const [selected, setSelected] = useState('');
|
||||
|
||||
@@ -50,9 +39,9 @@ export const VersionSelector = observer<Props>(function VersionSelector({ versio
|
||||
const version = versions.find(v => v.number === selected);
|
||||
const Instruction = versionUpdateService.versionInstructionGetter?.();
|
||||
|
||||
return styled(style)(
|
||||
return (
|
||||
<Container gap>
|
||||
<Group gap large>
|
||||
<Group className={s(style, { group: true })} gap large>
|
||||
<Combobox
|
||||
items={versions}
|
||||
keySelector={value => value.number}
|
||||
@@ -65,15 +54,15 @@ export const VersionSelector = observer<Props>(function VersionSelector({ versio
|
||||
</Combobox>
|
||||
{version && Instruction && (
|
||||
<GroupItem>
|
||||
<Instruction version={version} containerId={serverConfigResource.data?.containerId} />
|
||||
<Instruction className={s(style, { instruction: true })} version={version} containerId={serverConfigResource.data?.containerId} />
|
||||
</GroupItem>
|
||||
)}
|
||||
<GroupTitle>{translate('plugin_version_update_administration_recommendations_label')}</GroupTitle>
|
||||
<GroupItem>
|
||||
<h4>{translate('plugin_version_update_administration_recommendations')}</h4>
|
||||
<h4 className={s(style, { h4: true })}>{translate('plugin_version_update_administration_recommendations')}</h4>
|
||||
</GroupItem>
|
||||
</Group>
|
||||
{version && <VersionInfo item={version.number} />}
|
||||
</Container>,
|
||||
</Container>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
.coloredContainer {
|
||||
composes: theme-typography--body2 from global;
|
||||
list-style-position: inside;
|
||||
}
|
||||
@@ -6,11 +6,10 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import styled, { css } from 'reshadow';
|
||||
import { gte } from 'semver';
|
||||
|
||||
import type { AdministrationItemContentComponent } from '@cloudbeaver/core-administration';
|
||||
import { ColoredContainer, useResource, useStyles } from '@cloudbeaver/core-blocks';
|
||||
import { ColoredContainer, s, useResource, useS, useStyles } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { CachedMapAllKey } from '@cloudbeaver/core-resource';
|
||||
import { VersionResource, VersionService } from '@cloudbeaver/core-version';
|
||||
@@ -18,16 +17,10 @@ import { VersionUpdateService } from '@cloudbeaver/core-version-update';
|
||||
|
||||
import { VersionChecker } from './VersionChecker';
|
||||
import { VersionSelector } from './VersionSelector';
|
||||
|
||||
const styles = css`
|
||||
ColoredContainer {
|
||||
composes: theme-typography--body2 from global;
|
||||
list-style-position: inside;
|
||||
}
|
||||
`;
|
||||
import styles from './VersionUpdate.m.css';
|
||||
|
||||
export const VersionUpdate: AdministrationItemContentComponent = observer(function VersionUpdate() {
|
||||
const style = useStyles(styles);
|
||||
const style = useS(styles);
|
||||
const versionService = useService(VersionService);
|
||||
const versionUpdateService = useService(VersionUpdateService);
|
||||
const versionResource = useResource(VersionUpdate, VersionResource, CachedMapAllKey, {
|
||||
@@ -37,8 +30,8 @@ export const VersionUpdate: AdministrationItemContentComponent = observer(functi
|
||||
const GeneralInstructions = versionUpdateService.generalInstructionsGetter?.();
|
||||
const versions = versionResource.resource.values.filter(v => gte(v.number, versionService.current));
|
||||
|
||||
return styled(style)(
|
||||
<ColoredContainer wrap gap overflow parent>
|
||||
return (
|
||||
<ColoredContainer className={s(style, { coloredContainer: true })} wrap gap overflow parent>
|
||||
<VersionChecker />
|
||||
{versions.length > 0 && (
|
||||
<>
|
||||
@@ -46,6 +39,6 @@ export const VersionUpdate: AdministrationItemContentComponent = observer(functi
|
||||
<VersionSelector versions={versions} />
|
||||
</>
|
||||
)}
|
||||
</ColoredContainer>,
|
||||
</ColoredContainer>
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user