show cloud content

This commit is contained in:
SPRINX0\prochazka
2025-05-21 17:09:16 +02:00
parent b553a81d47
commit 590a4ae476
9 changed files with 96 additions and 10 deletions

View File

@@ -4,8 +4,13 @@ const {
refreshPublicFiles, refreshPublicFiles,
callCloudApiGet, callCloudApiGet,
callCloudApiPost, callCloudApiPost,
getCloudFolderEncryptor,
} = require('../utility/cloudIntf'); } = require('../utility/cloudIntf');
const connections = require('./connections');
const socket = require('../utility/socket'); const socket = require('../utility/socket');
const { decryptConnection, recryptConnection, getInternalEncryptor } = require('../utility/crypting');
const { getConnectionLabel, getLogger, extractErrorLogData } = require('dbgate-tools');
const logger = getLogger('cloud');
module.exports = { module.exports = {
publicFiles_meta: true, publicFiles_meta: true,
@@ -30,9 +35,14 @@ module.exports = {
contentList_meta: true, contentList_meta: true,
async contentList() { async contentList() {
const resp = callCloudApiGet('content-list'); try {
console.log('contentList', resp); const resp = await callCloudApiGet('content-list');
return resp; return resp;
} catch (err) {
logger.error(extractErrorLogData(err), 'Error getting cloud content list');
return [];
}
}, },
getContent_meta: true, getContent_meta: true,
@@ -79,4 +89,21 @@ module.exports = {
status: 'ok', status: 'ok',
}; };
}, },
moveConnectionCloud_meta: true,
async moveConnectionCloud({ conid, folid }) {
const conn = await connections.getCore({ conid });
const folderEncryptor = getCloudFolderEncryptor(folid);
const recryptedConn = recryptConnection(conn, getInternalEncryptor(), folderEncryptor);
await this.putContent({
folid,
cntid: conid,
content: JSON.stringify(recryptedConn),
name: getConnectionLabel(conn),
type: 'connection',
});
return {
status: 'ok',
};
},
}; };

View File

