tab management

This commit is contained in:
Jan Prochazka
2020-01-20 21:20:53 +01:00
parent 07e2b0f26f
commit 119b30260f
9 changed files with 113 additions and 14 deletions

View File

@@ -16,7 +16,8 @@
"react-modal": "^3.11.1", "react-modal": "^3.11.1",
"react-scripts": "3.3.0", "react-scripts": "3.3.0",
"socket.io-client": "^2.3.0", "socket.io-client": "^2.3.0",
"styled-components": "^4.4.1" "styled-components": "^4.4.1",
"uuid": "^3.4.0"
}, },
"scripts": { "scripts": {
"start": "cross-env PORT=5000 react-scripts start", "start": "cross-env PORT=5000 react-scripts start",

View File

@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import './index.css'; import './index.css';
import Screen from './Screen'; import Screen from './Screen';
import { CurrentWidgetProvider, CurrentDatabaseProvider } from './utility/globalState'; import { CurrentWidgetProvider, CurrentDatabaseProvider, OpenedFilesProvider } from './utility/globalState';
import { SocketProvider } from './utility/SocketProvider'; import { SocketProvider } from './utility/SocketProvider';
function App() { function App() {
@@ -9,7 +9,9 @@ function App() {
<CurrentWidgetProvider> <CurrentWidgetProvider>
<CurrentDatabaseProvider> <CurrentDatabaseProvider>
<SocketProvider> <SocketProvider>
<OpenedFilesProvider>
<Screen /> <Screen />
</OpenedFilesProvider>
</SocketProvider> </SocketProvider>
</CurrentDatabaseProvider> </CurrentDatabaseProvider>
</CurrentWidgetProvider> </CurrentWidgetProvider>

View File

@@ -3,12 +3,13 @@ import styled from 'styled-components';
import theme from './theme'; import theme from './theme';
import { TableIcon } from './icons'; import { TableIcon } from './icons';
import { useOpenedFiles, useSetOpenedFiles } from './utility/globalState';
const files = [ // const files = [
{ name: 'app.js' }, // { name: 'app.js' },
{ name: 'BranchCategory', type: 'table', selected: true }, // { name: 'BranchCategory', type: 'table', selected: true },
{ name: 'ApplicationList' }, // { name: 'ApplicationList' },
]; // ];
const FileTabItem = styled.div` const FileTabItem = styled.div`
border-right: 1px solid white; border-right: 1px solid white;
@@ -30,10 +31,31 @@ const FileNameWrapper = styled.span`
`; `;
export default function FilesTabsPanel() { 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 ( return (
<> <>
{files.map(file => ( {files.map(file => (
<FileTabItem {...file} key={file.name}> <FileTabItem
{...file}
key={file.id}
onClick={() => handleTabClick(file.id)}
onMouseUp={e => handleMouseUp(e, file.id)}
>
<TableIcon /> <TableIcon />
<FileNameWrapper>{file.name}</FileNameWrapper> <FileNameWrapper>{file.name}</FileNameWrapper>
</FileTabItem> </FileTabItem>

View File

@@ -2,11 +2,14 @@ import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { showMenu } from '../modals/DropDownMenu'; import { showMenu } from '../modals/DropDownMenu';
import { AppObjectCore } from './AppObjects'; import { AppObjectCore } from './AppObjects';
import { useSetOpenedFiles } from '../utility/globalState';
export function AppObjectList({ list, makeAppObj, SubItems = undefined, onObjectClick = undefined }) { export function AppObjectList({ list, makeAppObj, SubItems = undefined, onObjectClick = undefined }) {
const setOpenedFiles = useSetOpenedFiles();
return (list || []).map(x => { return (list || []).map(x => {
const appobj = makeAppObj(x); const appobj = makeAppObj(x, { setOpenedFiles });
let res = <AppObjectCore key={appobj.key} {...appobj} data={x} makeAppObj={makeAppObj} onClick={onObjectClick} />; if (onObjectClick) appobj.onClick = onObjectClick;
let res = <AppObjectCore key={appobj.key} data={x} makeAppObj={makeAppObj} {...appobj} />;
if (SubItems) { if (SubItems) {
res = ( res = (
<> <>

View File

@@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { showMenu } from '../modals/DropDownMenu'; import { showMenu } from '../modals/DropDownMenu';
import { useSetOpenedFiles } from '../utility/globalState';
const AppObjectDiv = styled.div` const AppObjectDiv = styled.div`
padding: 5px; padding: 5px;
@@ -34,6 +35,7 @@ export function AppObjectCore({ title, Icon, Menu, data, makeAppObj, onClick })
} }
export function AppObjectControl({ data, makeAppObj }) { export function AppObjectControl({ data, makeAppObj }) {
const appobj = makeAppObj(data); const setOpenedFiles = useSetOpenedFiles();
const appobj = makeAppObj(data, { setOpenedFiles });
return <AppObjectCore {...appobj} data={data} makeAppObj={makeAppObj} />; return <AppObjectCore {...appobj} data={data} makeAppObj={makeAppObj} />;
} }

View File

@@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import uuidv1 from 'uuid/v1';
import { TableIcon } from '../icons'; import { TableIcon } from '../icons';
import { DropDownMenuItem } from '../modals/DropDownMenu'; import { DropDownMenuItem } from '../modals/DropDownMenu';
import showModal from '../modals/showModal'; 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 title = schemaName ? `${schemaName}.${pureName}` : pureName;
const key = title; const key = title;
const Icon = TableIcon; 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 };
} }

View File

@@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import useStorage from './useStorage';
function createGlobalState(defaultValue) { function createGlobalState(defaultValue) {
const Context = React.createContext(null); const Context = React.createContext(null);
@@ -19,8 +20,30 @@ function createGlobalState(defaultValue) {
return [Provider, useValue, useSetValue]; 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'); const [CurrentWidgetProvider, useCurrentWidget, useSetCurrentWidget] = createGlobalState('database');
export { CurrentWidgetProvider, useCurrentWidget, useSetCurrentWidget }; export { CurrentWidgetProvider, useCurrentWidget, useSetCurrentWidget };
const [CurrentDatabaseProvider, useCurrentDatabase, useSetCurrentDatabase] = createGlobalState(null); const [CurrentDatabaseProvider, useCurrentDatabase, useSetCurrentDatabase] = createGlobalState(null);
export { CurrentDatabaseProvider, useCurrentDatabase, useSetCurrentDatabase }; export { CurrentDatabaseProvider, useCurrentDatabase, useSetCurrentDatabase };
const [OpenedFilesProvider, useOpenedFiles, useSetOpenedFiles] = createStorageState('openedFiles', []);
export { OpenedFilesProvider, useOpenedFiles, useSetOpenedFiles };

View 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];
}

View File

@@ -10412,6 +10412,11 @@ uuid@^3.0.1, uuid@^3.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== 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: v8-compile-cache@^2.0.3:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"