diff --git a/packages/api/package.json b/packages/api/package.json index 0ac5da100..8d8ee1eff 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -33,6 +33,7 @@ "express-basic-auth": "^1.2.0", "express-fileupload": "^1.2.0", "fs-extra": "^9.1.0", + "fs-reverse": "^0.0.3", "get-port": "^5.1.1", "http": "^0.0.0", "json-stable-stringify": "^1.0.1", @@ -71,4 +72,4 @@ "optionalDependencies": { "msnodesqlv8": "^2.0.10" } -} \ No newline at end of file +} diff --git a/packages/api/src/controllers/queryHistory.js b/packages/api/src/controllers/queryHistory.js new file mode 100644 index 000000000..e6a3ea077 --- /dev/null +++ b/packages/api/src/controllers/queryHistory.js @@ -0,0 +1,45 @@ +const fsReverse = require('fs-reverse'); +const fs = require('fs-extra'); +const path = require('path'); +const { datadir } = require('../utility/directories'); +const _ = require('lodash'); +const { filterName } = require('dbgate-tools'); + +function readCore(reader, skip, limit, filter) { + return new Promise(resolve => { + const res = []; + let readed = 0; + reader.on('data', line => { + const json = JSON.parse(line); + if (filterName(filter, json.sql)) { + if (!skip || readed >= skip) { + res.push(json); + } + readed++; + if (limit && readed > (skip || 0) + limit) { + reader.destroy(); + resolve(res); + } + } + }); + reader.on('end', () => resolve(res)); + }); +} + +module.exports = { + read_meta: 'get', + async read({ skip, limit, filter }) { + const fileName = path.join(datadir(), 'query-history.jsonl'); + // @ts-ignore + if (!(await fs.exists(fileName))) return []; + const reader = fsReverse(fileName); + const res = await readCore(reader, skip, limit, filter); + return res; + }, + + write_meta: 'post', + async write({ data }) { + const fileName = path.join(datadir(), 'query-history.jsonl'); + await fs.appendFile(fileName, JSON.stringify(data) + '\n'); + }, +}; diff --git a/packages/api/src/main.js b/packages/api/src/main.js index 3171aec00..29159fca9 100644 --- a/packages/api/src/main.js +++ b/packages/api/src/main.js @@ -27,6 +27,7 @@ const uploads = require('./controllers/uploads'); const plugins = require('./controllers/plugins'); const files = require('./controllers/files'); const scheduler = require('./controllers/scheduler'); +const queryHistory = require('./controllers/queryHistory'); const { rundir } = require('./utility/directories'); const platformInfo = require('./utility/platformInfo'); @@ -102,6 +103,7 @@ function start() { useController(app, '/plugins', plugins); useController(app, '/files', files); useController(app, '/scheduler', scheduler); + useController(app, '/query-history', queryHistory); // if (process.env.PAGES_DIRECTORY) { // app.use('/pages', express.static(process.env.PAGES_DIRECTORY)); diff --git a/packages/datalib/src/FormViewDisplay.ts b/packages/datalib/src/FormViewDisplay.ts index 48ccdd907..20a372a10 100644 --- a/packages/datalib/src/FormViewDisplay.ts +++ b/packages/datalib/src/FormViewDisplay.ts @@ -1,19 +1,7 @@ import _ from 'lodash'; import { GridConfig, GridCache, GridConfigColumns, createGridCache, GroupFunc } from './GridConfig'; -import { - ForeignKeyInfo, - TableInfo, - ColumnInfo, - EngineDriver, - NamedObjectInfo, - DatabaseInfo, - SqlDialect, -} from 'dbgate-types'; -import { parseFilter, getFilterType, getFilterValueExpression } from 'dbgate-filterparser'; -import { filterName } from './filterName'; -import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet'; -import { Expression, Select, treeToSql, dumpSqlSelect, Condition } from 'dbgate-sqltree'; -import { isTypeLogical } from 'dbgate-tools'; +import { TableInfo, EngineDriver, DatabaseInfo, SqlDialect } from 'dbgate-types'; +import { getFilterValueExpression } from 'dbgate-filterparser'; import { ChangeCacheFunc, ChangeConfigFunc, DisplayColumn } from './GridDisplay'; export class FormViewDisplay { diff --git a/packages/datalib/src/GridDisplay.ts b/packages/datalib/src/GridDisplay.ts index 6b7a78c66..9b5678a82 100644 --- a/packages/datalib/src/GridDisplay.ts +++ b/packages/datalib/src/GridDisplay.ts @@ -11,7 +11,7 @@ import { SqlDialect, } from 'dbgate-types'; import { parseFilter, getFilterType } from 'dbgate-filterparser'; -import { filterName } from './filterName'; +import { filterName } from 'dbgate-tools'; import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet'; import { Expression, Select, treeToSql, dumpSqlSelect, Condition } from 'dbgate-sqltree'; import { isTypeLogical } from 'dbgate-tools'; diff --git a/packages/datalib/src/TableFormViewDisplay.ts b/packages/datalib/src/TableFormViewDisplay.ts index 6043ca7b1..7c6bb292f 100644 --- a/packages/datalib/src/TableFormViewDisplay.ts +++ b/packages/datalib/src/TableFormViewDisplay.ts @@ -12,7 +12,6 @@ import { Condition, OrderByExpression, } from 'dbgate-sqltree'; -import { filterName } from './filterName'; import { TableGridDisplay } from './TableGridDisplay'; import stableStringify from 'json-stable-stringify'; import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet'; diff --git a/packages/datalib/src/TableGridDisplay.ts b/packages/datalib/src/TableGridDisplay.ts index 16d215e42..46bc64d5a 100644 --- a/packages/datalib/src/TableGridDisplay.ts +++ b/packages/datalib/src/TableGridDisplay.ts @@ -1,9 +1,9 @@ import _ from 'lodash'; +import { filterName } from 'dbgate-tools'; import { GridDisplay, ChangeCacheFunc, DisplayColumn, DisplayedColumnInfo, ChangeConfigFunc } from './GridDisplay'; import { TableInfo, EngineDriver, ViewInfo, ColumnInfo, NamedObjectInfo, DatabaseInfo } from 'dbgate-types'; import { GridConfig, GridCache, createGridCache } from './GridConfig'; import { Expression, Select, treeToSql, dumpSqlSelect } from 'dbgate-sqltree'; -import { filterName } from './filterName'; export class TableGridDisplay extends GridDisplay { public table: TableInfo; diff --git a/packages/datalib/src/index.ts b/packages/datalib/src/index.ts index 2e1788de6..b29344daf 100644 --- a/packages/datalib/src/index.ts +++ b/packages/datalib/src/index.ts @@ -4,7 +4,6 @@ export * from './TableGridDisplay'; export * from './ViewGridDisplay'; export * from './JslGridDisplay'; export * from './ChangeSet'; -export * from './filterName'; export * from './FreeTableGridDisplay'; export * from './FreeTableModel'; export * from './MacroDefinition'; diff --git a/packages/datalib/src/filterName.ts b/packages/tools/src/filterName.ts similarity index 89% rename from packages/datalib/src/filterName.ts rename to packages/tools/src/filterName.ts index a99dbda67..95867d507 100644 --- a/packages/datalib/src/filterName.ts +++ b/packages/tools/src/filterName.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import _compact from 'lodash/compact'; // original C# variant // public bool Match(string value) @@ -39,6 +39,6 @@ export function filterName(filter: string, ...names: string[]) { // const camelVariants = [name.replace(/[^A-Z]/g, '')] const tokens = filter.split(' ').map(x => x.trim()); - return !!_.compact(names).find(name => !tokens.find(token => !name.toUpperCase().includes(token.toUpperCase()))); + return !!_compact(names).find(name => !tokens.find(token => !name.toUpperCase().includes(token.toUpperCase()))); // return name.toUpperCase().includes(filter.toUpperCase()); } diff --git a/packages/tools/src/index.ts b/packages/tools/src/index.ts index c3b1c611e..0418719e0 100644 --- a/packages/tools/src/index.ts +++ b/packages/tools/src/index.ts @@ -10,3 +10,4 @@ export * from './testPermission'; export * from './SqlGenerator'; export * from './structureTools'; export * from './settingsExtractors'; +export * from './filterName'; diff --git a/packages/web/src/appobj/AppObjectList.svelte b/packages/web/src/appobj/AppObjectList.svelte index cf27e6652..cefe1ecf3 100644 --- a/packages/web/src/appobj/AppObjectList.svelte +++ b/packages/web/src/appobj/AppObjectList.svelte @@ -9,7 +9,7 @@ export let subItemsComponent = undefined; export let expandOnClick = false; export let isExpandable = undefined; - export let filter; + export let filter = undefined; export let expandIconFunc = undefined; export let checkedObjectsStore = null; export let disableContextMenu = false; @@ -34,6 +34,7 @@ : null; $: groups = groupFunc ? _.groupBy(listGrouped, 'group') : null; + {#if groupFunc} diff --git a/packages/web/src/appobj/ArchiveFileAppObject.svelte b/packages/web/src/appobj/ArchiveFileAppObject.svelte index 9031f0a24..c1da6219c 100644 --- a/packages/web/src/appobj/ArchiveFileAppObject.svelte +++ b/packages/web/src/appobj/ArchiveFileAppObject.svelte @@ -17,7 +17,7 @@ diff --git a/packages/web/src/datagrid/ReferenceManager.svelte b/packages/web/src/datagrid/ReferenceManager.svelte index 4534c81c5..cb0b5b0dd 100644 --- a/packages/web/src/datagrid/ReferenceManager.svelte +++ b/packages/web/src/datagrid/ReferenceManager.svelte @@ -1,5 +1,6 @@ @@ -86,4 +88,5 @@ .link:hover { text-decoration: underline; } + diff --git a/packages/web/src/formview/FormView.svelte b/packages/web/src/formview/FormView.svelte index b9617935b..baf296642 100644 --- a/packages/web/src/formview/FormView.svelte +++ b/packages/web/src/formview/FormView.svelte @@ -156,7 +156,7 @@ diff --git a/packages/web/src/widgets/FilesWidget.svelte b/packages/web/src/widgets/FilesWidget.svelte index 94f2d1993..ea4717951 100644 --- a/packages/web/src/widgets/FilesWidget.svelte +++ b/packages/web/src/widgets/FilesWidget.svelte @@ -3,9 +3,30 @@ import WidgetColumnBar from './WidgetColumnBar.svelte'; import WidgetColumnBarItem from './WidgetColumnBarItem.svelte'; + + import AppObjectList from '../appobj/AppObjectList.svelte'; + import * as closedTabAppObject from '../appobj/ClosedTabAppObject.svelte'; + import * as favoriteFileAppObject from '../appobj/FavoriteFileAppObject.svelte'; + import { openedTabs } from '../stores'; + + import hasPermission from '../utility/hasPermission'; + import { useFavorites } from '../utility/metadataLoaders'; + + import WidgetsInnerContainer from './WidgetsInnerContainer.svelte'; + + $: favorites = useFavorites(); + + {#if hasPermission('files/favorites/read')} + + + + + + {/if} + diff --git a/packages/web/src/widgets/FavoritesWidget.svelte b/packages/web/src/widgets/HistoryWidget.svelte similarity index 77% rename from packages/web/src/widgets/FavoritesWidget.svelte rename to packages/web/src/widgets/HistoryWidget.svelte index c4280ca5d..66a356d07 100644 --- a/packages/web/src/widgets/FavoritesWidget.svelte +++ b/packages/web/src/widgets/HistoryWidget.svelte @@ -14,16 +14,10 @@ import WidgetsInnerContainer from './WidgetsInnerContainer.svelte'; $: favorites = useFavorites(); + - {#if hasPermission('files/favorites/read')} - - - - - - {/if} {#if $selectedWidget == 'database'} @@ -14,15 +15,15 @@ import CellDataWidget from './CellDataWidget.svelte'; {#if $selectedWidget == 'file'} {/if} +{#if $selectedWidget == 'history'} + +{/if} {#if $selectedWidget == 'archive'} {/if} {#if $selectedWidget == 'plugins'} {/if} -{#if $selectedWidget == 'favorites'} - -{/if} {#if $selectedWidget == 'cell-data'} {/if} diff --git a/packages/web/src/widgets/WidgetIconPanel.svelte b/packages/web/src/widgets/WidgetIconPanel.svelte index 637a541e9..41dd2e07a 100644 --- a/packages/web/src/widgets/WidgetIconPanel.svelte +++ b/packages/web/src/widgets/WidgetIconPanel.svelte @@ -18,7 +18,12 @@ { icon: 'icon file', name: 'file', - title: 'Closed tabs & Saved SQL files', + title: 'Favorites & Saved files', + }, + { + icon: 'icon history', + name: 'history', + title: 'Query history & Closed tabs', }, { icon: 'icon archive', @@ -30,11 +35,6 @@ name: 'plugins', title: 'Extensions & Plugins', }, - { - icon: 'icon favorite', - name: 'favorites', - title: 'Favorites', - }, { icon: 'icon cell-data', name: 'cell-data', diff --git a/yarn.lock b/yarn.lock index 71c97e2ae..27759e55b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4359,6 +4359,11 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" +from@~0.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" + integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= + fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" @@ -4408,6 +4413,13 @@ fs-minipass@^2.0.0, fs-minipass@^2.1.0: dependencies: minipass "^3.0.0" +fs-reverse@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/fs-reverse/-/fs-reverse-0.0.3.tgz#5ef1e180a65fc0ee3cfb972d376114814203b43d" + integrity sha512-zu+5yhmaWueDBAWm7y6ejj2PipVep3EQlQYdfS6r3zsfzIfTVkcdbrsqye2UovisDqogu5dJFxae/dUAOYQqBA== + dependencies: + from "~0.1" + fs-write-stream-atomic@^1.0.8: version "1.0.10" resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9"