mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-30 13:53:59 +00:00
reference manager control design
This commit is contained in:
@@ -4,6 +4,7 @@ import ColumnLabel from './ColumnLabel';
|
|||||||
import { filterName } from '@dbgate/datalib';
|
import { filterName } from '@dbgate/datalib';
|
||||||
import { ExpandIcon } from '../icons';
|
import { ExpandIcon } from '../icons';
|
||||||
import InlineButton from '../widgets/InlineButton';
|
import InlineButton from '../widgets/InlineButton';
|
||||||
|
import { ManagerInnerContainer } from './ManagerStyles';
|
||||||
|
|
||||||
const Wrapper = styled.div``;
|
const Wrapper = styled.div``;
|
||||||
|
|
||||||
@@ -86,7 +87,7 @@ export default function ColumnManager(props) {
|
|||||||
const { display } = props;
|
const { display } = props;
|
||||||
const [columnFilter, setColumnFilter] = React.useState('');
|
const [columnFilter, setColumnFilter] = React.useState('');
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<>
|
||||||
<SearchBoxWrapper>
|
<SearchBoxWrapper>
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -97,12 +98,14 @@ export default function ColumnManager(props) {
|
|||||||
<InlineButton onClick={() => display.hideAllColumns()}>Hide</InlineButton>
|
<InlineButton onClick={() => display.hideAllColumns()}>Hide</InlineButton>
|
||||||
<InlineButton onClick={() => display.showAllColumns()}>Show</InlineButton>
|
<InlineButton onClick={() => display.showAllColumns()}>Show</InlineButton>
|
||||||
</SearchBoxWrapper>
|
</SearchBoxWrapper>
|
||||||
{display
|
<ManagerInnerContainer>
|
||||||
.getColumns(columnFilter)
|
{display
|
||||||
.filter((column) => filterName(columnFilter, column.columnName))
|
.getColumns(columnFilter)
|
||||||
.map((column) => (
|
.filter((column) => filterName(columnFilter, column.columnName))
|
||||||
<ColumnManagerRow key={column.uniqueName} display={display} column={column} />
|
.map((column) => (
|
||||||
))}
|
<ColumnManagerRow key={column.uniqueName} display={display} column={column} />
|
||||||
</Wrapper>
|
))}
|
||||||
|
</ManagerInnerContainer>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,17 @@ import styled from 'styled-components';
|
|||||||
import DataGridCore from './DataGridCore';
|
import DataGridCore from './DataGridCore';
|
||||||
import ColumnManager from './ColumnManager';
|
import ColumnManager from './ColumnManager';
|
||||||
|
|
||||||
|
import {
|
||||||
|
// SearchBoxWrapper,
|
||||||
|
// WidgetsInnerContainer,
|
||||||
|
// Input,
|
||||||
|
ManagerMainContainer,
|
||||||
|
ManagerOuterContainer1,
|
||||||
|
ManagerOuterContainer2,
|
||||||
|
WidgetTitle,
|
||||||
|
} from './ManagerStyles';
|
||||||
|
import ReferenceManager from './ReferenceManager';
|
||||||
|
|
||||||
const MainContainer = styled.div`
|
const MainContainer = styled.div`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -17,6 +28,11 @@ const ColumnManagerContainer = styled.div`
|
|||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const LeftContainer = styled.div`
|
||||||
|
background-color: white;
|
||||||
|
display: flex;
|
||||||
|
`;
|
||||||
|
|
||||||
const DataGridContainer = styled.div`
|
const DataGridContainer = styled.div`
|
||||||
position: relative;
|
position: relative;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
@@ -26,9 +42,22 @@ const DataGridContainer = styled.div`
|
|||||||
export default function DataGrid(props) {
|
export default function DataGrid(props) {
|
||||||
return (
|
return (
|
||||||
<MainContainer>
|
<MainContainer>
|
||||||
<ColumnManagerContainer>
|
<LeftContainer>
|
||||||
|
<ManagerMainContainer>
|
||||||
|
<ManagerOuterContainer1>
|
||||||
|
<WidgetTitle>Columns</WidgetTitle>
|
||||||
|
<ColumnManager {...props} />
|
||||||
|
</ManagerOuterContainer1>
|
||||||
|
<ManagerOuterContainer2>
|
||||||
|
<WidgetTitle>References</WidgetTitle>
|
||||||
|
<ReferenceManager {...props} />
|
||||||
|
</ManagerOuterContainer2>
|
||||||
|
</ManagerMainContainer>
|
||||||
|
</LeftContainer>
|
||||||
|
|
||||||
|
{/* <ColumnManagerContainer>
|
||||||
<ColumnManager {...props} />
|
<ColumnManager {...props} />
|
||||||
</ColumnManagerContainer>
|
</ColumnManagerContainer> */}
|
||||||
<DataGridContainer>
|
<DataGridContainer>
|
||||||
<DataGridCore {...props} />
|
<DataGridCore {...props} />
|
||||||
</DataGridContainer>
|
</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 { useSetCurrentDatabase, useCurrentDatabase, useOpenedConnections } from '../utility/globalState';
|
||||||
import InlineButton from './InlineButton';
|
import InlineButton from './InlineButton';
|
||||||
import databaseObjectAppObject from '../appobj/databaseObjectAppObject';
|
import databaseObjectAppObject from '../appobj/databaseObjectAppObject';
|
||||||
import { useSqlObjectList, useDatabaseList, useConnectionList, useServerStatus, useDatabaseStatus } from '../utility/metadataLoaders';
|
import {
|
||||||
import { SearchBoxWrapper, InnerContainer, Input, MainContainer, OuterContainer, WidgetTitle } from './WidgetStyles';
|
useSqlObjectList,
|
||||||
|
useDatabaseList,
|
||||||
|
useConnectionList,
|
||||||
|
useServerStatus,
|
||||||
|
useDatabaseStatus,
|
||||||
|
} from '../utility/metadataLoaders';
|
||||||
|
import {
|
||||||
|
SearchBoxWrapper,
|
||||||
|
WidgetsInnerContainer,
|
||||||
|
Input,
|
||||||
|
WidgetsMainContainer,
|
||||||
|
WidgetsOuterContainer,
|
||||||
|
WidgetTitle,
|
||||||
|
} from './WidgetStyles';
|
||||||
import axios from '../utility/axios';
|
import axios from '../utility/axios';
|
||||||
import LoadingInfo from './LoadingInfo';
|
import LoadingInfo from './LoadingInfo';
|
||||||
|
|
||||||
@@ -55,14 +68,14 @@ function ConnectionList() {
|
|||||||
<InlineButton onClick={handleRefreshConnections}>Refresh</InlineButton>
|
<InlineButton onClick={handleRefreshConnections}>Refresh</InlineButton>
|
||||||
</SearchBoxWrapper>
|
</SearchBoxWrapper>
|
||||||
|
|
||||||
<InnerContainer>
|
<WidgetsInnerContainer>
|
||||||
<AppObjectList
|
<AppObjectList
|
||||||
list={connectionsWithStatus}
|
list={connectionsWithStatus}
|
||||||
makeAppObj={connectionAppObject({ boldCurrentDatabase: true })}
|
makeAppObj={connectionAppObject({ boldCurrentDatabase: true })}
|
||||||
SubItems={SubDatabaseList}
|
SubItems={SubDatabaseList}
|
||||||
filter={filter}
|
filter={filter}
|
||||||
/>
|
/>
|
||||||
</InnerContainer>
|
</WidgetsInnerContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -93,7 +106,7 @@ function SqlObjectList({ conid, database }) {
|
|||||||
/>
|
/>
|
||||||
<InlineButton onClick={handleRefreshDatabase}>Refresh</InlineButton>
|
<InlineButton onClick={handleRefreshDatabase}>Refresh</InlineButton>
|
||||||
</SearchBoxWrapper>
|
</SearchBoxWrapper>
|
||||||
<InnerContainer>
|
<WidgetsInnerContainer>
|
||||||
{status && status.name == 'pending' ? (
|
{status && status.name == 'pending' ? (
|
||||||
<LoadingInfo message="Loading database structure" />
|
<LoadingInfo message="Loading database structure" />
|
||||||
) : (
|
) : (
|
||||||
@@ -104,7 +117,7 @@ function SqlObjectList({ conid, database }) {
|
|||||||
filter={filter}
|
filter={filter}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</InnerContainer>
|
</WidgetsInnerContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -122,13 +135,13 @@ function SqlObjectListWrapper() {
|
|||||||
|
|
||||||
export default function DatabaseWidget() {
|
export default function DatabaseWidget() {
|
||||||
return (
|
return (
|
||||||
<MainContainer>
|
<WidgetsMainContainer>
|
||||||
<OuterContainer>
|
<WidgetsOuterContainer>
|
||||||
<ConnectionList />
|
<ConnectionList />
|
||||||
</OuterContainer>
|
</WidgetsOuterContainer>
|
||||||
<OuterContainer>
|
<WidgetsOuterContainer>
|
||||||
<SqlObjectListWrapper />
|
<SqlObjectListWrapper />
|
||||||
</OuterContainer>
|
</WidgetsOuterContainer>
|
||||||
</MainContainer>
|
</WidgetsMainContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,14 @@ import _ from 'lodash';
|
|||||||
import { AppObjectList } from '../appobj/AppObjectList';
|
import { AppObjectList } from '../appobj/AppObjectList';
|
||||||
import { useOpenedTabs, useSavedSqlFiles } from '../utility/globalState';
|
import { useOpenedTabs, useSavedSqlFiles } from '../utility/globalState';
|
||||||
import openedTabAppObject from '../appobj/openedTabAppObject';
|
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';
|
import savedSqlFileAppObject from '../appobj/savedSqlFileAppObject';
|
||||||
|
|
||||||
function OpenedTabsList() {
|
function OpenedTabsList() {
|
||||||
@@ -14,9 +21,9 @@ function OpenedTabsList() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<WidgetTitle>Opened tabs</WidgetTitle>
|
<WidgetTitle>Opened tabs</WidgetTitle>
|
||||||
<InnerContainer>
|
<WidgetsInnerContainer>
|
||||||
<AppObjectList list={tabs} makeAppObj={openedTabAppObject()} />
|
<AppObjectList list={tabs} makeAppObj={openedTabAppObject()} />
|
||||||
</InnerContainer>
|
</WidgetsInnerContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -27,22 +34,22 @@ function SavedSqlFilesList() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<WidgetTitle>Saved SQL files</WidgetTitle>
|
<WidgetTitle>Saved SQL files</WidgetTitle>
|
||||||
<InnerContainer>
|
<WidgetsInnerContainer>
|
||||||
<AppObjectList list={files} makeAppObj={savedSqlFileAppObject()} />
|
<AppObjectList list={files} makeAppObj={savedSqlFileAppObject()} />
|
||||||
</InnerContainer>
|
</WidgetsInnerContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function FilesWidget() {
|
export default function FilesWidget() {
|
||||||
return (
|
return (
|
||||||
<MainContainer>
|
<WidgetsMainContainer>
|
||||||
<OuterContainer>
|
<WidgetsOuterContainer>
|
||||||
<OpenedTabsList />
|
<OpenedTabsList />
|
||||||
</OuterContainer>
|
</WidgetsOuterContainer>
|
||||||
<OuterContainer>
|
<WidgetsOuterContainer>
|
||||||
<SavedSqlFilesList />
|
<SavedSqlFilesList />
|
||||||
</OuterContainer>
|
</WidgetsOuterContainer>
|
||||||
</MainContainer>
|
</WidgetsMainContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export const SearchBoxWrapper = styled.div`
|
|||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const MainContainer = styled.div`
|
export const WidgetsMainContainer = styled.div`
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column wrap;
|
flex-flow: column wrap;
|
||||||
@@ -15,7 +15,7 @@ export const MainContainer = styled.div`
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const OuterContainer = styled.div`
|
export const WidgetsOuterContainer = styled.div`
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: ${theme.leftPanel.width}px;
|
width: ${theme.leftPanel.width}px;
|
||||||
@@ -24,7 +24,7 @@ export const OuterContainer = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const InnerContainer = styled.div`
|
export const WidgetsInnerContainer = styled.div`
|
||||||
flex: 1 1;
|
flex: 1 1;
|
||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
width: ${theme.leftPanel.width}px;
|
width: ${theme.leftPanel.width}px;
|
||||||
|
|||||||
Reference in New Issue
Block a user