app object refactor WIP

This commit is contained in:
Jan Prochazka
2020-12-03 11:35:27 +01:00
parent d693cb734b
commit 9bf755ff25
17 changed files with 313 additions and 244 deletions

View File

@@ -4,9 +4,10 @@ import _ from 'lodash';
import React from 'react';
import styled from 'styled-components';
import { FontIcon } from '../icons';
import { useShowMenu } from '../modals/showMenu';
// import { showMenu } from '../modals/DropDownMenu';
import useTheme from '../theme/useTheme';
import { useSetOpenedTabs, useAppObjectParams } from '../utility/globalState';
// import { useSetOpenedTabs, useAppObjectParams } from '../utility/globalState';
const AppObjectDiv = styled.div`
padding: 5px;
@@ -18,10 +19,10 @@ const AppObjectDiv = styled.div`
font-weight: ${(props) => (props.isBold ? 'bold' : 'normal')};
`;
const AppObjectSpan = styled.span`
white-space: nowrap;
font-weight: ${(props) => (props.isBold ? 'bold' : 'normal')};
`;
// const AppObjectSpan = styled.span`
// white-space: nowrap;
// font-weight: ${(props) => (props.isBold ? 'bold' : 'normal')};
// `;
const IconWrap = styled.span`
margin-right: 5px;
@@ -32,49 +33,57 @@ const StatusIconWrap = styled.span`
`;
const ExtInfoWrap = styled.span`
font-weight: normal;
margin-left: 5px;
font-weight: normal;
margin-left: 5px;
color: ${(props) => props.theme.left_font3};
`;
export function AppObjectCore({
title,
icon,
Menu,
data,
makeAppObj,
onClick,
isBold,
isBusy,
component = 'div',
prefix = null,
statusIcon,
extInfo,
statusTitle,
// makeAppObj,
onClick = undefined,
onClick2 = undefined,
onClick3 = undefined,
isBold = undefined,
isBusy = undefined,
// component = 'div',
prefix = undefined,
statusIcon = undefined,
extInfo = undefined,
statusTitle = undefined,
Menu = undefined,
...other
}) {
const appObjectParams = useAppObjectParams();
// const appObjectParams = useAppObjectParams();
const theme = useTheme();
const showMenu = useShowMenu();
const handleContextMenu = (event) => {
if (!Menu) return;
event.preventDefault();
showMenu(event.pageX, event.pageY, <Menu data={data} />);
// showMenu(event.pageX, event.pageY, <Menu data={data} makeAppObj={makeAppObj} {...appObjectParams} />);
};
const Component = component == 'div' ? AppObjectDiv : AppObjectSpan;
// const Component = component == 'div' ? AppObjectDiv : AppObjectSpan;
let bold = false;
if (_.isFunction(isBold)) bold = isBold(appObjectParams);
else bold = !!isBold;
// let bold = false;
// if (_.isFunction(isBold)) bold = isBold(appObjectParams);
// else bold = !!isBold;
return (
<Component
<AppObjectDiv
onContextMenu={handleContextMenu}
onClick={onClick ? () => onClick(data) : undefined}
isBold={bold}
onClick={() => {
if (onClick) onClick(data);
if (onClick2) onClick2(data);
if (onClick3) onClick3(data);
}}
theme={theme}
isBold={isBold}
{...other}
>
{prefix}
@@ -86,12 +95,12 @@ export function AppObjectCore({
</StatusIconWrap>
)}
{extInfo && <ExtInfoWrap theme={theme}>{extInfo}</ExtInfoWrap>}
</Component>
</AppObjectDiv>
);
}
export function AppObjectControl({ data, makeAppObj, component = 'div' }) {
const appObjectParams = useAppObjectParams();
const appobj = makeAppObj(data, appObjectParams);
return <AppObjectCore {...appobj} data={data} makeAppObj={makeAppObj} component={component} />;
}
// export function AppObjectControl({ data, makeAppObj, component = 'div' }) {
// const appObjectParams = useAppObjectParams();
// const appobj = makeAppObj(data, appObjectParams);
// return <AppObjectCore {...appobj} data={data} makeAppObj={makeAppObj} component={component} />;
// }

View File

@@ -1,7 +1,5 @@
import React from 'react';
import _ from 'lodash';
import { AppObjectCore } from './AppObjects';
import { useSetOpenedTabs, useAppObjectParams } from '../utility/globalState';
import styled from 'styled-components';
import { ExpandIcon } from '../icons';
import useTheme from '../theme/useTheme';
@@ -31,53 +29,37 @@ const GroupDiv = styled.div`
font-weight: bold;
`;
function AppObjectListItem({ makeAppObj, data, filter, appobj, onObjectClick, SubItems }) {
function AppObjectListItem({ AppObjectComponent, data, filter, onObjectClick, isExpandable, SubItems }) {
const [isExpanded, setIsExpanded] = React.useState(false);
const [isHover, setIsHover] = React.useState(false);
const expandable = data && isExpandable && isExpandable(data);
React.useEffect(() => {
if (!appobj.isExpandable) {
if (!expandable) {
// if (data._id == '6pOY2iFY8Gsq7mk6') console.log('COLLAPSE1');
setIsExpanded(false);
}
}, [appobj && appobj.isExpandable]);
}, [expandable]);
// const { matcher } = appobj;
// if (matcher && !matcher(filter)) return null;
if (onObjectClick)
appobj = {
...appobj,
onClick: onObjectClick,
};
const commonProps = {
prefix: SubItems ? (
<ExpandIconHolder2>
{expandable ? <ExpandIcon isExpanded={isExpanded} /> : <ExpandIcon isBlank />}
</ExpandIconHolder2>
) : null,
};
if (SubItems) {
const oldClick = appobj.onClick;
appobj = {
...appobj,
onClick: () => {
if (oldClick) oldClick();
// if (data._id == '6pOY2iFY8Gsq7mk6') console.log('COLLAPSE2');
setIsExpanded((v) => !v);
},
};
commonProps.onClick2 = () => setIsExpanded((v) => !v);
}
if (onObjectClick) {
commonProps.onClick3 = onObjectClick;
}
let res = (
<AppObjectCore
data={data}
makeAppObj={makeAppObj}
{...appobj}
onMouseEnter={() => setIsHover(true)}
onMouseLeave={() => setIsHover(false)}
prefix={
SubItems ? (
<ExpandIconHolder2>
{appobj.isExpandable ? <ExpandIcon isExpanded={isExpanded} /> : <ExpandIcon isBlank />}
</ExpandIconHolder2>
) : null
}
/>
);
let res = <AppObjectComponent data={data} commonProps={commonProps} />;
if (SubItems && isExpanded) {
res = (
<>
@@ -93,16 +75,10 @@ function AppObjectListItem({ makeAppObj, data, filter, appobj, onObjectClick, Su
function AppObjectGroup({ group, items }) {
const [isExpanded, setIsExpanded] = React.useState(true);
const [isHover, setIsHover] = React.useState(false);
const theme = useTheme();
return (
<>
<GroupDiv
onMouseEnter={() => setIsHover(true)}
onMouseLeave={() => setIsHover(false)}
onClick={() => setIsExpanded(!isExpanded)}
theme={theme}
>
<GroupDiv onClick={() => setIsExpanded(!isExpanded)} theme={theme}>
<ExpandIconHolder>
<ExpandIcon isExpanded={isExpanded} />
</ExpandIconHolder>
@@ -115,36 +91,35 @@ function AppObjectGroup({ group, items }) {
export function AppObjectList({
list,
makeAppObj,
AppObjectComponent,
SubItems = undefined,
onObjectClick = undefined,
filter = undefined,
groupFunc = undefined,
groupOrdered = undefined,
isExpandable = undefined,
}) {
const appObjectParams = useAppObjectParams();
const createComponent = (data, appobj) => (
const createComponent = (data) => (
<AppObjectListItem
key={appobj.key}
appobj={appobj}
makeAppObj={makeAppObj}
key={AppObjectComponent.extractKey(data)}
AppObjectComponent={AppObjectComponent}
data={data}
filter={filter}
onObjectClick={onObjectClick}
SubItems={SubItems}
isExpandable={isExpandable}
/>
);
if (groupFunc) {
const listGrouped = _.compact(
(list || []).map((data) => {
const appobj = makeAppObj(data, appObjectParams);
const { matcher } = appobj;
// const appobj = makeAppObj(data, appObjectParams);
const matcher = AppObjectComponent.createMatcher && AppObjectComponent.createMatcher(data);
if (matcher && !matcher(filter)) return null;
const component = createComponent(data, appobj);
const group = groupFunc(appobj);
return { group, appobj, component };
const component = createComponent(data);
const group = groupFunc(data);
return { group, data, component };
})
);
const groups = _.groupBy(listGrouped, 'group');
@@ -154,9 +129,8 @@ export function AppObjectList({
}
return (list || []).map((data) => {
const appobj = makeAppObj(data, appObjectParams);
const { matcher } = appobj;
const matcher = AppObjectComponent.createMatcher && AppObjectComponent.createMatcher(data);
if (matcher && !matcher(filter)) return null;
return createComponent(data, appobj);
return createComponent(data);
});
}

View File

@@ -1,10 +1,10 @@
import React from 'react';
import _ from 'lodash';
import moment from 'moment';
import { DropDownMenuItem } from '../modals/DropDownMenu';
import { openNewTab } from '../utility/common';
import { filterName } from 'dbgate-datalib';
import axios from '../utility/axios';
import { useSetOpenedTabs } from '../utility/globalState';
import { AppObjectCore } from './AppObjectCore';
function openArchive(setOpenedTabs, fileName, folderName) {
openNewTab(setOpenedTabs, {
@@ -57,15 +57,19 @@ function Menu({ data, setOpenedTabs }) {
);
}
const archiveFileAppObject = () => ({ fileName, folderName }, { setOpenedTabs }) => {
const key = fileName;
const icon = 'img archive';
function ArchiveFileAppObject({ data, commonProps }) {
const { fileName, folderName } = data;
const setOpenedTabs = useSetOpenedTabs();
const onClick = () => {
openArchive(setOpenedTabs, fileName, folderName);
};
const matcher = (filter) => filterName(filter, fileName);
return { title: fileName, key, icon, Menu, onClick, matcher };
};
return (
<AppObjectCore {...commonProps} data={data} title={fileName} icon="img archive" onClick={onClick} Menu={Menu} />
);
}
export default archiveFileAppObject;
ArchiveFileAppObject.extractKey = (data) => data.fileName;
ArchiveFileAppObject.createMatcher = ({ fileName }) => (filter) => filterName(filter, fileName);
export default ArchiveFileAppObject;

View File

@@ -0,0 +1,34 @@
import React from 'react';
import { DropDownMenuItem } from '../modals/DropDownMenu';
import axios from '../utility/axios';
import { filterName } from 'dbgate-datalib';
import { AppObjectCore } from './AppObjectCore';
import { useCurrentArchive } from '../utility/globalState';
function Menu({ data }) {
const handleDelete = () => {
axios.post('archive/delete-folder', { folder: data.name });
};
return <>{data.name != 'default' && <DropDownMenuItem onClick={handleDelete}>Delete</DropDownMenuItem>}</>;
}
function ArchiveFolderAppObject({ data, commonProps }) {
const { name } = data;
const currentArchive = useCurrentArchive();
return (
<AppObjectCore
{...commonProps}
data={data}
title={name}
icon="img archive-folder"
isBold={name == currentArchive}
Menu={Menu}
/>
);
}
ArchiveFolderAppObject.extractKey = (data) => data.name;
ArchiveFolderAppObject.createMatcher = (data) => (filter) => filterName(filter, data.name);
export default ArchiveFolderAppObject;

View File

@@ -2,8 +2,11 @@ import React from 'react';
import _ from 'lodash';
import moment from 'moment';
import { DropDownMenuItem } from '../modals/DropDownMenu';
import { useSetOpenedTabs } from '../utility/globalState';
import { AppObjectCore } from './AppObjectCore';
function Menu({ data, setOpenedTabs }) {
function Menu({ data }) {
const setOpenedTabs = useSetOpenedTabs();
const handleDelete = () => {
setOpenedTabs((tabs) => tabs.filter((x) => x.tabid != data.tabid));
};
@@ -18,9 +21,9 @@ function Menu({ data, setOpenedTabs }) {
);
}
const closedTabAppObject = () => ({ tabid, props, selected, icon, title, closedTime, busy }, { setOpenedTabs }) => {
const key = tabid;
const isBold = !!selected;
function ClosedTabAppObject({ data, commonProps }) {
const { tabid, props, selected, icon, title, closedTime, busy } = data;
const setOpenedTabs = useSetOpenedTabs();
const onClick = () => {
setOpenedTabs((files) =>
@@ -32,7 +35,20 @@ const closedTabAppObject = () => ({ tabid, props, selected, icon, title, closedT
);
};
return { title: `${title} ${moment(closedTime).fromNow()}`, key, icon, isBold, onClick, isBusy: busy, Menu };
};
return (
<AppObjectCore
{...commonProps}
data={data}
title={`${title} ${moment(closedTime).fromNow()}`}
icon={icon}
isBold={!!selected}
onClick={onClick}
isBusy={busy}
Menu={Menu}
/>
);
}
export default closedTabAppObject;
ClosedTabAppObject.extractKey = (data) => data.tabid;
export default ClosedTabAppObject;

View File

@@ -6,8 +6,17 @@ import axios from '../utility/axios';
import { filterName } from 'dbgate-datalib';
import ConfirmModal from '../modals/ConfirmModal';
import CreateDatabaseModal from '../modals/CreateDatabaseModal';
import { useCurrentDatabase, useOpenedConnections, useSetOpenedConnections } from '../utility/globalState';
import { AppObjectCore } from './AppObjectCore';
import useShowModal from '../modals/showModal';
import { useConfig } from '../utility/metadataLoaders';
function Menu({ data }) {
const openedConnections = useOpenedConnections();
const setOpenedConnections = useSetOpenedConnections();
const showModal = useShowModal();
const config = useConfig();
function Menu({ data, setOpenedConnections, openedConnections, config, showModal }) {
const handleEdit = () => {
showModal((modalState) => <ConnectionModal modalState={modalState} connection={data} />);
};
@@ -54,21 +63,16 @@ function Menu({ data, setOpenedConnections, openedConnections, config, showModal
);
}
const connectionAppObject = (flags) => (
{ _id, server, displayName, engine, status },
{ openedConnections, setOpenedConnections }
) => {
const title = displayName || server;
const key = _id;
const isExpandable = openedConnections.includes(_id);
const icon = 'img server';
const matcher = (filter) => filterName(filter, displayName, server);
const { boldCurrentDatabase } = flags || {};
const isBold = boldCurrentDatabase
? ({ currentDatabase }) => {
return _.get(currentDatabase, 'connection._id') == _id;
}
: null;
function ConnectionAppObject({ data, commonProps }) {
const { _id, server, displayName, engine, status } = data;
const openedConnections = useOpenedConnections();
const setOpenedConnections = useSetOpenedConnections();
const currentDatabase = useCurrentDatabase();
// const key = _id;
// const isExpandable = openedConnections.includes(_id);
// const matcher = (filter) => filterName(filter, displayName, server);
const isBold = _.get(currentDatabase, 'connection._id') == _id;
const onClick = () => setOpenedConnections((c) => [...c, _id]);
let statusIcon = null;
@@ -84,19 +88,37 @@ const connectionAppObject = (flags) => (
}
const extInfo = engine;
return {
title,
key,
icon,
Menu,
matcher,
isBold,
isExpandable,
onClick,
statusIcon,
statusTitle,
extInfo,
};
};
return (
<AppObjectCore
{...commonProps}
title={displayName || server}
icon="img server"
data={data}
statusIcon={statusIcon}
statusTitle={statusTitle}
extInfo={extInfo}
isBold={isBold}
onClick={onClick}
Menu={Menu}
/>
);
export default connectionAppObject;
// return {
// title,
// key,
// icon,
// Menu,
// matcher,
// isBold,
// isExpandable,
// onClick,
// statusIcon,
// statusTitle,
// extInfo,
// };
}
ConnectionAppObject.extractKey = (data) => data._id;
ConnectionAppObject.createMatcher = ({ displayName, server }) => (filter) => filterName(filter, displayName, server);
export default ConnectionAppObject;

View File

@@ -4,11 +4,17 @@ import { DropDownMenuItem } from '../modals/DropDownMenu';
import { openNewTab } from '../utility/common';
import ImportExportModal from '../modals/ImportExportModal';
import { getDefaultFileFormat } from '../utility/fileformats';
import { useSetOpenedTabs } from '../utility/globalState';
import { useCurrentDatabase, useSetOpenedTabs } from '../utility/globalState';
import { AppObjectCore } from './AppObjectCore';
import useShowModal from '../modals/showModal';
import useExtensions from '../utility/useExtensions';
function Menu({ data, showModal, extensions }) {
const setOpenedTabs = useSetOpenedTabs();
function Menu({ data }) {
const { connection, name } = data;
const setOpenedTabs = useSetOpenedTabs();
const extensions = useExtensions();
const showModal = useShowModal();
const tooltip = `${connection.displayName || connection.server}\n${name}`;
const handleNewQuery = () => {
@@ -31,8 +37,8 @@ function Menu({ data, showModal, extensions }) {
initialValues={{
sourceStorageType: getDefaultFileFormat(extensions).storageType,
targetStorageType: 'database',
targetConnectionId: data.connection._id,
targetDatabaseName: data.name,
targetConnectionId: connection._id,
targetDatabaseName: name,
}}
/>
));
@@ -45,8 +51,8 @@ function Menu({ data, showModal, extensions }) {
initialValues={{
targetStorageType: getDefaultFileFormat(extensions).storageType,
sourceStorageType: 'database',
sourceConnectionId: data.connection._id,
sourceDatabaseName: data.name,
sourceConnectionId: connection._id,
sourceDatabaseName: name,
}}
/>
));
@@ -61,20 +67,23 @@ function Menu({ data, showModal, extensions }) {
);
}
const databaseAppObject = (flags) => ({ name, connection }) => {
const { boldCurrentDatabase } = flags || {};
const title = name;
const key = name;
const icon = 'img database';
const isBold = boldCurrentDatabase
? ({ currentDatabase }) => {
return (
_.get(currentDatabase, 'connection._id') == _.get(connection, '_id') && _.get(currentDatabase, 'name') == name
);
function DatabaseAppObject({ data, commonProps }) {
const { name, connection } = data;
const currentDatabase = useCurrentDatabase();
return (
<AppObjectCore
{...commonProps}
data={data}
title={name}
icon="img database"
isBold={
_.get(currentDatabase, 'connection._id') == _.get(connection, '_id') && _.get(currentDatabase, 'name') == name
}
: null;
Menu={Menu}
/>
);
}
return { title, key, icon, Menu, isBold };
};
DatabaseAppObject.extractKey = (props) => props.name;
export default databaseAppObject;
export default DatabaseAppObject;

View File

@@ -6,6 +6,9 @@ import { getConnectionInfo } from '../utility/metadataLoaders';
import fullDisplayName from '../utility/fullDisplayName';
import { filterName } from 'dbgate-datalib';
import ImportExportModal from '../modals/ImportExportModal';
import { useSetOpenedTabs } from '../utility/globalState';
import { AppObjectCore } from './AppObjectCore';
import useShowModal from '../modals/showModal';
const icons = {
tables: 'img table',
@@ -114,7 +117,9 @@ export async function openDatabaseObjectDetail(
});
}
function Menu({ data, makeAppObj, setOpenedTabs, showModal }) {
function Menu({ data }) {
const showModal = useShowModal();
const setOpenedTabs = useSetOpenedTabs();
return (
<>
{menus[data.objectTypeField].map((menu) => (
@@ -166,13 +171,9 @@ function Menu({ data, makeAppObj, setOpenedTabs, showModal }) {
);
}
const databaseObjectAppObject = () => (
{ conid, database, pureName, schemaName, objectTypeField },
{ setOpenedTabs }
) => {
const title = schemaName ? `${schemaName}.${pureName}` : pureName;
const key = title;
const icon = icons[objectTypeField];
function DatabaseObjectAppObject({ data, commonProps }) {
const { conid, database, pureName, schemaName, objectTypeField } = data;
const setOpenedTabs = useSetOpenedTabs();
// const Icon = (props) => getIconImage(icons[objectTypeField], props);
const onClick = ({ schemaName, pureName }) => {
openDatabaseObjectDetail(
@@ -188,10 +189,27 @@ const databaseObjectAppObject = () => (
}
);
};
const matcher = (filter) => filterName(filter, pureName);
const groupTitle = _.startCase(objectTypeField);
// const matcher = (filter) => filterName(filter, pureName);
// const groupTitle = _.startCase(objectTypeField);
return { title, key, icon, Menu, onClick, matcher, groupTitle };
};
return (
<AppObjectCore
{...commonProps}
data={data}
title={schemaName ? `${schemaName}.${pureName}` : pureName}
icon={icons[objectTypeField]}
onClick={onClick}
Menu={Menu}
/>
);
// return { title, key, icon, Menu, onClick, matcher, groupTitle };
}
export default databaseObjectAppObject;
DatabaseObjectAppObject.extractKey = ({ schemaName, pureName }) =>
schemaName ? `${schemaName}.${pureName}` : pureName;
DatabaseObjectAppObject.createMatcher = ({ pureName }) => (filter) => filterName(filter, pureName);
// DatabaseObjectAppObject.groupTitle = ({ pureName }) => (filter) => filterName(filter, pureName);
export default DatabaseObjectAppObject;

View File

@@ -2,6 +2,8 @@ import React from 'react';
import axios from '../utility/axios';
import _ from 'lodash';
import { DropDownMenuItem } from '../modals/DropDownMenu';
import { AppObjectCore } from './AppObjectCore';
import useNewQuery from '../query/useNewQuery';
function Menu({ data }) {
const handleDelete = () => {
@@ -14,20 +16,22 @@ function Menu({ data }) {
);
}
const savedSqlFileAppObject = () => ({ name }, { setOpenedTabs, newQuery, openedTabs }) => {
const key = name;
const title = name;
const icon = 'img sql-file';
function SavedSqlFileAppObject({ data, commonProps }) {
const { name } = data;
const newQuery = useNewQuery();
const onClick = async () => {
const resp = await axios.post('files/load', { folder: 'sql', file: name });
newQuery({
title: name,
// @ts-ignore
initialScript: resp.data,
});
};
return { title, key, icon, onClick, Menu };
};
return <AppObjectCore {...commonProps} data={data} title={name} icon="img sql-file" onClick={onClick} Menu={Menu} />;
}
export default savedSqlFileAppObject;
SavedSqlFileAppObject.extractKey = (data) => data.name;
export default SavedSqlFileAppObject;

View File

@@ -1,24 +0,0 @@
import React from 'react';
import _ from 'lodash';
import moment from 'moment';
import { DropDownMenuItem } from '../modals/DropDownMenu';
import axios from '../utility/axios';
import { filterName } from 'dbgate-datalib';
function Menu({ data, setOpenedTabs }) {
const handleDelete = () => {
axios.post('archive/delete-folder', { folder: data.name });
};
return <>{data.name != 'default' && <DropDownMenuItem onClick={handleDelete}>Delete</DropDownMenuItem>}</>;
}
const archiveFolderAppObject = () => ({ name }, { setOpenedTabs, currentArchive }) => {
const key = name;
const icon = 'img archive-folder';
const isBold = name == currentArchive;
const matcher = (filter) => filterName(filter, name);
return { title: name, key, icon, isBold, Menu, matcher };
};
export default archiveFolderAppObject;