reference manager control design

This commit is contained in:
Jan Prochazka 2020-05-09 22:15:51 +02:00
parent 9284861c35
commit 8f8dd15c04
7 changed files with 216 additions and 36 deletions

View File

@ -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>
</>
);
}

View File

@ -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>

View 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;
`;

View 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>
</>
);
}

View File

@ -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>
);
}

View File

@ -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>
);
}

View File

@ -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;