add to favorites basic functionality

This commit is contained in:
Jan Prochazka
2020-12-12 18:33:42 +01:00
parent b1a2093e6b
commit 3dcc761c14
23 changed files with 243 additions and 44 deletions

View File

@@ -66,6 +66,25 @@ module.exports = {
}
},
favorites_meta: 'get',
async favorites() {
if (!hasPermission(`files/favorites/read`)) return [];
const dir = path.join(filesdir(), 'favorites');
if (!(await fs.exists(dir))) return [];
const files = await fs.readdir(dir);
const res = [];
for (const file of files) {
const filePath = path.join(dir, file);
const text = await fs.readFile(filePath, { encoding: 'utf-8' });
res.push({
file,
folder: 'favorites',
...JSON.parse(text),
});
}
return res;
},
markdownManifest_meta: 'get',
async markdownManifest() {
if (!hasPermission(`files/markdown/read`)) return [];

View File

@@ -44,7 +44,7 @@ function Menu({ data, menuExt = null }) {
);
}
export function SavedFileAppObjectBase({ data, commonProps, format, icon, onLoad, menuExt = null }) {
export function SavedFileAppObjectBase({ data, commonProps, format, icon, onLoad, title = undefined, menuExt = null }) {
const { file, folder } = data;
const onClick = async () => {
@@ -56,7 +56,7 @@ export function SavedFileAppObjectBase({ data, commonProps, format, icon, onLoad
<AppObjectCore
{...commonProps}
data={data}
title={file}
title={title || file}
icon={icon}
onClick={onClick}
Menu={menuExt ? (props) => <Menu {...props} menuExt={menuExt} /> : Menu}
@@ -90,7 +90,7 @@ export function SavedSqlFileAppObject({ data, commonProps }) {
icon: 'img shell',
tabComponent: 'ShellTab',
},
script.getScript()
{ editor: script.getScript() }
);
};
@@ -111,6 +111,8 @@ export function SavedSqlFileAppObject({ data, commonProps }) {
initialData: data,
// @ts-ignore
savedFile: file,
savedFolder: 'sql',
savedFormat: 'text',
});
}}
/>
@@ -135,9 +137,11 @@ export function SavedShellFileAppObject({ data, commonProps }) {
tabComponent: 'ShellTab',
props: {
savedFile: file,
savedFolder: 'shell',
savedFormat: 'text',
},
},
data
{ editor: data }
);
}}
/>
@@ -171,10 +175,12 @@ export function SavedChartFileAppObject({ data, commonProps }) {
conid: connection._id,
database,
savedFile: file,
savedFolder: 'charts',
savedFormat: 'json',
},
tabComponent: 'ChartTab',
},
data
{ editor: data }
);
}}
/>
@@ -191,7 +197,9 @@ export function SavedMarkdownFileAppObject({ data, commonProps }) {
icon: 'img markdown',
tabComponent: 'MarkdownViewTab',
props: {
file,
savedFile: file,
savedFolder: 'markdown',
savedFormat: 'text',
},
});
};
@@ -209,9 +217,11 @@ export function SavedMarkdownFileAppObject({ data, commonProps }) {
tabComponent: 'MarkdownEditorTab',
props: {
savedFile: file,
savedFolder: 'markdown',
savedFormat: 'text',
},
},
data
{ editor: data }
);
}}
menuExt={<DropDownMenuItem onClick={showPage}>Show page</DropDownMenuItem>}
@@ -219,7 +229,51 @@ export function SavedMarkdownFileAppObject({ data, commonProps }) {
);
}
[SavedSqlFileAppObject, SavedShellFileAppObject, SavedChartFileAppObject, SavedMarkdownFileAppObject].forEach((fn) => {
export function FavoriteFileAppObject({ data, commonProps }) {
const { file, folder, icon, tabComponent, title, props, tabdata } = data;
const openNewTab = useOpenNewTab();
return (
<SavedFileAppObjectBase
data={data}
commonProps={commonProps}
format="json"
icon={icon || 'img favorite'}
title={title}
onLoad={async (data) => {
let tabdataNew = tabdata;
if (props.savedFile) {
const resp = await axios.post('files/load', {
folder: props.savedFolder,
file: props.savedFile,
format: props.savedFormat,
});
tabdataNew = {
...tabdata,
editor: resp.data,
};
}
openNewTab(
{
title,
icon: icon || 'img favorite',
props,
tabComponent,
},
tabdataNew
);
}}
/>
);
}
[
SavedSqlFileAppObject,
SavedShellFileAppObject,
SavedChartFileAppObject,
SavedMarkdownFileAppObject,
FavoriteFileAppObject,
].forEach((fn) => {
// @ts-ignore
fn.extractKey = (data) => data.file;
});

View File

@@ -341,7 +341,7 @@ export default function DataGridCore(props) {
tabComponent: 'FreeTableTab',
props: {},
},
getSelectedFreeData()
{ editor: getSelectedFreeData() }
);
};
@@ -354,8 +354,10 @@ export default function DataGridCore(props) {
props: {},
},
{
data: getSelectedFreeData(),
config: { chartType: 'bar' },
editor: {
data: getSelectedFreeData(),
config: { chartType: 'bar' },
},
}
);
};

