mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-10-29 18:03:45 +08:00
feat(core): extract table to blocks
This commit is contained in:
@@ -55,6 +55,8 @@ const administrationStyles = composes(
|
||||
}
|
||||
content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 styled, { css } from 'reshadow';
|
||||
|
||||
const styles = css`
|
||||
administration-tools {
|
||||
height: 48px;
|
||||
}
|
||||
`;
|
||||
|
||||
type Props = React.PropsWithChildren<{
|
||||
className?: string;
|
||||
}>
|
||||
|
||||
export function AdministrationTools({ children, className }: Props) {
|
||||
|
||||
return styled(styles)(
|
||||
<administration-tools as='div' className={className}>
|
||||
{children}
|
||||
</administration-tools>
|
||||
);
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { manifest } from './manifest';
|
||||
|
||||
export default manifest;
|
||||
|
||||
export * from './Administration/AdministrationTools/AdministrationTools';
|
||||
export * from './AdministrationItem/AdministrationItemService';
|
||||
export * from './AdministrationItem/IAdministrationItem';
|
||||
export * from './AdministrationScreen/AdministrationScreenService';
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
|
||||
<path fill="#F0840E" d="M9 0c2.485 0 4.5 2.015 4.5 4.5S11.485 9 9 9 4.5 6.985 4.5 4.5 6.515 0 9 0zm0 2.25c-1.243 0-2.25 1.007-2.25 2.25S7.757 6.75 9 6.75s2.25-1.007 2.25-2.25S10.243 2.25 9 2.25zm0 7.875c3.004 0 9 1.496 9 4.5V18H0v-3.375c0-3.004 5.996-4.5 9-4.5zm0 2.137c-3.341 0-6.862 1.643-6.862 2.363v1.238h13.725v-1.238c0-.72-3.522-2.363-6.863-2.363z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 452 B |
@@ -6,10 +6,76 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
export function UsersAdministration() {
|
||||
return (
|
||||
import { observer } from 'mobx-react';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { AdministrationTools } from '@dbeaver/administration';
|
||||
import {
|
||||
Table, TableHeader, TableColumnHeader, TableBody, TableItem, TableColumnValue
|
||||
} from '@dbeaver/core/blocks';
|
||||
import { useStyles, composes } from '@dbeaver/core/theming';
|
||||
|
||||
const styles = composes(
|
||||
css`
|
||||
AdministrationTools {
|
||||
composes: theme-background-secondary theme-text-on-secondary from global;
|
||||
}
|
||||
`,
|
||||
css`
|
||||
content {
|
||||
padding-top: 16px;
|
||||
}
|
||||
TableColumnHeader {
|
||||
border-top: solid 1px;
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
export const UsersAdministration = observer(function UsersAdministration() {
|
||||
return styled(useStyles(styles))(
|
||||
<>
|
||||
Hello
|
||||
<AdministrationTools></AdministrationTools>
|
||||
<content as='div'>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableColumnHeader>User login</TableColumnHeader>
|
||||
<TableColumnHeader>User first name</TableColumnHeader>
|
||||
<TableColumnHeader>User last name</TableColumnHeader>
|
||||
<TableColumnHeader>User last name</TableColumnHeader>
|
||||
<TableColumnHeader></TableColumnHeader>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableItem item={0}>
|
||||
<TableColumnValue>a</TableColumnValue>
|
||||
<TableColumnValue>b</TableColumnValue>
|
||||
<TableColumnValue>c</TableColumnValue>
|
||||
<TableColumnValue>d</TableColumnValue>
|
||||
<TableColumnValue></TableColumnValue>
|
||||
</TableItem>
|
||||
<TableItem item={1}>
|
||||
<TableColumnValue>a</TableColumnValue>
|
||||
<TableColumnValue>b</TableColumnValue>
|
||||
<TableColumnValue>c</TableColumnValue>
|
||||
<TableColumnValue>d</TableColumnValue>
|
||||
<TableColumnValue></TableColumnValue>
|
||||
</TableItem>
|
||||
<TableItem item={2}>
|
||||
<TableColumnValue>a</TableColumnValue>
|
||||
<TableColumnValue>b</TableColumnValue>
|
||||
<TableColumnValue>c</TableColumnValue>
|
||||
<TableColumnValue>d</TableColumnValue>
|
||||
<TableColumnValue></TableColumnValue>
|
||||
</TableItem>
|
||||
<TableItem item={3}>
|
||||
<TableColumnValue>a</TableColumnValue>
|
||||
<TableColumnValue>b</TableColumnValue>
|
||||
<TableColumnValue>c</TableColumnValue>
|
||||
<TableColumnValue>d</TableColumnValue>
|
||||
<TableColumnValue></TableColumnValue>
|
||||
</TableItem>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</content>
|
||||
</>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@ import { useStyles } from '@dbeaver/core/theming';
|
||||
export function UsersDrawerItem({ item, onSelect, style }: AdministrationItemDrawerProps) {
|
||||
return styled(useStyles(...style))(
|
||||
<Tab tabId={item.name} onOpen={() => onSelect(item.name)}>
|
||||
<TabIcon icon='/icons/grid.png' />
|
||||
<TabIcon icon='/icons/account.svg' />
|
||||
<TabTitle>Users</TabTitle>
|
||||
</Tab>
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
@mixin table($query: mdc-feature-all()) {
|
||||
table {
|
||||
composes: theme-typography--body2 from global;
|
||||
min-width: 100%;
|
||||
text-align: left;
|
||||
border-collapse: collapse;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { observable } from 'mobx';
|
||||
import { useState, useCallback } from 'react';
|
||||
import styled from 'reshadow';
|
||||
|
||||
import { useStyles } from '@dbeaver/core/theming';
|
||||
|
||||
import { TableContext, ITableContext } from './TableContext';
|
||||
|
||||
type Props = React.PropsWithChildren<{
|
||||
selectedItems?: Map<any, boolean>;
|
||||
className?: string;
|
||||
}>
|
||||
|
||||
export function Table({ selectedItems, children, className }: Props) {
|
||||
const [selected] = useState<Map<any, boolean>>(() => selectedItems || observable(new Map()));
|
||||
const setItemSelect = useCallback((item: any, state: boolean) => selected.set(item, state), []);
|
||||
const clearSelection = useCallback(() => selected.clear(), []);
|
||||
|
||||
const [context] = useState<ITableContext>(() => ({
|
||||
selectedItems: selected,
|
||||
setItemSelect,
|
||||
clearSelection,
|
||||
}));
|
||||
|
||||
return styled(useStyles())(
|
||||
<TableContext.Provider value={context}>
|
||||
<table className={className}>
|
||||
{children}
|
||||
</table>
|
||||
</TableContext.Provider>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 styled from 'reshadow';
|
||||
|
||||
import { useStyles } from '@dbeaver/core/theming';
|
||||
|
||||
type Props = React.PropsWithChildren<{
|
||||
className?: string;
|
||||
}>
|
||||
|
||||
export function TableBody({ children, className }: Props) {
|
||||
return styled(useStyles())(
|
||||
<tbody className={className}>
|
||||
{children}
|
||||
</tbody>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 styled from 'reshadow';
|
||||
|
||||
import { useStyles } from '@dbeaver/core/theming';
|
||||
|
||||
type Props = React.PropsWithChildren<{
|
||||
title?: string;
|
||||
className?: string;
|
||||
}>
|
||||
|
||||
export function TableColumnHeader({ title, children, className }: Props) {
|
||||
return styled(useStyles())(
|
||||
<th title={title} className={className}>
|
||||
{children}
|
||||
</th>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { observer } from 'mobx-react';
|
||||
import styled from 'reshadow';
|
||||
|
||||
import { useStyles } from '@dbeaver/core/theming';
|
||||
|
||||
type Props = React.PropsWithChildren<{
|
||||
className?: string;
|
||||
}>
|
||||
|
||||
export const TableColumnValue = observer(function TableColumnValue({ children, className }: Props) {
|
||||
return styled(useStyles())(
|
||||
<td className={className}>{children}</td>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { createContext } from 'react';
|
||||
|
||||
export interface ITableContext {
|
||||
selectedItems: Map<any, boolean>;
|
||||
setItemSelect: (item: any, state: boolean) => void;
|
||||
clearSelection: () => void;
|
||||
}
|
||||
|
||||
export const TableContext = createContext<ITableContext | undefined>(undefined);
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 styled from 'reshadow';
|
||||
|
||||
import { useStyles } from '@dbeaver/core/theming';
|
||||
|
||||
type Props = React.PropsWithChildren<{
|
||||
className?: string;
|
||||
}>
|
||||
|
||||
export function TableHeader({ children, className }: Props) {
|
||||
return styled(useStyles())(
|
||||
<thead className={className}>
|
||||
<tr>
|
||||
{children}
|
||||
</tr>
|
||||
</thead>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { observer } from 'mobx-react';
|
||||
import { useContext, useCallback } from 'react';
|
||||
import styled, { use } from 'reshadow';
|
||||
|
||||
|
||||
import { useStyles } from '@dbeaver/core/theming';
|
||||
|
||||
import { TableContext } from './TableContext';
|
||||
|
||||
type Props = React.PropsWithChildren<{
|
||||
item: any;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
onDoubleClick?: () => void;
|
||||
}>
|
||||
|
||||
export const TableItem = observer(function TableItem({
|
||||
item, children, className, onClick, onDoubleClick,
|
||||
}: Props) {
|
||||
const context = useContext(TableContext);
|
||||
if (!context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleClick = useCallback(
|
||||
(e: React.MouseEvent<HTMLTableRowElement>) => {
|
||||
if (!e.ctrlKey) {
|
||||
context.clearSelection();
|
||||
}
|
||||
const isSelected = context.selectedItems.get(item);
|
||||
|
||||
context.setItemSelect(item, !isSelected);
|
||||
|
||||
if (onClick) {
|
||||
onClick();
|
||||
}
|
||||
},
|
||||
[context, item, onClick]
|
||||
);
|
||||
const handleDoubleClick = useCallback((e: React.MouseEvent<HTMLTableRowElement>) => {
|
||||
if (onDoubleClick) {
|
||||
onDoubleClick();
|
||||
}
|
||||
}, [onDoubleClick]);
|
||||
|
||||
const isSelected = context.selectedItems.get(item);
|
||||
|
||||
return styled(useStyles())(
|
||||
<tr onClick={handleClick} onDoubleClick={handleDoubleClick} className={className} {...use({ isSelected })}>
|
||||
{children}
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
export * from './Table';
|
||||
export * from './TableBody';
|
||||
export * from './TableColumnHeader';
|
||||
export * from './TableColumnValue';
|
||||
export * from './TableContext';
|
||||
export * from './TableHeader';
|
||||
export * from './TableItem';
|
||||
@@ -9,6 +9,7 @@ export * from './Placeholder/PlaceholderContainer';
|
||||
export * from './PropertiesTable';
|
||||
export * from './SanitizedHTML/SanitizedHTML';
|
||||
export * from './Split';
|
||||
export * from './Table';
|
||||
export * from './Tabs';
|
||||
export * from './Button';
|
||||
export * from './ErrorMessage';
|
||||
|
||||
+7
-6
@@ -8,11 +8,12 @@
|
||||
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { TableColumnHeader } from '@dbeaver/core/blocks';
|
||||
import { ObjectPropertyInfo } from '@dbeaver/core/sdk';
|
||||
import { useStyles } from '@dbeaver/core/theming';
|
||||
|
||||
const styles = css`
|
||||
th:first-child {
|
||||
TableColumnHeader:first-child {
|
||||
width:16px;
|
||||
border-right: none;
|
||||
}
|
||||
@@ -34,13 +35,13 @@ type HeaderProps = {
|
||||
export function Header({ properties }: HeaderProps) {
|
||||
|
||||
return styled(useStyles(styles))(
|
||||
<tr>
|
||||
<th></th>
|
||||
<>
|
||||
<TableColumnHeader></TableColumnHeader>
|
||||
{properties.map(property => (
|
||||
<th key={property.id} title={property.description}>
|
||||
<TableColumnHeader key={property.id} title={property.description}>
|
||||
{property.displayName}
|
||||
</th>
|
||||
</TableColumnHeader>
|
||||
))}
|
||||
</tr>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+16
-22
@@ -8,10 +8,10 @@
|
||||
|
||||
import { observer } from 'mobx-react';
|
||||
import { useCallback } from 'react';
|
||||
import styled, { css, use } from 'reshadow';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { NodesManagerService, useDatabaseObjectInfo, useNode } from '@dbeaver/core/app';
|
||||
import { StaticImage } from '@dbeaver/core/blocks';
|
||||
import { StaticImage, TableItem, TableColumnValue } from '@dbeaver/core/blocks';
|
||||
import { useService } from '@dbeaver/core/di';
|
||||
import { useStyles } from '@dbeaver/core/theming';
|
||||
|
||||
@@ -32,10 +32,10 @@ const itemStyles = css`
|
||||
height: 16px;
|
||||
width: 180px;
|
||||
}
|
||||
tr {
|
||||
TableItem {
|
||||
position: relative;
|
||||
}
|
||||
td:nth-child(2) {
|
||||
TableColumnValue:nth-child(2) {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
@@ -44,51 +44,45 @@ const itemStyles = css`
|
||||
type ItemProps = {
|
||||
objectId: string;
|
||||
columns: number;
|
||||
isSelected: boolean;
|
||||
onClick: (objectId: string, isMultiple: boolean) => void;
|
||||
}
|
||||
|
||||
export const Item = observer(function Item({
|
||||
objectId, columns, isSelected, onClick,
|
||||
objectId, columns,
|
||||
}: ItemProps) {
|
||||
const nodesManagerService = useService(NodesManagerService);
|
||||
const object = useNode(objectId);
|
||||
const databaseObjectInfo = useDatabaseObjectInfo(objectId);
|
||||
const handleOpen = useCallback(() => nodesManagerService.navToNode(objectId), [objectId]);
|
||||
const handleClick = useCallback(
|
||||
(e: React.MouseEvent<HTMLTableRowElement>) => onClick(objectId, e.ctrlKey),
|
||||
[objectId, onClick]
|
||||
);
|
||||
|
||||
if (!object || !databaseObjectInfo?.properties) {
|
||||
return styled(useStyles(itemStyles))(
|
||||
<tr tabIndex={0} onDoubleClick={handleOpen} onClick={handleClick} {...use({ isSelected })}>
|
||||
<td>
|
||||
<TableItem item={objectId} onDoubleClick={handleOpen}>
|
||||
<TableColumnValue>
|
||||
<icon as="div">
|
||||
<placeholder as="div" />
|
||||
</icon>
|
||||
</td>
|
||||
</TableColumnValue>
|
||||
{Array(columns)
|
||||
.fill(0)
|
||||
.map((_, i) => (
|
||||
<td key={i}>
|
||||
<TableColumnValue key={i}>
|
||||
<placeholder as="div" />
|
||||
</td>
|
||||
</TableColumnValue>
|
||||
))}
|
||||
</tr>
|
||||
</TableItem>
|
||||
);
|
||||
}
|
||||
|
||||
return styled(useStyles(itemStyles))(
|
||||
<tr tabIndex={0} onDoubleClick={handleOpen} onClick={handleClick} {...use({ isSelected })}>
|
||||
<td>
|
||||
<TableItem item={objectId} onDoubleClick={handleOpen}>
|
||||
<TableColumnValue>
|
||||
<icon as="div">
|
||||
<StaticImage icon={object.icon} />
|
||||
</icon>
|
||||
</td>
|
||||
</TableColumnValue>
|
||||
{databaseObjectInfo.properties.map(property => (
|
||||
<td key={property.id}>{getValue(property.value)}</td>
|
||||
<TableColumnValue key={property.id}>{getValue(property.value)}</TableColumnValue>
|
||||
))}
|
||||
</tr>
|
||||
</TableItem>
|
||||
);
|
||||
});
|
||||
|
||||
+14
-39
@@ -7,67 +7,42 @@
|
||||
*/
|
||||
|
||||
import { observer } from 'mobx-react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { useDatabaseObjectInfo } from '@dbeaver/core/app';
|
||||
import { useStyles } from '@dbeaver/core/theming';
|
||||
import { TableHeader, TableBody, Table } from '@dbeaver/core/blocks';
|
||||
|
||||
import { Header } from './Header';
|
||||
import { Item } from './Item';
|
||||
|
||||
const styles = css`
|
||||
table {
|
||||
composes: theme-typography--body2 from global;
|
||||
}
|
||||
`;
|
||||
|
||||
type ObjectChildrenPropertyTableProps = {
|
||||
nodeIds?: string[];
|
||||
}
|
||||
|
||||
export const ObjectChildrenPropertyTable = observer(function ObjectPropertyTable(
|
||||
props: ObjectChildrenPropertyTableProps
|
||||
) {
|
||||
export const ObjectChildrenPropertyTable = observer(function ObjectPropertyTable({
|
||||
nodeIds,
|
||||
}: ObjectChildrenPropertyTableProps) {
|
||||
|
||||
const [selected, setSelected] = useState<string[]>([]);
|
||||
const handleSelect = useCallback((objectId: string, isMultiple: boolean) => {
|
||||
if (isMultiple) {
|
||||
if (selected.includes(objectId)) {
|
||||
setSelected(selected.filter(v => v !== objectId));
|
||||
} else {
|
||||
setSelected([...selected, objectId]);
|
||||
}
|
||||
} else if (!selected.includes(objectId)) {
|
||||
setSelected([objectId]);
|
||||
} else {
|
||||
setSelected([]);
|
||||
}
|
||||
}, [selected]);
|
||||
|
||||
if (!props.nodeIds) {
|
||||
if (!nodeIds) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const firstChild = props.nodeIds[0] || '';
|
||||
const firstChild = nodeIds[0] || '';
|
||||
const properties = useDatabaseObjectInfo(firstChild)?.properties;
|
||||
|
||||
return styled(useStyles(styles))(
|
||||
<table>
|
||||
<thead>
|
||||
return (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<Header properties={properties || []} />
|
||||
</thead>
|
||||
<tbody>
|
||||
{props.nodeIds.map(id => (
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{nodeIds.map(id => (
|
||||
<Item
|
||||
key={id}
|
||||
objectId={id}
|
||||
columns={properties?.length || 0}
|
||||
isSelected={selected.includes(id)}
|
||||
onClick={handleSelect}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user