mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
reference manager control design
This commit is contained in:
parent
9284861c35
commit
8f8dd15c04
@ -4,6 +4,7 @@ import ColumnLabel from './ColumnLabel';
|
||||
import { filterName } from '@dbgate/datalib';
|
||||
import { ExpandIcon } from '../icons';
|
||||
import InlineButton from '../widgets/InlineButton';
|
||||
import { ManagerInnerContainer } from './ManagerStyles';
|
||||
|
||||
const Wrapper = styled.div``;
|
||||
|
||||
@ -86,7 +87,7 @@ export default function ColumnManager(props) {
|
||||
const { display } = props;
|
||||
const [columnFilter, setColumnFilter] = React.useState('');
|
||||
return (
|
||||
<Wrapper>
|
||||
<>
|
||||
<SearchBoxWrapper>
|
||||
<Input
|
||||
type="text"
|
||||
@ -97,12 +98,14 @@ export default function ColumnManager(props) {
|
||||
<InlineButton onClick={() => display.hideAllColumns()}>Hide</InlineButton>
|
||||
<InlineButton onClick={() => display.showAllColumns()}>Show</InlineButton>
|
||||
</SearchBoxWrapper>
|
||||
{display
|
||||
.getColumns(columnFilter)
|
||||
.filter((column) => filterName(columnFilter, column.columnName))
|
||||
.map((column) => (
|
||||
<ColumnManagerRow key={column.uniqueName} display={display} column={column} />
|
||||
))}
|
||||
</Wrapper>
|
||||
<ManagerInnerContainer>
|
||||
{display
|
||||
.getColumns(columnFilter)
|
||||
.filter((column) => filterName(columnFilter, column.columnName))
|
||||
.map((column) => (
|
||||
<ColumnManagerRow key={column.uniqueName} display={display} column={column} />
|
||||
))}
|
||||
</ManagerInnerContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -3,6 +3,17 @@ import styled from 'styled-components';
|
||||
import DataGridCore from './DataGridCore';
|
||||
import ColumnManager from './ColumnManager';
|
||||
|
||||
import {
|
||||
// SearchBoxWrapper,
|
||||
// WidgetsInnerContainer,
|
||||
// Input,
|
||||
ManagerMainContainer,
|
||||
ManagerOuterContainer1,
|
||||
ManagerOuterContainer2,
|
||||
WidgetTitle,
|
||||
} from './ManagerStyles';
|
||||
import ReferenceManager from './ReferenceManager';
|
||||
|
||||
const MainContainer = styled.div`
|
||||
position: absolute;
|
||||
left: 0;
|
||||
@ -17,6 +28,11 @@ const ColumnManagerContainer = styled.div`
|
||||
overflow-y: scroll;
|
||||
`;
|
||||
|
||||
const LeftContainer = styled.div`
|
||||
background-color: white;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const DataGridContainer = styled.div`
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
@ -26,9 +42,22 @@ const DataGridContainer = styled.div`
|
||||
export default function DataGrid(props) {
|
||||
return (
|
||||
<MainContainer>
|
||||
<ColumnManagerContainer>
|
||||
<LeftContainer>
|
||||
<ManagerMainContainer>
|
||||
<ManagerOuterContainer1>
|
||||
<WidgetTitle>Columns</WidgetTitle>
|
||||
<ColumnManager {...props} />
|
||||
</ManagerOuterContainer1>
|
||||
<ManagerOuterContainer2>
|
||||
<WidgetTitle>References</WidgetTitle>
|
||||
<ReferenceManager {...props} />
|
||||
</ManagerOuterContainer2>
|
||||
</ManagerMainContainer>
|
||||
</LeftContainer>
|
||||
|
||||
{/* <ColumnManagerContainer>
|
||||
<ColumnManager {...props} />
|
||||
</ColumnManagerContainer>
|
||||
</ColumnManagerContainer> */}
|
||||
<DataGridContainer>
|
||||
<DataGridCore {...props} />
|
||||
</DataGridContainer>
|
||||
|
50
packages/web/src/datagrid/ManagerStyles.js
Normal file
50
packages/web/src/datagrid/ManagerStyles.js
Normal file
@ -0,0 +1,50 @@
|
||||
import styled from 'styled-components';
|
||||
import theme from '../theme';
|
||||
|
||||
// export const SearchBoxWrapper = styled.div`
|
||||
// display: flex;
|
||||
// margin-bottom: 5px;
|
||||
// `;
|
||||
|
||||
export const ManagerMainContainer = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
user-select: none;
|
||||
`;
|
||||
|
||||
export const ManagerOuterContainer = styled.div`
|
||||
flex: 1 1 0;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
export const ManagerOuterContainer1 = styled(ManagerOuterContainer)`
|
||||
flex: 0 0 60%;
|
||||
`;
|
||||
|
||||
export const ManagerOuterContainer2 = styled(ManagerOuterContainer)`
|
||||
flex: 0 0 40%;
|
||||
`;
|
||||
|
||||
export const ManagerInnerContainer = styled.div`
|
||||
flex: 1 1;
|
||||
overflow-y: scroll;
|
||||
`;
|
||||
|
||||
export const Input = styled.input`
|
||||
flex: 1;
|
||||
min-width: 90px;
|
||||
`;
|
||||
|
||||
export const WidgetTitle = styled.div`
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
background-color: gray;
|
||||
// background-color: #CEC;
|
||||
`;
|
78
packages/web/src/datagrid/ReferenceManager.js
Normal file
78
packages/web/src/datagrid/ReferenceManager.js
Normal file
@ -0,0 +1,78 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { ManagerInnerContainer } from './ManagerStyles';
|
||||
import { LinkIcon, ReferenceIcon } from '../icons';
|
||||
|
||||
const SearchBoxWrapper = styled.div`
|
||||
display: flex;
|
||||
margin-bottom: 5px;
|
||||
`;
|
||||
|
||||
const Input = styled.input`
|
||||
flex: 1;
|
||||
min-width: 90px;
|
||||
`;
|
||||
|
||||
const Header = styled.div`
|
||||
font-weight: bold;
|
||||
`;
|
||||
|
||||
const LinkContainer = styled.div`
|
||||
color: #337ab7;
|
||||
margin: 5px;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const NameContainer = styled.div`
|
||||
margin-left: 5px;
|
||||
`;
|
||||
|
||||
function ManagerRow({ tableName, columns, Icon }) {
|
||||
return (
|
||||
<LinkContainer>
|
||||
<Icon />
|
||||
<NameContainer>
|
||||
{tableName} ({columns.map((x) => x.columnName).join(', ')})
|
||||
</NameContainer>
|
||||
</LinkContainer>
|
||||
);
|
||||
}
|
||||
|
||||
/** @param props {import('./types').DataGridProps} */
|
||||
export default function ReferenceManager(props) {
|
||||
const [filter, setFilter] = React.useState('');
|
||||
const { display } = props;
|
||||
const { baseTable } = display || {};
|
||||
const { foreignKeys } = baseTable || {};
|
||||
const { dependencies } = baseTable || {};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchBoxWrapper>
|
||||
<Input type="text" placeholder="Search" value={filter} onChange={(e) => setFilter(e.target.value)} />
|
||||
</SearchBoxWrapper>
|
||||
<ManagerInnerContainer>
|
||||
{foreignKeys && foreignKeys.length > 0 && (
|
||||
<>
|
||||
<Header>References tables ({foreignKeys.length})</Header>
|
||||
{foreignKeys.map((fk) => (
|
||||
<ManagerRow key={fk.constraintName} Icon={LinkIcon} tableName={fk.refTableName} columns={fk.columns} />
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{dependencies && dependencies.length > 0 && (
|
||||
<>
|
||||
<Header>Dependend tables ({dependencies.length})</Header>
|
||||
{dependencies.map((fk) => (
|
||||
<ManagerRow key={fk.constraintName} Icon={ReferenceIcon} tableName={fk.pureName} columns={fk.columns} />
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</ManagerInnerContainer>
|
||||
</>
|
||||
);
|
||||
}
|
@ -7,8 +7,21 @@ import databaseAppObject from '../appobj/databaseAppObject';
|
||||
import { useSetCurrentDatabase, useCurrentDatabase, useOpenedConnections } from '../utility/globalState';
|
||||
import InlineButton from './InlineButton';
|
||||
import databaseObjectAppObject from '../appobj/databaseObjectAppObject';
|
||||
import { useSqlObjectList, useDatabaseList, useConnectionList, useServerStatus, useDatabaseStatus } from '../utility/metadataLoaders';
|
||||
import { SearchBoxWrapper, InnerContainer, Input, MainContainer, OuterContainer, WidgetTitle } from './WidgetStyles';
|
||||
import {
|
||||
useSqlObjectList,
|
||||
useDatabaseList,
|
||||
useConnectionList,
|
||||
useServerStatus,
|
||||
useDatabaseStatus,
|
||||
} from '../utility/metadataLoaders';
|
||||
import {
|
||||
SearchBoxWrapper,
|
||||
WidgetsInnerContainer,
|
||||
Input,
|
||||
WidgetsMainContainer,
|
||||
WidgetsOuterContainer,
|
||||
WidgetTitle,
|
||||
} from './WidgetStyles';
|
||||
import axios from '../utility/axios';
|
||||
import LoadingInfo from './LoadingInfo';
|
||||
|
||||
@ -55,14 +68,14 @@ function ConnectionList() {
|
||||
<InlineButton onClick={handleRefreshConnections}>Refresh</InlineButton>
|
||||
</SearchBoxWrapper>
|
||||
|
||||
<InnerContainer>
|
||||
<WidgetsInnerContainer>
|
||||
<AppObjectList
|
||||
list={connectionsWithStatus}
|
||||
makeAppObj={connectionAppObject({ boldCurrentDatabase: true })}
|
||||
SubItems={SubDatabaseList}
|
||||
filter={filter}
|
||||
/>
|
||||
</InnerContainer>
|
||||
</WidgetsInnerContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -93,7 +106,7 @@ function SqlObjectList({ conid, database }) {
|
||||
/>
|
||||
<InlineButton onClick={handleRefreshDatabase}>Refresh</InlineButton>
|
||||
</SearchBoxWrapper>
|
||||
<InnerContainer>
|
||||
<WidgetsInnerContainer>
|
||||
{status && status.name == 'pending' ? (
|
||||
<LoadingInfo message="Loading database structure" />
|
||||
) : (
|
||||
@ -104,7 +117,7 @@ function SqlObjectList({ conid, database }) {
|
||||
filter={filter}
|
||||
/>
|
||||
)}
|
||||
</InnerContainer>
|
||||
</WidgetsInnerContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -122,13 +135,13 @@ function SqlObjectListWrapper() {
|
||||
|
||||
export default function DatabaseWidget() {
|
||||
return (
|
||||
<MainContainer>
|
||||
<OuterContainer>
|
||||
<WidgetsMainContainer>
|
||||
<WidgetsOuterContainer>
|
||||
<ConnectionList />
|
||||
</OuterContainer>
|
||||
<OuterContainer>
|
||||
</WidgetsOuterContainer>
|
||||
<WidgetsOuterContainer>
|
||||
<SqlObjectListWrapper />
|
||||
</OuterContainer>
|
||||
</MainContainer>
|
||||
</WidgetsOuterContainer>
|
||||
</WidgetsMainContainer>
|
||||
);
|
||||
}
|
||||
|
@ -5,7 +5,14 @@ import _ from 'lodash';
|
||||
import { AppObjectList } from '../appobj/AppObjectList';
|
||||
import { useOpenedTabs, useSavedSqlFiles } from '../utility/globalState';
|
||||
import openedTabAppObject from '../appobj/openedTabAppObject';
|
||||
import { SearchBoxWrapper, InnerContainer, Input, MainContainer, OuterContainer, WidgetTitle } from './WidgetStyles';
|
||||
import {
|
||||
SearchBoxWrapper,
|
||||
WidgetsInnerContainer,
|
||||
Input,
|
||||
WidgetsMainContainer,
|
||||
WidgetsOuterContainer,
|
||||
WidgetTitle,
|
||||
} from './WidgetStyles';
|
||||
import savedSqlFileAppObject from '../appobj/savedSqlFileAppObject';
|
||||
|
||||
function OpenedTabsList() {
|
||||
@ -14,9 +21,9 @@ function OpenedTabsList() {
|
||||
return (
|
||||
<>
|
||||
<WidgetTitle>Opened tabs</WidgetTitle>
|
||||
<InnerContainer>
|
||||
<WidgetsInnerContainer>
|
||||
<AppObjectList list={tabs} makeAppObj={openedTabAppObject()} />
|
||||
</InnerContainer>
|
||||
</WidgetsInnerContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -27,22 +34,22 @@ function SavedSqlFilesList() {
|
||||
return (
|
||||
<>
|
||||
<WidgetTitle>Saved SQL files</WidgetTitle>
|
||||
<InnerContainer>
|
||||
<WidgetsInnerContainer>
|
||||
<AppObjectList list={files} makeAppObj={savedSqlFileAppObject()} />
|
||||
</InnerContainer>
|
||||
</WidgetsInnerContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function FilesWidget() {
|
||||
return (
|
||||
<MainContainer>
|
||||
<OuterContainer>
|
||||
<WidgetsMainContainer>
|
||||
<WidgetsOuterContainer>
|
||||
<OpenedTabsList />
|
||||
</OuterContainer>
|
||||
<OuterContainer>
|
||||
</WidgetsOuterContainer>
|
||||
<WidgetsOuterContainer>
|
||||
<SavedSqlFilesList />
|
||||
</OuterContainer>
|
||||
</MainContainer>
|
||||
</WidgetsOuterContainer>
|
||||
</WidgetsMainContainer>
|
||||
);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ export const SearchBoxWrapper = styled.div`
|
||||
margin-bottom: 5px;
|
||||
`;
|
||||
|
||||
export const MainContainer = styled.div`
|
||||
export const WidgetsMainContainer = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
@ -15,7 +15,7 @@ export const MainContainer = styled.div`
|
||||
user-select: none;
|
||||
`;
|
||||
|
||||
export const OuterContainer = styled.div`
|
||||
export const WidgetsOuterContainer = styled.div`
|
||||
flex: 1 1 0;
|
||||
overflow: hidden;
|
||||
width: ${theme.leftPanel.width}px;
|
||||
@ -24,7 +24,7 @@ export const OuterContainer = styled.div`
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
export const InnerContainer = styled.div`
|
||||
export const WidgetsInnerContainer = styled.div`
|
||||
flex: 1 1;
|
||||
overflow: scroll;
|
||||
width: ${theme.leftPanel.width}px;
|
||||
|
Loading…
Reference in New Issue
Block a user