@@ -10,6 +10,7 @@ const connections = require('../controllers/connections');
const { isProApp } = require('./checkLicense'); const { isProApp } = require('./checkLicense');
const socket = require('./socket'); const socket = require('./socket');
const config = require('../controllers/config'); const config = require('../controllers/config');
const simpleEncryptor = require('simple-encryptor');
const logger = getLogger('cloudIntf'); const logger = getLogger('cloudIntf');
@@ -239,6 +240,14 @@ async function callCloudApiPost(endpoint, body) {
return resp.data; return resp.data;
} }
async function getCloudFolderEncryptor(folid) {
const { encryptionKey } = await callCloudApiGet(`folder-key/${folid}`);
if (!encryptionKey) {
throw new Error('No encryption key');
}
return simpleEncryptor.createEncryptor(encryptionKey);
}
module.exports = { module.exports = {
createDbGateIdentitySession, createDbGateIdentitySession,
startCloudTokenChecking, startCloudTokenChecking,
@@ -248,4 +257,5 @@ module.exports = {
refreshPublicFiles, refreshPublicFiles,
callCloudApiGet, callCloudApiGet,
callCloudApiPost, callCloudApiPost,
getCloudFolderEncryptor,
}; };

View File

@@ -0,0 +1,30 @@
<script lang="ts" context="module">
import AppObjectCore from './AppObjectCore.svelte';
export const extractKey = data => data.cntid;
export const createMatcher =
filter =>
({ name }) =>
filterName(filter, name);
</script>
<script lang="ts">
import { filterName } from 'dbgate-tools';
export let data;
function createMenu() {
return [];
}
</script>
<AppObjectCore {...$$restProps} {data} icon={'img connection'} title={data.name} menu={createMenu}></AppObjectCore>
<style>
.info {
margin-left: 30px;
margin-right: 5px;
color: var(--theme-font-3);
white-space: nowrap;
}
</style>

View File

@@ -108,6 +108,7 @@
import _ from 'lodash'; import _ from 'lodash';
import AppObjectCore from './AppObjectCore.svelte'; import AppObjectCore from './AppObjectCore.svelte';
import { import {
cloudSigninToken,
currentDatabase, currentDatabase,
DEFAULT_CONNECTION_SEARCH_SETTINGS, DEFAULT_CONNECTION_SEARCH_SETTINGS,
expandedConnections, expandedConnections,
@@ -332,6 +333,17 @@
text: _t('connection.duplicate', { defaultMessage: 'Duplicate' }), text: _t('connection.duplicate', { defaultMessage: 'Duplicate' }),
onClick: handleDuplicate, onClick: handleDuplicate,
}, },
!$openedConnections.includes(data._id) &&
$cloudSigninToken &&
passProps?.cloudContentList?.length > 0 && {
text: _t('connection.moveToCloudFolder', { defaultMessage: 'Move to cloud folder' }),
submenu: passProps?.cloudContentList?.map(fld => ({
text: fld.name,
onClick: () => {
apiCall('cloud/move-connection-cloud', { conid: data._id, folid: fld.folid });
},
})),
},
], ],
{ divider: true }, { divider: true },
!data.singleDatabase && [ !data.singleDatabase && [

View File

@@ -183,7 +183,6 @@ export const focusedConnectionOrDatabase = writable<{ conid: string; database?:
export const focusedTreeDbKey = writable<{ key: string; root: string; type: string; text: string }>(null); export const focusedTreeDbKey = writable<{ key: string; root: string; type: string; text: string }>(null);
export const cloudSigninToken = writableSettingsValue(null, 'cloudSigninToken'); export const cloudSigninToken = writableSettingsValue(null, 'cloudSigninToken');
export const cloudEncryptKeysByFolder = writableSettingsValue({}, 'cloudEncryptKeysByFolder');
// export const cloudSigninToken = getElectron() // export const cloudSigninToken = getElectron()
// ? writableSettingsValue(null, 'cloudSigninToken') // ? writableSettingsValue(null, 'cloudSigninToken')

View File

@@ -5,7 +5,8 @@
import WidgetColumnBarItem from './WidgetColumnBarItem.svelte'; import WidgetColumnBarItem from './WidgetColumnBarItem.svelte';
import AppObjectList from '../appobj/AppObjectList.svelte'; import AppObjectList from '../appobj/AppObjectList.svelte';
import * as cloudFileAppObject from '../appobj/CloudFileAppObject.svelte'; import * as publicCloudFileAppObject from '../appobj/PublicCloudFileAppObject.svelte';
import * as cloudContentAppObject from '../appobj/CloudContentAppObject.svelte';
import { useCloudContentList, usePublicCloudFiles } from '../utility/metadataLoaders'; import { useCloudContentList, usePublicCloudFiles } from '../utility/metadataLoaders';
import { _t } from '../translations'; import { _t } from '../translations';
@@ -26,7 +27,7 @@
$: cloudContentList = useCloudContentList(); $: cloudContentList = useCloudContentList();
$: emptyCloudContent = ($cloudContentList || []).filter(x => !x.items?.length).map(x => x.folid); $: emptyCloudContent = ($cloudContentList || []).filter(x => !x.items?.length).map(x => x.folid);
$: cloudContentFlat = ($cloudContentList || []).flatMap(fld => fld.items ?? []).map(x => x.folid); $: cloudContentFlat = ($cloudContentList || []).flatMap(fld => fld.items ?? []);
$: contentGroupTitleMap = _.fromPairs(($cloudContentList || []).map(x => [x.folid, x.name])); $: contentGroupTitleMap = _.fromPairs(($cloudContentList || []).map(x => [x.folid, x.name]));
async function handleRefreshPublic() { async function handleRefreshPublic() {
@@ -61,7 +62,7 @@
<AppObjectList <AppObjectList
list={cloudContentFlat || []} list={cloudContentFlat || []}
module={cloudFileAppObject} module={cloudContentAppObject}
emptyGroupNames={emptyCloudContent} emptyGroupNames={emptyCloudContent}
groupFunc={data => data.folid} groupFunc={data => data.folid}
mapGroupTitle={folid => contentGroupTitleMap[folid]} mapGroupTitle={folid => contentGroupTitleMap[folid]}
@@ -86,7 +87,7 @@
<AppObjectList <AppObjectList
list={$publicFiles || []} list={$publicFiles || []}
module={cloudFileAppObject} module={publicCloudFileAppObject}
groupFunc={data => data.folder || undefined} groupFunc={data => data.folder || undefined}
filter={publicFilter} filter={publicFilter}
/> />

View File

@@ -351,6 +351,7 @@
isExpandable={data => $openedConnections.includes(data._id) && !data.singleDatabase} isExpandable={data => $openedConnections.includes(data._id) && !data.singleDatabase}
{filter} {filter}
passProps={{ passProps={{
...passProps,
connectionColorFactory: $connectionColorFactory, connectionColorFactory: $connectionColorFactory,
showPinnedInsteadOfUnpin: true, showPinnedInsteadOfUnpin: true,
searchSettings: $connectionAppObjectSearchSettings, searchSettings: $connectionAppObjectSearchSettings,

View File

@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { findEngineDriver } from 'dbgate-tools'; import { findEngineDriver } from 'dbgate-tools';
import { currentDatabase, extensions, pinnedDatabases, pinnedTables } from '../stores'; import { currentDatabase, extensions, pinnedDatabases, pinnedTables } from '../stores';
import { useConfig, useConnectionInfo } from '../utility/metadataLoaders'; import { useCloudContentList, useConfig, useConnectionInfo } from '../utility/metadataLoaders';
import ConnectionList from './ConnectionList.svelte'; import ConnectionList from './ConnectionList.svelte';
import PinnedObjectsList from './PinnedObjectsList.svelte'; import PinnedObjectsList from './PinnedObjectsList.svelte';
@@ -26,6 +26,7 @@
$: config = useConfig(); $: config = useConfig();
$: singleDatabase = $currentDatabase?.connection?.singleDatabase; $: singleDatabase = $currentDatabase?.connection?.singleDatabase;
$: database = $currentDatabase?.name; $: database = $currentDatabase?.name;
$: cloudContentList = useCloudContentList();
</script> </script>
<WidgetColumnBar {hidden}> <WidgetColumnBar {hidden}>
@@ -45,7 +46,12 @@
height="35%" height="35%"
storageName="connectionsWidget" storageName="connectionsWidget"
> >
<ConnectionList passProps={{ onFocusSqlObjectList: () => domSqlObjectList.focus() }} /> <ConnectionList
passProps={{
onFocusSqlObjectList: () => domSqlObjectList.focus(),
cloudContentList: $cloudContentList,
}}
/>
</WidgetColumnBarItem> </WidgetColumnBarItem>
{/if} {/if}
<WidgetColumnBarItem <WidgetColumnBarItem