View File

@@ -92,10 +92,12 @@ export default function SqlDataGridCore(props) {
},
},
{
config: { chartType: 'bar' },
sql: display.getExportQuery((select) => {
select.orderBy = null;
}),
editor: {
config: { chartType: 'bar' },
sql: display.getExportQuery((select) => {
select.orderBy = null;
}),
},
}
);
}

View File

@@ -9,6 +9,7 @@ const iconNames = {
'icon export': 'mdi mdi-application-export',
'icon new-connection': 'mdi mdi-database-plus',
'icon tables': 'mdi mdi-table-multiple',
'icon favorite': 'mdi mdi-star',
'icon database': 'mdi mdi-database',
'icon server': 'mdi mdi-server',
@@ -65,6 +66,7 @@ const iconNames = {
'img chart': 'mdi mdi-chart-bar color-magenta-7',
'img markdown': 'mdi mdi-application color-red-7',
'img preview': 'mdi mdi-file-find color-red-7',
'img favorite': 'mdi mdi-star color-yellow-7',
'img free-table': 'mdi mdi-table color-green-7',
'img macro': 'mdi mdi-hammer-wrench',

View File

@@ -23,7 +23,7 @@ export default function OpenChartLink({ file, children }) {
savedFile: file,
},
},
resp.data
{ editor: resp.data }
);
};

View File

@@ -104,7 +104,7 @@ function GenerateSctriptButton({ modalState }) {
icon: 'img shell',
tabComponent: 'ShellTab',
},
code
{ editor: code }
);
modalState.close();
};

View File

@@ -13,7 +13,12 @@ export default function SaveTabModal({ data, folder, format, modalState, tabid,
changeTab(tabid, setOpenedTabs, (tab) => ({
...tab,
title: name,
props: { ...tab.props, savedFile: name },
props: {
...tab.props,
savedFile: name,
savedFolder: folder,
savedFormat: format,
},
}));
const handleKeyboard = React.useCallback(

View File

@@ -24,6 +24,6 @@ export default function useNewQuery() {
database,
},
},
initialData
{ editor: initialData }
);
}

View File

@@ -74,3 +74,5 @@ export default function ChartTab({ tabVisible, toolbarPortalRef, conid, database
</>
);
}
ChartTab.allowAddToFavorites = (props) => props.savedFile;

View File

