cloud files WIP

This commit is contained in:
SPRINX0\prochazka
2025-05-28 08:25:10 +02:00
parent d3a5df0007
commit 741b942dea
8 changed files with 109 additions and 54 deletions

View File

@@ -205,6 +205,11 @@ module.exports = {
return resp; return resp;
}, },
// saveFile_meta: true, saveFile_meta: true,
// async saveFile({folid, file, data, folder, format}) async saveFile({ folid, cntid, fileName, data, contentFolder, format }) {
const resp = await putCloudContent(folid, cntid, data, fileName, 'file', contentFolder, format);
socket.emitChanged('cloud-content-changed');
socket.emit('cloud-content-updated');
return resp;
},
}; };

View File

@@ -284,9 +284,13 @@ async function getCloudContent(folid, cntid) {
const encryptor = simpleEncryptor.createEncryptor(signinHolder.encryptionKey); const encryptor = simpleEncryptor.createEncryptor(signinHolder.encryptionKey);
const { content, name, type, apiErrorMessage } = await callCloudApiGet(`content/${folid}/${cntid}`, signinHolder, { const { content, name, type, contentFolder, contentType, apiErrorMessage } = await callCloudApiGet(
'x-kehid': signinHolder.kehid, `content/${folid}/${cntid}`,
}); signinHolder,
{
'x-kehid': signinHolder.kehid,
}
);
if (apiErrorMessage) { if (apiErrorMessage) {
return { apiErrorMessage }; return { apiErrorMessage };
@@ -296,10 +300,16 @@ async function getCloudContent(folid, cntid) {
content: encryptor.decrypt(content), content: encryptor.decrypt(content),
name, name,
type, type,
contentFolder,
contentType,
}; };
} }
async function putCloudContent(folid, cntid, content, name, type) { /**
*
* @returns Promise<{ cntid: string } | { apiErrorMessage: string }>
*/
async function putCloudContent(folid, cntid, content, name, type, contentFolder = null, contentType = null) {
const signinHolder = await getCloudSigninHolder(); const signinHolder = await getCloudSigninHolder();
if (!signinHolder) { if (!signinHolder) {
throw new Error('No signed in'); throw new Error('No signed in');
@@ -316,6 +326,8 @@ async function putCloudContent(folid, cntid, content, name, type) {
type, type,
kehid: signinHolder.kehid, kehid: signinHolder.kehid,
content: encryptor.encrypt(content), content: encryptor.encrypt(content),
contentFolder,
contentType,
}, },
signinHolder signinHolder
); );

View File

@@ -17,6 +17,7 @@
import openNewTab from '../utility/openNewTab'; import openNewTab from '../utility/openNewTab';
import { showModal } from '../modals/modalTools'; import { showModal } from '../modals/modalTools';
import ConfirmModal from '../modals/ConfirmModal.svelte'; import ConfirmModal from '../modals/ConfirmModal.svelte';
import SavedFileAppObject from './SavedFileAppObject.svelte';
export let data; export let data;
export let passProps; export let passProps;
@@ -102,6 +103,19 @@
on:dblclick on:dblclick
on:expand on:expand
/> />
{:else if data.type == 'file'}
<SavedFileAppObject
{...$$restProps}
{passProps}
data={{
file: data.name,
folder: data.contentFolder,
folid: data.folid,
cntid: data.cntid,
}}
on:dblclick
on:expand
/>
{:else} {:else}
<AppObjectCore <AppObjectCore
{...$$restProps} {...$$restProps}

View File

@@ -247,10 +247,19 @@
}; };
async function openTab() { async function openTab() {
const resp = await apiCall('files/load', { folder, file: data.file, format: handler.format }); let dataContent;
if (data.folid && data.cntid) {
const resp = await apiCall('cloud/get-content', {
folid: data.folid,
cntid: data.cntid,
});
dataContent = resp.content;
} else {
dataContent = await apiCall('files/load', { folder, file: data.file, format: handler.format });
}
const connProps: any = {};
let tooltip = undefined; let tooltip = undefined;
const connProps: any = {};
if (handler.currentConnection) { if (handler.currentConnection) {
const connection = _.get($currentDatabase, 'connection') || {}; const connection = _.get($currentDatabase, 'connection') || {};
@@ -270,10 +279,12 @@
savedFile: data.file, savedFile: data.file,
savedFolder: handler.folder, savedFolder: handler.folder,
savedFormat: handler.format, savedFormat: handler.format,
savedCloudFolderId: data.folid,
savedCloudContentId: data.cntid,
...connProps, ...connProps,
}, },
}, },
{ editor: resp } { editor: dataContent }
); );
} }
</script> </script>

