refactor: CB-1093 types

This commit is contained in:
Wroud
2021-07-16 22:41:51 +03:00
parent 780b85e4ae
commit f65cf434af
22 changed files with 83 additions and 353 deletions
@@ -10,17 +10,31 @@ import { useEffect, useState } from 'react';
import { IServiceConstructor, useService } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import { CachedResourceIncludeArgs, CachedMapResource, CachedMapResourceGetter, isResourceKeyList, ResourceKey, CachedMapResourceValue, CachedMapResourceKey, CachedMapResourceArguments } from '@cloudbeaver/core-sdk';
import { CachedResourceIncludeArgs, CachedMapResource, CachedMapResourceGetter, ResourceKey, CachedMapResourceValue, CachedMapResourceKey, CachedMapResourceArguments, CachedMapResourceLoader } from '@cloudbeaver/core-sdk';
import { useObjectRef } from './useObjectRef';
interface IActions<TResource extends CachedMapResource<any, any, any>> {
interface IActions<
TKeyArg extends ResourceKey<CachedMapResourceKey<TResource>>,
TResource extends CachedMapResource<any, any, any>,
TIncludes
> {
isActive?: () => Promise<boolean> | boolean;
onLoad?: (resource: TResource) => Promise<any> | any;
onData?: (
data: CachedMapResourceValue<TResource>,
data: CachedMapResourceLoader<
TKeyArg,
CachedMapResourceKey<TResource>,
CachedMapResourceValue<TResource>,
TIncludes
>,
resource: TResource,
prevData: CachedMapResourceValue<TResource> | undefined,
prevData: CachedMapResourceLoader<
TKeyArg,
CachedMapResourceKey<TResource>,
CachedMapResourceValue<TResource>,
TIncludes
> | undefined,
) => Promise<any> | any;
onError?: (exception: Error) => void;
}
@@ -53,7 +67,7 @@ export function useMapResource<
>(
ctor: IServiceConstructor<TResource> | TResource,
keyObj: TResource extends any ? TKeyArg | null | KeyWithIncludes<TKeyArg, TIncludes> : never,
actions?: IActions<TResource>
actions?: TResource extends any ? IActions<TKeyArg, TResource, TIncludes> : never
): IMapResourceResult<TKeyArg, TResource, TIncludes> {
// eslint-disable-next-line react-hooks/rules-of-hooks
const resource = ctor instanceof CachedMapResource ? ctor : useService(ctor);
@@ -74,7 +88,12 @@ export function useMapResource<
exception,
includes,
actions,
prevData: (isResourceKeyList(key) ? [] : undefined) as CachedMapResourceValue<TResource> | undefined,
prevData: undefined as CachedMapResourceLoader<
TKeyArg,
CachedMapResourceKey<TResource>,
CachedMapResourceValue<TResource>,
TIncludes
> | undefined,
load: () => {},
}, {
resource,
@@ -18,14 +18,15 @@ import { CONNECTION_DETAILS_STYLES } from './ConnectionDetailsStyles';
export const Origin: PlaceholderComponent<IConnectionDetailsPlaceholderProps> = observer(function Origin({
connection,
}) {
const isLocal = connection.origin.type === AUTH_PROVIDER_LOCAL_ID;
const icon = connection.origin.icon;
const title = connection.origin.displayName;
const isLocal = connection.origin?.type === AUTH_PROVIDER_LOCAL_ID;
if (isLocal) {
if (!connection.origin || isLocal) {
return null;
}
const icon = connection.origin.icon;
const title = connection.origin.displayName;
return styled(CONNECTION_DETAILS_STYLES)(
<StaticImage icon={icon} title={title} />
);
@@ -267,6 +267,9 @@ export function isLocalConnection(connection: DatabaseConnection): boolean {
}
export function isCloudConnection(connection: DatabaseConnection): boolean {
if (!connection.origin) {
return false;
}
return connection.origin.type === 'cloud';
}
@@ -39,10 +39,12 @@ export class ConnectionAuthService {
return connection;
}
const state = await this.authProviderService.requireProvider(connection.origin);
if (connection.origin) {
const state = await this.authProviderService.requireProvider(connection.origin);
if (!state) {
return connection;
if (!state) {
return connection;
}
}
await this.connectionInfoResource.waitLoad();
@@ -323,9 +323,9 @@ export class ConnectionOptionsTabService extends Bootstrap {
): Promise<ObjectPropertyInfo[]> {
const authModel = await this.databaseAuthModelsResource.load(authModelId);
let properties = authModel?.properties;
let properties = authModel.properties;
if (connectionInfo && connectionInfo.authProperties.length > 0) {
if (connectionInfo?.authProperties && connectionInfo.authProperties.length > 0) {
properties = connectionInfo.authProperties;
}
@@ -22,7 +22,7 @@ export const OriginInfoTab: TabContainerTabComponent<IConnectionFormProps> = obs
}) {
return styled(useStyles(style))(
<Tab {...rest} style={style}>
<TabTitle><Translate token={info?.origin.displayName || 'Origin'} /></TabTitle>
<TabTitle><Translate token={info?.origin?.displayName || 'Origin'} /></TabTitle>
</Tab>
);
});
@@ -36,6 +36,15 @@ export type CachedMapResourceGetter<
? Array<CachedResourceValueIncludes<TValue, TIncludes> | undefined>
: CachedResourceValueIncludes<TValue, TIncludes> | undefined;
export type CachedMapResourceLoader<
TRealKey extends ResourceKey<TKey>,
TKey,
TValue,
TIncludes
> = TRealKey extends ResourceKeyList<TKey>
? Array<CachedResourceValueIncludes<TValue, TIncludes>>
: CachedResourceValueIncludes<TValue, TIncludes>;
export interface ICachedMapResourceMetadata extends ICachedResourceMetadata {
includes: string[];
}
@@ -103,7 +103,9 @@ export const CellRenderer: React.FC<CellRendererProps<any>> = observer(function
return;
}
if (!this.column.editable
if (
!this.column.editable
|| this.dataGridContext?.model.isDisabled(this.dataGridContext.resultIndex)
|| (
this.resultColumn
&& isBooleanFormatterAvailable(this.editor?.getCell(this.rowIdx, Number(this.column.key)), this.resultColumn)
@@ -34,7 +34,8 @@ export class DataGridContextMenuCellEditingService {
},
isHidden(context) {
const format = context.data.model.source.getAction(context.data.resultIndex, ResultSetFormatAction);
return format.isReadOnly({ column: context.data.column, row: context.data.row });
return format.isReadOnly({ column: context.data.column, row: context.data.row })
|| context.data.model.isDisabled(context.data.resultIndex);
},
order: 4,
title: 'data_grid_table_editing',
@@ -45,6 +45,9 @@ export class DataGridContextMenuOrderService {
isPresent(context) {
return context.contextType === DataGridContextMenuService.cellContext;
},
isHidden(context) {
return context.data.model.isDisabled(context.data.resultIndex);
},
order: 1,
title: 'data_grid_table_order',
icon: 'order-arrow-unknown',
@@ -78,7 +78,7 @@ export const TableColumnHeader: React.FC<HeaderRendererProps<any>> = observer(fu
const columnName = calculatedColumn.name as string;
// TODO we want to get "sortable" property from SqlResultColumn data
const sortable = model.source.results.length === 1;
const sortable = model.source.results.length === 1 && !model.source.isDisabled(resultIndex);
const readOnly = !tableDataContext.isReadOnly() && column?.readOnly;
const readOnlyStatus = column?.readOnlyStatus ? `(Read-only: ${column.readOnlyStatus})` : '';
const columnTooltip = `${columnName}${column?.fullTypeName ? ': ' + column.fullTypeName : ''} ${readOnlyStatus}`;
@@ -34,12 +34,16 @@ export class TableFooterMenuService {
return context.contextType === TableFooterMenuService.nodeContextType;
},
isDisabled(context) {
if (!context.data.model.source.hasResult(context.data.resultIndex)) {
if (
context.data.model.isLoading()
|| context.data.model.isDisabled(context.data.resultIndex)
|| !context.data.model.source.hasResult(context.data.resultIndex)
) {
return true;
}
const editor = context.data.model.source.getEditor(context.data.resultIndex);
return context.data.model.isLoading() || !editor.isEdited();
return !editor.isEdited();
},
order: 1,
title: 'ui_processing_save',
@@ -52,7 +56,11 @@ export class TableFooterMenuService {
return context.contextType === TableFooterMenuService.nodeContextType;
},
isDisabled(context) {
if (!context.data.model.source.hasResult(context.data.resultIndex)) {
if (
context.data.model.isLoading()
|| context.data.model.isDisabled(context.data.resultIndex)
|| !context.data.model.source.hasResult(context.data.resultIndex)
) {
return true;
}
const editor = context.data.model.source.getEditor(context.data.resultIndex);
@@ -28,7 +28,6 @@ interface Props {
export const PresentationTab = observer(function PresentationTab({
model,
resultIndex,
presentation,
className,
style,
@@ -46,7 +45,7 @@ export const PresentationTab = observer(function PresentationTab({
style={verticalRotatedTabStyles}
model={model}
presentation={presentation}
disabled={model.isLoading() || model.isDisabled(resultIndex)}
disabled={model.isLoading()}
/>
);
}
@@ -55,7 +54,7 @@ export const PresentationTab = observer(function PresentationTab({
<Tab
tabId={presentation.id}
style={[verticalRotatedTabStyles, style]}
disabled={model.isLoading() || model.isDisabled(resultIndex)}
disabled={model.isLoading()}
>
{presentation.icon && <TabIcon icon={presentation.icon} />}
{presentation.title && <TabTitle>{translate(presentation.title)}</TabTitle>}
@@ -85,7 +85,7 @@ export const TablePresentationBar = observer(function TablePresentationBar({
}
return styled(style)(
<table-left-bar as="div" className={className}>
<table-left-bar className={className}>
<TabsState currentTabId={presentationId} onChange={changePresentation}>
<TabList {...use({ flexible: type === DataPresentationType.main })}>
{presentations.map(presentation => (
@@ -6,7 +6,7 @@
* you may not use this file except in compliance with the License.
*/
import { observable, makeObservable } from 'mobx';
import { observable, makeObservable, computed } from 'mobx';
import { injectable } from '@cloudbeaver/core-di';
@@ -19,9 +19,14 @@ import { DataModelWrapper } from './DataModelWrapper';
export class TableViewerStorageService {
private tableModelMap: Map<string, IDatabaseDataModel<any, any>> = new Map();
get values(): Array<IDatabaseDataModel<any, any>> {
return Array.from(this.tableModelMap.values());
}
constructor() {
makeObservable<TableViewerStorageService, 'tableModelMap'>(this, {
makeObservable<this, 'tableModelMap'>(this, {
tableModelMap: observable,
values: computed,
});
}
@@ -128,7 +128,7 @@ export const TextValuePresentation: TabContainerPanelComponent<IDataValuePanelPr
}
}
readonly = model.isReadonly() || readonly;
readonly = model.isReadonly() || model.isDisabled(resultIndex) || readonly;
if (contentType !== state.lastContentType) {
state.setDefaultContentType(contentType);
@@ -6,16 +6,14 @@
* you may not use this file except in compliance with the License.
*/
import {
import type {
EditorConfiguration,
Editor,
EditorChange,
Position,
Hints,
HintFunction, on as CodemirrorOn,
ShowHintOptions,
off as CodemirrorOff,
Hint
HintFunction,
} from 'codemirror';
import { computed, makeObservable } from 'mobx';
import type { IControlledCodeMirror } from 'react-codemirror2';
@@ -87,8 +85,6 @@ export class SqlEditorController implements IInitializableController {
private tab!: ITab<ISqlEditorTabState>;
private editor?: Editor;
private lastHints: Hints | null;
private lastCompletion: string | null;
constructor(
private sqlResultTabsService: SqlResultTabsService,
@@ -97,9 +93,6 @@ export class SqlEditorController implements IInitializableController {
private sqlEditorService: SqlEditorService,
private sqlExecutionPlanService: SqlExecutionPlanService,
) {
this.lastHints = null;
this.lastCompletion = null;
this.setLastCompletion = this.setLastCompletion.bind(this);
this.getHandleAutocomplete = this.getHandleAutocomplete.bind(this);
this.getHandleAutocomplete = throttleAsync(this.getHandleAutocomplete, 1000 / 3);
makeObservable(this, {
@@ -252,23 +245,9 @@ export class SqlEditorController implements IInitializableController {
})),
};
if (this.lastHints) {
CodemirrorOff(this.lastHints, 'pick', this.setLastCompletion);
}
this.lastHints = hints;
CodemirrorOn(hints, 'pick', this.setLastCompletion);
return hints;
}
private setLastCompletion(hint: string | Hint): void {
if (typeof hint === 'object') {
hint = hint.text;
}
this.lastCompletion = hint;
}
private handleEditorConfigure(editor: Editor) {
this.editor = editor;
@@ -1,192 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2021 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-code-editor() {
.material.CodeMirror-hints {
border: none;
border-radius: 0;
padding: 0;
@include mdc-theme-prop(background-color, surface, false);
@include mdc-theme-prop(color, on-surface, false);
}
.material .CodeMirror-hint {
position: relative;
border: none;
border-radius: 0;
padding: 0 8px;
@include mdc-theme-prop(color, on-surface, false);
&:hover:before {
content: '';
position: absolute;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
opacity: 0.14;
@include mdc-theme-prop(background-color, primary, false);
}
}
.material .CodeMirror-hint-active {
@include mdc-theme-prop(background-color, primary, false);
@include mdc-theme-prop(color, on-primary, false);
&:hover:before {
display: none;
}
}
.react-codemirror2 {
height: 100%;
flex: 1 auto;
[use|readonly] .CodeMirror-cursors {
display: none;
}
.cm-s-material.CodeMirror {
height: 100%;
@include mdc-theme-prop(background-color, surface, false);
@include mdc-theme-prop(color, on-surface, false);
// color: #EEFFFF;
}
.cm-s-material .CodeMirror-gutters {
@include mdc-theme-prop(background, secondary, false);
@include mdc-theme-prop(color, on-secondary, false);
@include mdc-theme-prop(border-color, background, false);
// color: #546E7A;
// border: none;
}
.cm-s-material .CodeMirror-guttermarker,
.cm-s-material .CodeMirror-guttermarker-subtle,
.cm-s-material .CodeMirror-linenumber {
@include mdc-theme-prop(color, on-secondary, false);
// color: #546E7A;
}
.cm-s-material .CodeMirror-cursor {
border-left: 1px solid $cursor;
}
.cm-s-material :global(div).CodeMirror-selected {
background: rgba(128, 203, 196, 0.2);
}
.cm-s-material.CodeMirror-focused :global(div).CodeMirror-selected {
background: rgba(128, 203, 196, 0.2);
}
.CodeMirror :global(pre).CodeMirror-line,
.CodeMirror :global(pre).CodeMirror-line-like {
padding: 0 8px;
}
.cm-s-material .CodeMirror-line::selection,
.cm-s-material .CodeMirror-line > :global(span)::selection,
.cm-s-material .CodeMirror-line > :global(span) > :global(span)::selection {
background: rgba(128, 203, 196, 0.2);
}
.cm-s-material .CodeMirror-line::-moz-selection,
.cm-s-material .CodeMirror-line > :global(span)::-moz-selection,
.cm-s-material .CodeMirror-line > :global(span) > :global(span)::-moz-selection {
background: rgba(128, 203, 196, 0.2);
}
.cm-s-material .CodeMirror-activeline-background {
background: rgba(0, 0, 0, 0.5);
}
.cm-s-material .cm-keyword {
color: $keyword;
font-weight: bold;
}
.cm-s-material .cm-operator {
color: $operator;
}
.cm-s-material .cm-variable-2 {
color: $variable-2;
}
.cm-s-material .cm-variable-3,
.cm-s-material .cm-type {
color: $variable-3;
}
.cm-s-material .cm-builtin {
color: $builtin;
}
.cm-s-material .cm-atom {
color: $atom;
}
.cm-s-material .cm-number {
color: $number;
}
.cm-s-material .cm-def {
color: $def;
}
.cm-s-material .cm-string {
color: $string;
}
.cm-s-material .cm-string-2 {
color: $string-2;
}
.cm-s-material .cm-comment {
color: $comment;
}
.cm-s-material .cm-variable {
color: $variable;
}
.cm-s-material .cm-tag {
color: $tag;
}
.cm-s-material .cm-meta {
color: $meta;
}
.cm-s-material .cm-attribute {
color: $attribute;
}
.cm-s-material .cm-property {
color: $property;
}
.cm-s-material .cm-qualifier {
color: $qualifier;
}
.cm-s-material .cm-variable-3,
.cm-s-material .cm-type {
color: $variable-3;
}
.cm-s-material .cm-error {
color: rgba(255, 255, 255, 1);
background-color: $error;
}
.cm-s-material .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
}
}
}
@@ -1,42 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2021 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-code-editor";
$meta: #ff1717;
$keyword: rgb(115, 158, 202);
$atom: #604aff;
$number: rgb(192, 192, 192);
$def: #00f;
$variable: rgb(126, 186, 211);
$variable-2: rgb(193, 170, 108);
$variable-3: rgb(193, 170, 108);
$property: rgb(126, 186, 211);
$operator: rgb(126, 186, 211);
$comment: rgb(102, 151, 104);
$string: rgb(202, 197, 128);
$string-2: #f50;
$qualifier: #555;
$builtin:#ab87ff;
$bracket: #cc7;
$tag: #170;
$attribute: #00c;
$link: #219;
$error: #f00;
$delimiter: rgb(238, 204, 100);
$cursor: #fff;
:global .CodeMirror-hints {
@include mdc-elevation(3);
@include mdc-typography(caption);
}
:global .#{$theme-class} {
@include base-code-editor;
}
@@ -1 +0,0 @@
export * from './styles';
@@ -1,42 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2021 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-code-editor";
$meta: #ff1717;
$keyword: #07a;
$atom: #905;
$number: #905;
$def: #00f;
$variable: black;
$variable-2: #834689;
$variable-3: #834689;
$property: black;
$operator: #a67f59;
$comment: #3f7f5f;
$string: #690;
$string-2: #f50;
$qualifier: #555;
$builtin: #07a;
$bracket: #cc7;
$tag: #170;
$attribute: #00c;
$link: #905;
$error: #f00;
$delimiter: rgb(238, 204, 100);
$cursor: #000;
:global .CodeMirror-hints {
@include mdc-elevation(3);
@include mdc-typography(caption);
}
:global .#{$theme-class} {
@include base-code-editor;
}
@@ -1,24 +0,0 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2021 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 type { ThemeSelector } from '@cloudbeaver/core-theming';
export const SqlEditorStyles: ThemeSelector = async theme => {
let styles: any;
switch (theme) {
case 'dark':
styles = await import('./dark.module.scss');
break;
default:
styles = await import('./light.module.scss');
break;
}
return styles.default;
};