diff --git a/.github/workflows/build-app-beta.yaml b/.github/workflows/build-app-beta.yaml index b2c02274e..c7f08bb8b 100644 --- a/.github/workflows/build-app-beta.yaml +++ b/.github/workflows/build-app-beta.yaml @@ -19,7 +19,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 with: fetch-depth: 1 - name: Use Node.js 10.x diff --git a/.github/workflows/build-app.yaml b/.github/workflows/build-app.yaml index 39f6109e9..33e526413 100644 --- a/.github/workflows/build-app.yaml +++ b/.github/workflows/build-app.yaml @@ -23,7 +23,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 with: fetch-depth: 1 - name: Use Node.js 10.x diff --git a/.github/workflows/build-docker-beta.yaml b/.github/workflows/build-docker-beta.yaml index 4801df4c8..b75b2aa19 100644 --- a/.github/workflows/build-docker-beta.yaml +++ b/.github/workflows/build-docker-beta.yaml @@ -21,7 +21,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 with: fetch-depth: 1 - name: Use Node.js 10.x diff --git a/.github/workflows/build-docker.yaml b/.github/workflows/build-docker.yaml index 629baa736..8534460ef 100644 --- a/.github/workflows/build-docker.yaml +++ b/.github/workflows/build-docker.yaml @@ -27,7 +27,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 with: fetch-depth: 1 - name: Use Node.js 10.x diff --git a/.github/workflows/build-npm.yaml b/.github/workflows/build-npm.yaml index 4757c13ce..fba1d0c3e 100644 --- a/.github/workflows/build-npm.yaml +++ b/.github/workflows/build-npm.yaml @@ -27,7 +27,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 with: fetch-depth: 1 - name: Use Node.js 10.x diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 3b261eb9a..6a44fd5b9 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -15,7 +15,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 with: fetch-depth: 1 - name: yarn install diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cae8679a..13f6928a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # ChangeLog +### 4.3.1 +- FIXED: #173 Using key phrase for SSH key file connection +- ADDED: #172 Abiloity to quick search within database names +- ADDED: Database search added to command palette (Ctrl+P) +- FIXED: #171 fixed PostgreSQL analyser for older versions than 9.3 (matviews don't exist) +- ADDED: DELETE cascade option - ability to delete all referenced rows, when deleting rows + ### 4.3.0 - ADDED: Table structure editor - ADDED: Index support diff --git a/app/src/electron.js b/app/src/electron.js index f1eb3a584..1a194b9c9 100644 --- a/app/src/electron.js +++ b/app/src/electron.js @@ -50,8 +50,10 @@ function buildMenu() { commandItem('file.open'), commandItem('group.save'), commandItem('group.saveAs'), + commandItem('database.search'), { type: 'separator' }, - { role: 'close' }, + commandItem('tabs.closeTab'), + commandItem('file.exit'), ], }, { diff --git a/package.json b/package.json index a7b35f372..d60013a7c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "4.3.0", + "version": "4.3.1", "name": "dbgate-all", "workspaces": [ "packages/*", diff --git a/packages/api/package.json b/packages/api/package.json index 4be96950b..b342da35d 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -66,7 +66,7 @@ "env-cmd": "^10.1.0", "node-loader": "^1.0.2", "nodemon": "^2.0.2", - "typescript": "^3.7.4", + "typescript": "^4.4.3", "webpack": "^4.42.0", "webpack-cli": "^3.3.11" }, diff --git a/packages/api/src/proc/databaseConnectionProcess.js b/packages/api/src/proc/databaseConnectionProcess.js index 898697049..ed3a6cbe3 100644 --- a/packages/api/src/proc/databaseConnectionProcess.js +++ b/packages/api/src/proc/databaseConnectionProcess.js @@ -14,6 +14,7 @@ let analysedStructure = null; let lastPing = null; let lastStatus = null; let analysedTime = 0; +let serverVersion; async function checkedAsyncCall(promise) { try { @@ -36,7 +37,7 @@ async function handleFullRefresh() { loadingModel = true; const driver = requireEngineDriver(storedConnection); setStatusName('loadStructure'); - analysedStructure = await checkedAsyncCall(driver.analyseFull(systemConnection)); + analysedStructure = await checkedAsyncCall(driver.analyseFull(systemConnection, serverVersion)); analysedTime = new Date().getTime(); process.send({ msgtype: 'structure', structure: analysedStructure }); process.send({ msgtype: 'structureTime', analysedTime }); @@ -48,7 +49,7 @@ async function handleIncrementalRefresh(forceSend) { loadingModel = true; const driver = requireEngineDriver(storedConnection); setStatusName('checkStructure'); - const newStructure = await checkedAsyncCall(driver.analyseIncremental(systemConnection, analysedStructure)); + const newStructure = await checkedAsyncCall(driver.analyseIncremental(systemConnection, analysedStructure, serverVersion)); analysedTime = new Date().getTime(); if (newStructure != null) { analysedStructure = newStructure; @@ -84,6 +85,7 @@ async function readVersion() { const driver = requireEngineDriver(storedConnection); const version = await driver.getVersion(systemConnection); process.send({ msgtype: 'version', version }); + serverVersion = version; } async function handleConnect({ connection, structure, globalSettings }) { @@ -93,7 +95,7 @@ async function handleConnect({ connection, structure, globalSettings }) { if (!structure) setStatusName('pending'); const driver = requireEngineDriver(storedConnection); systemConnection = await checkedAsyncCall(connectUtility(driver, storedConnection)); - readVersion(); + await checkedAsyncCall(readVersion()); if (structure) { analysedStructure = structure; handleIncrementalRefresh(true); diff --git a/packages/api/src/utility/crypting.js b/packages/api/src/utility/crypting.js index 491ed39ae..d7428df77 100644 --- a/packages/api/src/utility/crypting.js +++ b/packages/api/src/utility/crypting.js @@ -70,14 +70,14 @@ function decryptPasswordField(connection, field) { function encryptConnection(connection) { connection = encryptPasswordField(connection, 'password'); connection = encryptPasswordField(connection, 'sshPassword'); - connection = encryptPasswordField(connection, 'sshKeyFilePassword'); + connection = encryptPasswordField(connection, 'sshKeyfilePassword'); return connection; } function decryptConnection(connection) { connection = decryptPasswordField(connection, 'password'); connection = decryptPasswordField(connection, 'sshPassword'); - connection = decryptPasswordField(connection, 'sshKeyFilePassword'); + connection = decryptPasswordField(connection, 'sshKeyfilePassword'); return connection; } diff --git a/packages/api/src/utility/platformInfo.js b/packages/api/src/utility/platformInfo.js index 2141df45e..2025dc72b 100644 --- a/packages/api/src/utility/platformInfo.js +++ b/packages/api/src/utility/platformInfo.js @@ -37,7 +37,7 @@ const platformInfo = { environment: process.env.NODE_ENV, platform, runningInWebpack: !!process.env.WEBPACK_DEV_SERVER_URL, - defaultKeyFile: path.join(os.homedir(), '.ssh/id_rsa'), + defaultKeyfile: path.join(os.homedir(), '.ssh/id_rsa'), }; module.exports = platformInfo; diff --git a/packages/api/src/utility/sshTunnel.js b/packages/api/src/utility/sshTunnel.js index 25484526a..a330821dd 100644 --- a/packages/api/src/utility/sshTunnel.js +++ b/packages/api/src/utility/sshTunnel.js @@ -16,9 +16,9 @@ const CONNECTION_FIELDS = [ 'sshLogin', 'sshPassword', 'sshMode', - 'sshKeyFile', + 'sshKeyfile', 'sshBastionHost', - 'sshKeyFilePassword', + 'sshKeyfilePassword', ]; const TUNNEL_FIELDS = [...CONNECTION_FIELDS, 'server', 'port']; @@ -31,7 +31,7 @@ async function getSshConnection(connection) { endPort: connection.sshPort || 22, bastionHost: connection.sshBastionHost || '', agentForward: connection.sshMode == 'agent', - passphrase: connection.sshMode == 'keyFile' ? connection.sshKeyFilePassword : undefined, + passphrase: connection.sshMode == 'keyFile' ? connection.sshKeyfilePassword : undefined, username: connection.sshLogin, password: connection.sshMode == 'userPassword' ? connection.sshPassword : undefined, agentSocket: connection.sshMode == 'agent' ? platformInfo.sshAuthSock : undefined, diff --git a/packages/datalib/package.json b/packages/datalib/package.json index 984ffa7fe..b39bdcc7b 100644 --- a/packages/datalib/package.json +++ b/packages/datalib/package.json @@ -17,6 +17,6 @@ "devDependencies": { "dbgate-types": "^4.1.1", "@types/node": "^13.7.0", - "typescript": "^3.7.5" + "typescript": "^4.4.3" } } \ No newline at end of file diff --git a/packages/datalib/src/ChangeSet.ts b/packages/datalib/src/ChangeSet.ts index 97c7aef12..a9a7011b8 100644 --- a/packages/datalib/src/ChangeSet.ts +++ b/packages/datalib/src/ChangeSet.ts @@ -118,7 +118,11 @@ export function setChangeSetValue( }; } -export function setChangeSetRowData(changeSet: ChangeSet, definition: ChangeSetRowDefinition, document: any): ChangeSet { +export function setChangeSetRowData( + changeSet: ChangeSet, + definition: ChangeSetRowDefinition, + document: any +): ChangeSet { if (!changeSet || !definition) return changeSet; let [fieldName, existingItem] = findExistingChangeSetItem(changeSet, definition); if (fieldName == 'deletes') { @@ -213,7 +217,7 @@ function extractFields(item: ChangeSetItem, allowNulls = true): UpdateField[] { })); } -function insertToSql( +function changeSetInsertToSql( item: ChangeSetItem, dbinfo: DatabaseInfo = null ): [AllowIdentityInsert, Insert, AllowIdentityInsert] { @@ -257,7 +261,7 @@ function insertToSql( ]; } -function extractCondition(item: ChangeSetItem): Condition { +export function extractChangeSetCondition(item: ChangeSetItem, alias?: string): Condition { return { conditionType: 'and', conditions: _.keys(item.condition).map(columnName => ({ @@ -271,6 +275,7 @@ function extractCondition(item: ChangeSetItem): Condition { pureName: item.pureName, schemaName: item.schemaName, }, + alias, }, }, right: { @@ -281,7 +286,7 @@ function extractCondition(item: ChangeSetItem): Condition { }; } -function updateToSql(item: ChangeSetItem): Update { +function changeSetUpdateToSql(item: ChangeSetItem): Update { return { from: { name: { @@ -291,11 +296,11 @@ function updateToSql(item: ChangeSetItem): Update { }, commandType: 'update', fields: extractFields(item), - where: extractCondition(item), + where: extractChangeSetCondition(item), }; } -function deleteToSql(item: ChangeSetItem): Delete { +function changeSetDeleteToSql(item: ChangeSetItem): Delete { return { from: { name: { @@ -304,16 +309,16 @@ function deleteToSql(item: ChangeSetItem): Delete { }, }, commandType: 'delete', - where: extractCondition(item), + where: extractChangeSetCondition(item), }; } export function changeSetToSql(changeSet: ChangeSet, dbinfo: DatabaseInfo): Command[] { return _.compact( _.flatten([ - ...(changeSet.inserts.map(item => insertToSql(item, dbinfo)) as any), - ...changeSet.updates.map(updateToSql), - ...changeSet.deletes.map(deleteToSql), + ...(changeSet.inserts.map(item => changeSetInsertToSql(item, dbinfo)) as any), + ...changeSet.updates.map(changeSetUpdateToSql), + ...changeSet.deletes.map(changeSetDeleteToSql), ]) ); } diff --git a/packages/datalib/src/deleteCascade.ts b/packages/datalib/src/deleteCascade.ts new file mode 100644 index 000000000..b93241056 --- /dev/null +++ b/packages/datalib/src/deleteCascade.ts @@ -0,0 +1,136 @@ +import _ from 'lodash'; +import { Command, Insert, Update, Delete, UpdateField, Condition, AllowIdentityInsert } from 'dbgate-sqltree'; +import { NamedObjectInfo, DatabaseInfo, ForeignKeyInfo, TableInfo } from 'dbgate-types'; +import { ChangeSet, ChangeSetItem, extractChangeSetCondition } from './ChangeSet'; + +export interface ChangeSetDeleteCascade { + title: string; + commands: Command[]; +} + +// function getDeleteScript() + +function processDependencies( + changeSet: ChangeSet, + result: ChangeSetDeleteCascade[], + allForeignKeys: ForeignKeyInfo[], + fkPath: ForeignKeyInfo[], + table: TableInfo, + baseCmd: ChangeSetItem, + dbinfo: DatabaseInfo +) { + if (result.find(x => x.title == table.pureName)) return; + + const dependencies = allForeignKeys.filter( + x => x.refSchemaName == table.schemaName && x.refTableName == table.pureName + ); + + for (const fk of dependencies) { + const depTable = dbinfo.tables.find(x => x.pureName == fk.pureName && x.schemaName == fk.schemaName); + const subFkPath = [...fkPath, fk]; + if (depTable && depTable.pureName != baseCmd.pureName) { + processDependencies(changeSet, result, allForeignKeys, subFkPath, depTable, baseCmd, dbinfo); + } + + const refCmd: Delete = { + commandType: 'delete', + from: { + name: { + pureName: fk.pureName, + schemaName: fk.schemaName, + }, + }, + where: { + conditionType: 'exists', + subQuery: { + commandType: 'select', + selectAll: true, + from: { + name: { + pureName: fk.pureName, + schemaName: fk.schemaName, + }, + alias: 't0', + relations: subFkPath.map((fkItem, fkIndex) => ({ + joinType: 'INNER JOIN', + alias: `t${fkIndex + 1}`, + name: { + pureName: fkItem.refTableName, + schemaName: fkItem.refSchemaName, + }, + conditions: fkItem.columns.map(column => ({ + conditionType: 'binary', + operator: '=', + left: { + exprType: 'column', + columnName: column.columnName, + source: { alias: `t${fkIndex}` }, + }, + right: { + exprType: 'column', + columnName: column.refColumnName, + source: { alias: `t${fkIndex + 1}` }, + }, + })), + })), + }, + where: { + conditionType: 'and', + conditions: [ + extractChangeSetCondition(baseCmd, `t${subFkPath.length}`), + // @ts-ignore + ...table.primaryKey.columns.map(column => ({ + conditionType: 'binary', + operator: '=', + left: { + exprType: 'column', + columnName: column.columnName, + source: { alias: 't0' }, + }, + right: { + exprType: 'column', + columnName: column.columnName, + source: { + name: fk, + }, + }, + })), + ], + }, + }, + }, + }; + let resItem = result.find(x => x.title == fk.pureName); + if (!resItem) { + resItem = { + title: fk.pureName, + commands: [], + }; + result.push(resItem); + } + resItem.commands.push(refCmd); + } +} + +export function getDeleteCascades(changeSet: ChangeSet, dbinfo: DatabaseInfo): ChangeSetDeleteCascade[] { + const result: ChangeSetDeleteCascade[] = []; + const allForeignKeys = _.flatten(dbinfo.tables.map(x => x.foreignKeys)); + for (const baseCmd of changeSet.deletes) { + const table = dbinfo.tables.find(x => x.pureName == baseCmd.pureName && x.schemaName == baseCmd.schemaName); + if (!table.primaryKey) continue; + + processDependencies(changeSet, result, allForeignKeys, [], table, baseCmd, dbinfo); + + // let resItem = result.find(x => x.title == baseCmd.pureName); + // if (!resItem) { + // resItem = { + // title: baseCmd.pureName, + // commands: [], + // }; + // result.push(resItem); + // } + // resItem.commands.push(changeSetDeleteToSql(baseCmd)); + } + + return result; +} diff --git a/packages/datalib/src/index.ts b/packages/datalib/src/index.ts index b29344daf..7bff4808e 100644 --- a/packages/datalib/src/index.ts +++ b/packages/datalib/src/index.ts @@ -11,3 +11,4 @@ export * from './runMacro'; export * from './FormViewDisplay'; export * from './TableFormViewDisplay'; export * from './CollectionGridDisplay'; +export * from './deleteCascade'; diff --git a/packages/filterparser/package.json b/packages/filterparser/package.json index 9b8a82c74..35f071052 100644 --- a/packages/filterparser/package.json +++ b/packages/filterparser/package.json @@ -18,7 +18,7 @@ "@types/node": "^13.7.0", "jest": "^24.9.0", "ts-jest": "^25.2.1", - "typescript": "^3.7.5" + "typescript": "^4.4.3" }, "dependencies": { "@types/parsimmon": "^1.10.1", diff --git a/packages/query-splitter/package.json b/packages/query-splitter/package.json index e4668e6eb..7d2cce9c2 100644 --- a/packages/query-splitter/package.json +++ b/packages/query-splitter/package.json @@ -32,6 +32,6 @@ "@types/node": "^13.7.0", "jest": "^24.9.0", "ts-jest": "^25.2.1", - "typescript": "^3.7.5" + "typescript": "^4.4.3" } } \ No newline at end of file diff --git a/packages/sqltree/package.json b/packages/sqltree/package.json index aa21d8a98..27f245665 100644 --- a/packages/sqltree/package.json +++ b/packages/sqltree/package.json @@ -28,7 +28,7 @@ "devDependencies": { "@types/node": "^13.7.0", "dbgate-types": "^4.1.1", - "typescript": "^3.7.5" + "typescript": "^4.4.3" }, "dependencies": { "lodash": "^4.17.21" diff --git a/packages/tools/package.json b/packages/tools/package.json index 554098260..a4e4df6a0 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -28,7 +28,7 @@ "dbgate-types": "^4.1.1", "jest": "^24.9.0", "ts-jest": "^25.2.1", - "typescript": "^3.7.5" + "typescript": "^4.4.3" }, "dependencies": { "lodash": "^4.17.21", diff --git a/packages/tools/src/DatabaseAnalyser.ts b/packages/tools/src/DatabaseAnalyser.ts index 45d8d7baa..6c92272ab 100644 --- a/packages/tools/src/DatabaseAnalyser.ts +++ b/packages/tools/src/DatabaseAnalyser.ts @@ -1,4 +1,4 @@ -import { DatabaseInfo, DatabaseModification, EngineDriver } from 'dbgate-types'; +import { DatabaseInfo, DatabaseModification, EngineDriver, SqlDialect } from 'dbgate-types'; import _sortBy from 'lodash/sortBy'; import _groupBy from 'lodash/groupBy'; import _pick from 'lodash/pick'; @@ -13,8 +13,11 @@ export class DatabaseAnalyser { modifications: DatabaseModification[]; singleObjectFilter: any; singleObjectId: string = null; + dialect: SqlDialect; - constructor(public pool, public driver: EngineDriver) {} + constructor(public pool, public driver: EngineDriver, version) { + this.dialect = (driver?.dialectByVersion && driver?.dialectByVersion(version)) || driver?.dialect; + } async _runAnalysis() { return DatabaseAnalyser.createEmptyStructure(); diff --git a/packages/tools/src/driverBase.ts b/packages/tools/src/driverBase.ts index 7adeb8cfd..671f2fc33 100644 --- a/packages/tools/src/driverBase.ts +++ b/packages/tools/src/driverBase.ts @@ -17,8 +17,8 @@ export const driverBase = { dumperClass: SqlDumper, dialect, - async analyseFull(pool) { - const analyser = new this.analyserClass(pool, this); + async analyseFull(pool, version) { + const analyser = new this.analyserClass(pool, this, version); return analyser.fullAnalysis(); }, async analyseSingleObject(pool, name, typeField = 'tables') { @@ -28,8 +28,8 @@ export const driverBase = { analyseSingleTable(pool, name) { return this.analyseSingleObject(pool, name, 'tables'); }, - async analyseIncremental(pool, structure) { - const analyser = new this.analyserClass(pool, this); + async analyseIncremental(pool, structure, version) { + const analyser = new this.analyserClass(pool, this, version); return analyser.incrementalAnalysis(structure); }, createDumper() { diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index 4f7510805..0a728b0a1 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -67,8 +67,8 @@ export interface EngineDriver { name: string; }[] >; - analyseFull(pool: any): Promise; - analyseIncremental(pool: any, structure: DatabaseInfo): Promise; + analyseFull(pool: any, serverVersion): Promise; + analyseIncremental(pool: any, structure: DatabaseInfo, serverVersion): Promise; dialect: SqlDialect; dialectByVersion(version): SqlDialect; createDumper(): SqlDumper; diff --git a/packages/web/package.json b/packages/web/package.json index 06dee6a0f..6fb18471c 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -14,10 +14,10 @@ "devDependencies": { "@ant-design/colors": "^5.0.0", "@mdi/font": "^5.9.55", - "@rollup/plugin-commonjs": "^17.0.0", - "@rollup/plugin-node-resolve": "^11.0.0", - "@rollup/plugin-replace": "^2.4.1", - "@rollup/plugin-typescript": "^6.0.0", + "@rollup/plugin-commonjs": "^20.0.0", + "@rollup/plugin-node-resolve": "^13.0.5", + "@rollup/plugin-replace": "^3.0.0", + "@rollup/plugin-typescript": "^8.2.5", "@tsconfig/svelte": "^1.0.0", "ace-builds": "^1.4.8", "chart.js": "^2.9.4", @@ -32,7 +32,7 @@ "lodash": "^4.17.21", "randomcolor": "^0.6.2", "resize-observer-polyfill": "^1.5.1", - "rollup": "^2.3.4", + "rollup": "^2.57.0", "rollup-plugin-copy": "^3.3.0", "rollup-plugin-css-only": "^3.1.0", "rollup-plugin-livereload": "^2.0.0", @@ -41,13 +41,13 @@ "sirv-cli": "^1.0.0", "socket.io-client": "^2.3.0", "sql-formatter": "^2.3.3", - "svelte": "^3.35.0", + "svelte": "^3.43.0", "svelte-check": "^1.0.0", "svelte-markdown": "^0.1.4", - "svelte-preprocess": "^4.0.0", + "svelte-preprocess": "^4.9.5", "svelte-select": "^3.17.0", - "tslib": "^2.0.0", - "typescript": "^3.9.3", + "tslib": "^2.3.1", + "typescript": "^4.4.3", "uuid": "^3.4.0" } } \ No newline at end of file diff --git a/packages/web/src/appobj/AppObjectGroup.svelte b/packages/web/src/appobj/AppObjectGroup.svelte index 4b87aaa85..b8fdd6253 100644 --- a/packages/web/src/appobj/AppObjectGroup.svelte +++ b/packages/web/src/appobj/AppObjectGroup.svelte @@ -52,8 +52,9 @@ {/if} - {#each filtered as item} + {#each items as item} import _ from 'lodash'; + import { asyncFilter } from '../utility/common'; import AppObjectGroup from './AppObjectGroup.svelte'; import AppObjectListItem from './AppObjectListItem.svelte'; @@ -16,11 +17,36 @@ export let groupFunc = undefined; - $: filtered = list.filter(data => { - const matcher = module.createMatcher && module.createMatcher(data); - if (matcher && !matcher(filter)) return false; - return true; - }); + $: filtered = !groupFunc + ? list.filter(data => { + const matcher = module.createMatcher && module.createMatcher(data); + if (matcher && !matcher(filter)) return false; + return true; + }) + : null; + + $: childrenMatched = !groupFunc + ? list.filter(data => { + const matcher = module.createChildMatcher && module.createChildMatcher(data); + if (matcher && !matcher(filter)) return false; + return true; + }) + : null; + + + // let filtered = []; + + // $: { + // if (!groupFunc) { + // asyncFilter(list, async data => { + // const matcher = module.createMatcher && module.createMatcher(data); + // if (matcher && !(await matcher(filter))) return false; + // return true; + // }).then(res => { + // filtered = res; + // }); + // } + // } $: listGrouped = groupFunc ? _.compact( @@ -34,7 +60,6 @@ : null; $: groups = groupFunc ? _.groupBy(listGrouped, 'group') : null; - {#if groupFunc} @@ -49,11 +74,13 @@ {checkedObjectsStore} {groupFunc} {disableContextMenu} + {filter} /> {/each} {:else} - {#each filtered as data} + {#each list as data} {/each} {/if} diff --git a/packages/web/src/appobj/AppObjectListItem.svelte b/packages/web/src/appobj/AppObjectListItem.svelte index ecf1548b3..3f1623138 100644 --- a/packages/web/src/appobj/AppObjectListItem.svelte +++ b/packages/web/src/appobj/AppObjectListItem.svelte @@ -10,6 +10,8 @@ import { tick } from 'svelte'; import { plusExpandIcon } from '../icons/expandIcons'; + export let isHidden; + export let filter; export let module; export let data; export let subItemsComponent; @@ -18,6 +20,7 @@ export let expandIconFunc = plusExpandIcon; export let checkedObjectsStore = null; export let disableContextMenu = false; + export let isExpandedBySearch = false; let isExpanded = false; @@ -37,21 +40,23 @@ $: if (!expandable && isExpanded) isExpanded = false; - +{#if !isHidden} + -{#if isExpanded && subItemsComponent} -
- -
+ {#if (isExpanded || isExpandedBySearch) && subItemsComponent} +
+ +
+ {/if} {/if} diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts index 69b18b8c1..3c3dcca89 100644 --- a/packages/web/src/commands/stdCommands.ts +++ b/packages/web/src/commands/stdCommands.ts @@ -266,6 +266,15 @@ if (hasPermission('settings/change')) { }); } +if (electron) { + registerCommand({ + id: 'file.exit', + category: 'File', + name: 'Exit', + onClick: () => electron.remote.getCurrentWindow().close(), + }); +} + export function registerFileCommands({ idPrefix, category, diff --git a/packages/web/src/forms/SelectField.svelte b/packages/web/src/forms/SelectField.svelte index daa7dedf5..9c72e09a0 100644 --- a/packages/web/src/forms/SelectField.svelte +++ b/packages/web/src/forms/SelectField.svelte @@ -10,6 +10,7 @@ export let isNative = false; export let isMulti = false; export let notSelected = null; + export let defaultValue = ''; let listOpen = false; let isFocused = false; @@ -21,18 +22,19 @@ {#if isNative}