mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
tab management
This commit is contained in:
parent
07e2b0f26f
commit
119b30260f
@ -16,7 +16,8 @@
|
||||
"react-modal": "^3.11.1",
|
||||
"react-scripts": "3.3.0",
|
||||
"socket.io-client": "^2.3.0",
|
||||
"styled-components": "^4.4.1"
|
||||
"styled-components": "^4.4.1",
|
||||
"uuid": "^3.4.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "cross-env PORT=5000 react-scripts start",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import './index.css';
|
||||
import Screen from './Screen';
|
||||
import { CurrentWidgetProvider, CurrentDatabaseProvider } from './utility/globalState';
|
||||
import { CurrentWidgetProvider, CurrentDatabaseProvider, OpenedFilesProvider } from './utility/globalState';
|
||||
import { SocketProvider } from './utility/SocketProvider';
|
||||
|
||||
function App() {
|
||||
@ -9,7 +9,9 @@ function App() {
|
||||
<CurrentWidgetProvider>
|
||||
<CurrentDatabaseProvider>
|
||||
<SocketProvider>
|
||||
<Screen />
|
||||
<OpenedFilesProvider>
|
||||
<Screen />
|
||||
</OpenedFilesProvider>
|
||||
</SocketProvider>
|
||||
</CurrentDatabaseProvider>
|
||||
</CurrentWidgetProvider>
|
||||
|
@ -3,12 +3,13 @@ import styled from 'styled-components';
|
||||
import theme from './theme';
|
||||
|
||||
import { TableIcon } from './icons';
|
||||
import { useOpenedFiles, useSetOpenedFiles } from './utility/globalState';
|
||||
|
||||
const files = [
|
||||
{ name: 'app.js' },
|
||||
{ name: 'BranchCategory', type: 'table', selected: true },
|
||||
{ name: 'ApplicationList' },
|
||||
];
|
||||
// const files = [
|
||||
// { name: 'app.js' },
|
||||
// { name: 'BranchCategory', type: 'table', selected: true },
|
||||
// { name: 'ApplicationList' },
|
||||
// ];
|
||||
|
||||
const FileTabItem = styled.div`
|
||||
border-right: 1px solid white;
|
||||
@ -30,10 +31,31 @@ const FileNameWrapper = styled.span`
|
||||
`;
|
||||
|
||||
export default function FilesTabsPanel() {
|
||||
const files = useOpenedFiles();
|
||||
const setOpenedFiles = useSetOpenedFiles();
|
||||
|
||||
const handleTabClick = id => {
|
||||
setOpenedFiles(files =>
|
||||
files.map(x => ({
|
||||
...x,
|
||||
selected: x.id == id,
|
||||
}))
|
||||
);
|
||||
};
|
||||
const handleMouseUp = (e, id) => {
|
||||
if (e.button == 1) {
|
||||
setOpenedFiles(files => files.filter(x => x.id != id));
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{files.map(file => (
|
||||
<FileTabItem {...file} key={file.name}>
|
||||
<FileTabItem
|
||||
{...file}
|
||||
key={file.id}
|
||||
onClick={() => handleTabClick(file.id)}
|
||||
onMouseUp={e => handleMouseUp(e, file.id)}
|
||||
>
|
||||
<TableIcon />
|
||||
<FileNameWrapper>{file.name}</FileNameWrapper>
|
||||
</FileTabItem>
|
||||
|
@ -2,11 +2,14 @@ import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { showMenu } from '../modals/DropDownMenu';
|
||||
import { AppObjectCore } from './AppObjects';
|
||||
import { useSetOpenedFiles } from '../utility/globalState';
|
||||
|
||||
export function AppObjectList({ list, makeAppObj, SubItems = undefined, onObjectClick = undefined }) {
|
||||
const setOpenedFiles = useSetOpenedFiles();
|
||||
return (list || []).map(x => {
|
||||
const appobj = makeAppObj(x);
|
||||
let res = <AppObjectCore key={appobj.key} {...appobj} data={x} makeAppObj={makeAppObj} onClick={onObjectClick} />;
|
||||
const appobj = makeAppObj(x, { setOpenedFiles });
|
||||
if (onObjectClick) appobj.onClick = onObjectClick;
|
||||
let res = <AppObjectCore key={appobj.key} data={x} makeAppObj={makeAppObj} {...appobj} />;
|
||||
if (SubItems) {
|
||||
res = (
|
||||
<>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { showMenu } from '../modals/DropDownMenu';
|
||||
import { useSetOpenedFiles } from '../utility/globalState';
|
||||
|
||||
const AppObjectDiv = styled.div`
|
||||
padding: 5px;
|
||||
@ -34,6 +35,7 @@ export function AppObjectCore({ title, Icon, Menu, data, makeAppObj, onClick })
|
||||
}
|
||||
|
||||
export function AppObjectControl({ data, makeAppObj }) {
|
||||
const appobj = makeAppObj(data);
|
||||
const setOpenedFiles = useSetOpenedFiles();
|
||||
const appobj = makeAppObj(data, { setOpenedFiles });
|
||||
return <AppObjectCore {...appobj} data={data} makeAppObj={makeAppObj} />;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import uuidv1 from 'uuid/v1';
|
||||
import { TableIcon } from '../icons';
|
||||
import { DropDownMenuItem } from '../modals/DropDownMenu';
|
||||
import showModal from '../modals/showModal';
|
||||
@ -20,10 +21,14 @@ function Menu({ data, makeAppObj }) {
|
||||
);
|
||||
}
|
||||
|
||||
export default function tableAppObject({ pureName, schemaName }) {
|
||||
export default function tableAppObject({ pureName, schemaName }, { setOpenedFiles }) {
|
||||
const title = schemaName ? `${schemaName}.${pureName}` : pureName;
|
||||
const key = title;
|
||||
const Icon = TableIcon;
|
||||
const onClick = ({ schemaName, pureName }) => {
|
||||
const id = uuidv1();
|
||||
setOpenedFiles(files => [...files, { id, name: pureName }]);
|
||||
};
|
||||
|
||||
return { title, key, Icon, Menu };
|
||||
return { title, key, Icon, Menu, onClick };
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import useStorage from './useStorage';
|
||||
|
||||
function createGlobalState(defaultValue) {
|
||||
const Context = React.createContext(null);
|
||||
@ -19,8 +20,30 @@ function createGlobalState(defaultValue) {
|
||||
return [Provider, useValue, useSetValue];
|
||||
}
|
||||
|
||||
function createStorageState(storageKey, defaultValue) {
|
||||
const Context = React.createContext(null);
|
||||
|
||||
function Provider({ children }) {
|
||||
const [currentvalue, setCurrentValue] = useStorage(storageKey, localStorage, defaultValue);
|
||||
return <Context.Provider value={[currentvalue, setCurrentValue]}>{children}</Context.Provider>;
|
||||
}
|
||||
|
||||
function useValue() {
|
||||
return React.useContext(Context)[0];
|
||||
}
|
||||
|
||||
function useSetValue() {
|
||||
return React.useContext(Context)[1];
|
||||
}
|
||||
|
||||
return [Provider, useValue, useSetValue];
|
||||
}
|
||||
|
||||
const [CurrentWidgetProvider, useCurrentWidget, useSetCurrentWidget] = createGlobalState('database');
|
||||
export { CurrentWidgetProvider, useCurrentWidget, useSetCurrentWidget };
|
||||
|
||||
const [CurrentDatabaseProvider, useCurrentDatabase, useSetCurrentDatabase] = createGlobalState(null);
|
||||
export { CurrentDatabaseProvider, useCurrentDatabase, useSetCurrentDatabase };
|
||||
|
||||
const [OpenedFilesProvider, useOpenedFiles, useSetOpenedFiles] = createStorageState('openedFiles', []);
|
||||
export { OpenedFilesProvider, useOpenedFiles, useSetOpenedFiles };
|
||||
|
36
web/src/utility/useStorage.js
Normal file
36
web/src/utility/useStorage.js
Normal file
@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
|
||||
export default function useStorage(key, storageObject, initialValue) {
|
||||
// State to store our value
|
||||
// Pass initial state function to useState so logic is only executed once
|
||||
const [storedValue, setStoredValue] = React.useState(() => {
|
||||
try {
|
||||
// Get from local storage by key
|
||||
const item = storageObject.getItem(key);
|
||||
// Parse stored json or if none return initialValue
|
||||
return item ? JSON.parse(item) : initialValue;
|
||||
} catch (error) {
|
||||
// If error also return initialValue
|
||||
console.log(error);
|
||||
return initialValue;
|
||||
}
|
||||
});
|
||||
|
||||
// Return a wrapped version of useState's setter function that ...
|
||||
// ... persists the new value to localStorage.
|
||||
const setValue = value => {
|
||||
try {
|
||||
// Allow value to be a function so we have same API as useState
|
||||
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
||||
// Save state
|
||||
setStoredValue(valueToStore);
|
||||
// Save to local storage
|
||||
storageObject.setItem(key, JSON.stringify(valueToStore));
|
||||
} catch (error) {
|
||||
// A more advanced implementation would handle the error case
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
return [storedValue, setValue];
|
||||
}
|
@ -10412,6 +10412,11 @@ uuid@^3.0.1, uuid@^3.3.2:
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
|
||||
integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==
|
||||
|
||||
uuid@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
||||
v8-compile-cache@^2.0.3:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
|
||||
|
Loading…
Reference in New Issue
Block a user