View File

@@ -6,14 +6,22 @@
export let name; export let name;
export let requiredRoleVariants = ['read', 'write', 'admin']; export let requiredRoleVariants = ['read', 'write', 'admin'];
export let prependFolders = [];
const cloudContentList = useCloudContentList(); const cloudContentList = useCloudContentList();
$: folderOptions = ($cloudContentList || []) $: folderOptions = [
.filter(folder => requiredRoleVariants.find(role => folder.role == role)) ...prependFolders.map(folder => ({
.map(folder => ({
value: folder.folid, value: folder.folid,
label: folder.name, label: folder.name,
})); })),
...($cloudContentList || [])
.filter(folder => requiredRoleVariants.find(role => folder.role == role))
.map(folder => ({
value: folder.folid,
label: folder.name,
})),
];
</script> </script>
<FormSelectField {...$$props} options={folderOptions} /> <FormSelectField {...$$props} options={folderOptions} />

View File

@@ -23,20 +23,42 @@
export let filePath; export let filePath;
export let onSave = undefined; export let onSave = undefined;
const values = writable({ name }); const values = writable({ name, cloudFolder: '__local' });
const electron = getElectron(); const electron = getElectron();
const handleSubmit = async e => { const handleSubmit = async e => {
const { name } = e.detail; const { name, cloudFolder } = e.detail;
await apiCall('files/save', { folder, file: name, data, format }); if (cloudFolder === '__local') {
closeCurrentModal(); await apiCall('files/save', { folder, file: name, data, format });
if (onSave) { closeCurrentModal();
onSave(name, { if (onSave) {
savedFile: name, onSave(name, {
savedFolder: folder, savedFile: name,
savedFilePath: null, savedFolder: folder,
savedFilePath: null,
});
}
} else {
const resp = await apiCall('cloud/save-file', {
folid: cloudFolder,
fileName: name,
data,
contentFolder: folder,
format,
}); });
if (resp.cntid) {
closeCurrentModal();
if (onSave) {
onSave(name, {
savedFile: name,
savedFolder: folder,
savedFilePath: null,
savedCloudFolderId: cloudFolder,
savedCloudContentId: resp.cntid,
});
}
}
} }
}; };
@@ -56,28 +78,6 @@
}); });
} }
}; };
const handleSaveToCloud = async folid => {
const resp = await apiCall('cloud/save-file', {
folid,
fileName: $values.name,
data,
contentFolder: folder,
format,
});
if (resp.cntid) {
closeCurrentModal();
if (onSave) {
onSave(name, {
savedFile: name,
savedFolder: folder,
savedFilePath: null,
savedCloudFolderId: folid,
savedCloudContentId: resp.cntid,
});
}
}
};
</script> </script>
<FormProviderCore {values}> <FormProviderCore {values}>
@@ -86,10 +86,16 @@
<FormTextField label="File name" name="name" focused /> <FormTextField label="File name" name="name" focused />
{#if $cloudSigninTokenHolder} {#if $cloudSigninTokenHolder}
<FormCloudFolderSelect <FormCloudFolderSelect
label="Choose local or cloud folder" label="Choose cloud folder"
name="cloudFolder" name="cloudFolder"
isNative isNative
requiredRoleVariants={['write', 'admin']} requiredRoleVariants={['write', 'admin']}
prependFolders={[
{
folid: '__local',
name: "Local folder (don't store on cloud)",
},
]}
/> />
{/if} {/if}

View File

@@ -34,8 +34,7 @@
import ConfirmModal from '../modals/ConfirmModal.svelte'; import ConfirmModal from '../modals/ConfirmModal.svelte';
import { showSnackbarInfo } from '../utility/snackbar'; import { showSnackbarInfo } from '../utility/snackbar';
let publicFilter = ''; let filter = '';
let cloudFilter = '';
let domSqlObjectList = null; let domSqlObjectList = null;
const cloudContentList = useCloudContentList(); const cloudContentList = useCloudContentList();
@@ -205,8 +204,8 @@
skip={!$cloudSigninTokenHolder} skip={!$cloudSigninTokenHolder}
> >
<SearchBoxWrapper> <SearchBoxWrapper>
<SearchInput placeholder="Search cloud connections and files" bind:value={cloudFilter} /> <SearchInput placeholder="Search cloud connections and files" bind:value={filter} />
<CloseSearchButton bind:filter={cloudFilter} /> <CloseSearchButton bind:filter />
<DropDownButton icon="icon plus-thick" menu={createAddMenu} /> <DropDownButton icon="icon plus-thick" menu={createAddMenu} />
<InlineButton <InlineButton
on:click={handleRefreshContent} on:click={handleRefreshContent}
@@ -223,7 +222,7 @@
emptyGroupNames={emptyCloudContent} emptyGroupNames={emptyCloudContent}
groupFunc={data => data.folid} groupFunc={data => data.folid}
mapGroupTitle={folid => `${contentGroupMap[folid]?.name} - ${contentGroupMap[folid]?.role}`} mapGroupTitle={folid => `${contentGroupMap[folid]?.name} - ${contentGroupMap[folid]?.role}`}
filter={publicFilter} {filter}
subItemsComponent={() => SubCloudItemsList} subItemsComponent={() => SubCloudItemsList}
expandIconFunc={plusExpandIcon} expandIconFunc={plusExpandIcon}
isExpandable={data => isExpandable={data =>

View File

@@ -18,7 +18,7 @@
import FontIcon from '../icons/FontIcon.svelte'; import FontIcon from '../icons/FontIcon.svelte';
import { apiCall } from '../utility/api'; import { apiCall } from '../utility/api';
import _ from 'lodash'; import _ from 'lodash';
let publicFilter = ''; let filter = '';
const publicFiles = usePublicCloudFiles(); const publicFiles = usePublicCloudFiles();
@@ -31,8 +31,8 @@
<WidgetColumnBarItem title="Public Knowledge Base" name="publicCloud" storageName="publicCloudItems"> <WidgetColumnBarItem title="Public Knowledge Base" name="publicCloud" storageName="publicCloudItems">
<WidgetsInnerContainer> <WidgetsInnerContainer>
<SearchBoxWrapper> <SearchBoxWrapper>
<SearchInput placeholder="Search public files" bind:value={publicFilter} /> <SearchInput placeholder="Search public files" bind:value={filter} />
<CloseSearchButton bind:filter={publicFilter} /> <CloseSearchButton bind:filter />
<InlineButton <InlineButton
on:click={handleRefreshPublic} on:click={handleRefreshPublic}
title="Refresh files" title="Refresh files"
@@ -46,7 +46,7 @@
list={$publicFiles || []} list={$publicFiles || []}
module={publicCloudFileAppObject} module={publicCloudFileAppObject}
groupFunc={data => data.folder || undefined} groupFunc={data => data.folder || undefined}
filter={publicFilter} {filter}
/> />
</WidgetsInnerContainer> </WidgetsInnerContainer>
</WidgetColumnBarItem> </WidgetColumnBarItem>