@@ -3,13 +3,17 @@ import axios from '../utility/axios';
import LoadingInfo from '../widgets/LoadingInfo';
import MarkdownExtendedView from '../markdown/MarkdownExtendedView';
export default function MarkdownViewTab({ file }) {
export default function MarkdownViewTab({ savedFile }) {
const [isLoading, setIsLoading] = React.useState(false);
const [text, setText] = React.useState(null);
const handleLoad = async () => {
setIsLoading(true);
const resp = await axios.post('files/load', { folder: 'markdown', file, format: 'text' });
const resp = await axios.post('files/load', {
folder: 'markdown',
file: savedFile,
format: 'text',
});
setText(resp.data);
setIsLoading(false);
};
@@ -28,3 +32,5 @@ export default function MarkdownViewTab({ file }) {
return <MarkdownExtendedView>{text || ''}</MarkdownExtendedView>;
}
MarkdownViewTab.allowAddToFavorites = (props) => true;

View File

@@ -176,3 +176,5 @@ export default function QueryTab({ tabid, conid, database, initialArgs, tabVisib
</>
);
}
QueryTab.allowAddToFavorites = (props) => props.savedFile;

View File

@@ -139,3 +139,5 @@ export default function ShellTab({ tabid, tabVisible, toolbarPortalRef, ...other
</>
);
}
ShellTab.allowAddToFavorites = (props) => props.savedFile;

View File

@@ -28,3 +28,4 @@ export default function TableDataTab({ conid, database, schemaName, pureName, ta
}
TableDataTab.matchingProps = ['conid', 'database', 'schemaName', 'pureName'];
TableDataTab.allowAddToFavorites = (props) => true;

View File

@@ -55,4 +55,5 @@ export default function ViewDataTab({ conid, database, schemaName, pureName, tab
);
}
ViewDataTab.matchingProps = ['conid', 'database', 'schemaName', 'pureName'];
ViewDataTab.matchingProps = ['conid', 'database', 'schemaName', 'pureName'];
ViewDataTab.allowAddToFavorites = (props) => true;

View File

@@ -46,6 +46,12 @@ const configLoader = () => ({
reloadTrigger: 'config-changed',
});
const favoritesLoader = () => ({
url: 'files/favorites',
params: {},
reloadTrigger: 'files-changed-favorites',
});
const markdownManifestLoader = () => ({
url: 'files/markdown-manifest',
params: {},
@@ -282,3 +288,10 @@ export function getMarkdownManifest(args) {
export function useMarkdownManifest(args) {
return useCore(markdownManifestLoader, args);
}
export function getFavorites(args) {
return getCore(favoritesLoader, args);
}
export function useFavorites(args) {
return useCore(favoritesLoader, args);
}

View File

@@ -5,7 +5,7 @@ import { changeTab } from './common';
import { useSetOpenedTabs } from './globalState';
export default function useEditorData({ tabid, reloadToken = 0, loadFromArgs = null }) {
const localStorageKey = `tabdata_${tabid}`;
const localStorageKey = `tabdata_editor_${tabid}`;
const setOpenedTabs = useSetOpenedTabs();
const changeCounterRef = React.useRef(0);
const savedCounterRef = React.useRef(0);

View File

@@ -46,7 +46,13 @@ export default function useOpenNewTab() {
const tabid = uuidv1();
if (initialData) {
await localforage.setItem(`tabdata_${tabid}`, initialData);
for (const key of _.keys(initialData)) {
if (key == 'editor') {
await localforage.setItem(`tabdata_${key}_${tabid}`, initialData[key]);
} else {
localStorage.setItem(`tabdata_${key}_${tabid}`, JSON.stringify(initialData[key]));
}
}
}
setOpenedTabs((files) => [
...(files || []).map((x) => ({ ...x, selected: false })),

View File

@@ -0,0 +1,57 @@
import React from 'react';
import _ from 'lodash';
import { AppObjectList } from '../appobj/AppObjectList';
import { useOpenedTabs } from '../utility/globalState';
import ClosedTabAppObject from '../appobj/ClosedTabAppObject';
import { WidgetsInnerContainer } from './WidgetStyles';
import { FavoriteFileAppObject } from '../appobj/SavedFileAppObject';
import WidgetColumnBar, { WidgetColumnBarItem } from './WidgetColumnBar';
import { useFavorites, useFiles } from '../utility/metadataLoaders';
import useHasPermission from '../utility/useHasPermission';
function ClosedTabsList() {
const tabs = useOpenedTabs();
return (
<>
<WidgetsInnerContainer>
<AppObjectList
list={_.sortBy(
tabs.filter((x) => x.closedTime),
(x) => -x.closedTime
)}
AppObjectComponent={ClosedTabAppObject}
/>
</WidgetsInnerContainer>
</>
);
}
function FavoritesList() {
const favorites = useFavorites();
return (
<>
<WidgetsInnerContainer>
<AppObjectList list={favorites} AppObjectComponent={FavoriteFileAppObject} />
</WidgetsInnerContainer>
</>
);
}
export default function FavoritesWidget() {
const hasPermission = useHasPermission();
return (
<WidgetColumnBar>
<WidgetColumnBarItem title="Recently closed tabs" name="closedTabs" height="20%">
<ClosedTabsList />
</WidgetColumnBarItem>
{hasPermission('files/favorites/read') && (
<WidgetColumnBarItem title="Favorites" name="favorites" height="15%">
<FavoritesList />
</WidgetColumnBarItem>
)}
</WidgetColumnBar>
);
}

View File

@@ -15,23 +15,6 @@ import WidgetColumnBar, { WidgetColumnBarItem } from './WidgetColumnBar';
import { useFiles } from '../utility/metadataLoaders';
import useHasPermission from '../utility/useHasPermission';
function ClosedTabsList() {
const tabs = useOpenedTabs();
return (
<>
<WidgetsInnerContainer>
<AppObjectList
list={_.sortBy(
tabs.filter((x) => x.closedTime),
(x) => -x.closedTime
)}
AppObjectComponent={ClosedTabAppObject}
/>
</WidgetsInnerContainer>
</>
);
}
function SavedSqlFilesList() {
const files = useFiles({ folder: 'sql' });
@@ -85,9 +68,6 @@ export default function FilesWidget() {
const hasPermission = useHasPermission();
return (
<WidgetColumnBar>
<WidgetColumnBarItem title="Recently closed tabs" name="closedTabs" height="20%">
<ClosedTabsList />
</WidgetColumnBarItem>
{hasPermission('files/sql/read') && (
<WidgetColumnBarItem title="Saved SQL files" name="sqlFiles" height="15%">
<SavedSqlFilesList />

View File

@@ -14,6 +14,9 @@ import { getDefaultFileFormat } from '../utility/fileformats';
import getElectron from '../utility/getElectron';
import AboutModal from '../modals/AboutModal';
import useOpenNewTab from '../utility/useOpenNewTab';
import axios from '../utility/axios';
import tabs from '../tabs';
import uuidv1 from 'uuid/v1';
const ToolbarContainer = styled.div`
display: flex;
@@ -36,6 +39,8 @@ export default function ToolBar({ toolbarPortalRef }) {
const electron = getElectron();
const markdownManifest = useMarkdownManifest();
const currentTab = openedTabs.find((x) => x.selected);
React.useEffect(() => {
window['dbgate_createNewConnection'] = modalState.open;
window['dbgate_newQuery'] = newQuery;
@@ -76,6 +81,31 @@ export default function ToolBar({ toolbarPortalRef }) {
});
};
const addToFavorite = () => {
const tabdata = {};
const re = new RegExp(`tabdata_(.*)_${currentTab.tabid}`);
for (const key in localStorage) {
const match = key.match(re);
if (!match) continue;
if (match[1] == 'editor') continue;
tabdata[match[1]] = JSON.parse(localStorage.getItem(key));
}
axios.post('files/save', {
folder: 'favorites',
file: uuidv1(),
format: 'json',
data: {
title: currentTab.title,
icon: currentTab.icon,
props: currentTab.props,
tabComponent: currentTab.tabComponent,
tabdata,
},
});
};
function openTabFromButton(page) {
if (
openedTabs.find(
@@ -134,6 +164,14 @@ export default function ToolBar({ toolbarPortalRef }) {
<ToolbarButton onClick={showImport} icon="icon import">
Import data
</ToolbarButton>
{!!currentTab &&
tabs[currentTab.tabComponent] &&
tabs[currentTab.tabComponent].allowAddToFavorites &&
tabs[currentTab.tabComponent].allowAddToFavorites(currentTab.props) && (
<ToolbarButton onClick={addToFavorite} icon="icon favorite">
Add to favorites
</ToolbarButton>
)}
<ToolbarButton onClick={switchTheme} icon="icon theme">
{currentTheme == 'dark' ? 'Light mode' : 'Dark mode'}
</ToolbarButton>

View File

@@ -2,6 +2,7 @@ import React from 'react';
import { useCurrentWidget } from '../utility/globalState';
import ArchiveWidget from './ArchiveWidget';
import DatabaseWidget from './DatabaseWidget';
import FavoritesWidget from './FavoritesWidget';
import FilesWidget from './FilesWidget';
import PluginsWidget from './PluginsWidget';
@@ -11,5 +12,6 @@ export default function WidgetContainer() {
if (currentWidget === 'file') return <FilesWidget />;
if (currentWidget === 'archive') return <ArchiveWidget />;
if (currentWidget === 'plugins') return <PluginsWidget />;
if (currentWidget === 'favorites') return <FavoritesWidget />;
return null;
}

View File

@@ -56,6 +56,11 @@ export default function WidgetIconPanel() {
name: 'plugins',
title: 'Extensions & Plugins',
},
{
icon: 'icon favorite',
name: 'favorites',
title: 'Favorites',
},
// {
// icon: 'fa-cog',
// name: 'settings',