D & D CSV files

This commit is contained in:
Jan Prochazka 2021-03-13 20:28:06 +01:00
parent 834eeabd3f
commit 500c1c76ba
9 changed files with 322 additions and 8 deletions

View File

@ -37,6 +37,7 @@
},
"dependencies": {
"@mdi/font": "^5.9.55",
"file-selector": "^0.2.4",
"sirv-cli": "^1.0.0",
"svelte-select": "^3.17.0"
}

View File

@ -1,7 +1,14 @@
<script>
import WidgetContainer from './widgets/WidgetContainer.svelte';
import WidgetIconPanel from './widgets/WidgetIconPanel.svelte';
import { currentTheme, leftPanelWidth, selectedWidget, visibleCommandPalette, visibleToolbar } from './stores';
import {
currentTheme,
isFileDragActive,
leftPanelWidth,
selectedWidget,
visibleCommandPalette,
visibleToolbar,
} from './stores';
import TabsPanel from './widgets/TabsPanel.svelte';
import TabRegister from './TabRegister.svelte';
import CommandPalette from './commands/CommandPalette.svelte';
@ -11,9 +18,10 @@
import StatusBar from './widgets/StatusBar.svelte';
import ModalLayer from './modals/ModalLayer.svelte';
import DragAndDropFileTarget from './DragAndDropFileTarget.svelte';
import dragDropFileTarget from './utility/dragDropFileTarget';
</script>
<div class={`${$currentTheme} root`}>
<div class={`${$currentTheme} root`} use:dragDropFileTarget>
<div class="iconbar">
<WidgetIconPanel />
</div>
@ -50,7 +58,9 @@
{/if}
<CurrentDropDownMenu />
<ModalLayer />
<!-- <DragAndDropFileTarget /> -->
{#if $isFileDragActive}
<DragAndDropFileTarget />
{/if}
</div>
<style>

View File

@ -1,11 +1,48 @@
<script lang="ts">
import { writable } from 'svelte/store';
<script lang="ts" context="module">
async function addFileToSourceListDefault({ fileName, shortName, isDownload }, newSources, newValues) {
const sourceName = shortName;
newSources.push(sourceName);
newValues[`sourceFile_${sourceName}`] = {
fileName,
isDownload,
};
}
async function addFilesToSourceList(extensions, files, values, valuesStore, preferedStorageType, setPreviewSource) {
const newSources = [];
const newValues = {};
const storage = preferedStorageType || values.sourceStorageType;
for (const file of getAsArray(files)) {
const format = findFileFormat(extensions, storage);
if (format) {
await (format.addFileToSourceList || addFileToSourceListDefault)(file, newSources, newValues);
}
}
newValues['sourceList'] = [...(values.sourceList || []).filter(x => !newSources.includes(x)), ...newSources];
if (preferedStorageType && preferedStorageType != values.sourceStorageType) {
newValues['sourceStorageType'] = preferedStorageType;
}
valuesStore.set({
...values,
...newValues,
});
if (setPreviewSource && newSources.length == 1) {
setPreviewSource(newSources[0]);
}
}
</script>
<script lang="ts">
import { onMount } from 'svelte';
import { writable } from 'svelte/store';
import TableControl from '../elements/TableControl.svelte';
import { getFormContext } from '../forms/FormProviderCore.svelte';
import FontIcon from '../icons/FontIcon.svelte';
import { findFileFormat } from '../plugins/fileformats';
import { extensions } from '../stores';
import getAsArray from '../utility/getAsArray';
import { useConnectionInfo, useDatabaseInfo } from '../utility/metadataLoaders';
import { setUploadListener } from '../utility/uploadFiles';
import PreviewCheckBox from './PreviewCheckBox.svelte';
import SourceAction from './SourceAction.svelte';
import SourceName from './SourceName.svelte';
@ -13,13 +50,60 @@
import SourceTargetConfig from './SourceTargetConfig.svelte';
import TargetName from './TargetName.svelte';
export let uploadedFile = undefined;
export let openedFile = undefined;
const { values } = getFormContext();
$: targetDbinfo = useDatabaseInfo({ conid: $values.targetConnectionId, database: $values.targetDatabaseName });
$: sourceConnectionInfo = useConnectionInfo({ conid: $values.sourceConnectionId });
$: sourceList = $values.sourceList;
const previewSource = writable(null);
const handleUpload = file => {
addFilesToSourceList(
$extensions,
[
{
fileName: file.filePath,
shortName: file.shortName,
},
],
$values,
values,
!sourceList || sourceList.length == 0 ? file.storageType : null,
previewSource.set
);
// setFieldValue('sourceList', [...(sourceList || []), file.originalName]);
};
onMount(() => {
setUploadListener(handleUpload);
if (uploadedFile) {
handleUpload(uploadedFile);
}
if (openedFile) {
handleUpload(openedFile);
// addFilesToSourceList(
// $extensions,
// [
// {
// fileName: openedFile.filePath,
// shortName: openedFile.shortName,
// },
// ],
// $values,
// values,
// !sourceList || sourceList.length == 0 ? openedFile.storageType : null,
// previewSource.set
// );
}
return () => {
setUploadListener(null);
};
});
// engine={sourceEngine}
// {setPreviewSource}
</script>

View File

@ -120,7 +120,7 @@
<div class="wrapper">
<HorizontalSplitter initialValue="70%">
<div class="content" slot="1">
<ImportExportConfigurator />
<ImportExportConfigurator {uploadedFile} {openedFile} />
</div>
<svelte:fragment slot="2">

View File

@ -40,6 +40,7 @@ export const currentDropDownMenu = writable(null);
export const openedModals = writable([]);
export const nullStore = readable(null, () => {});
export const currentArchive = writable('default');
export const isFileDragActive = writable(false);
subscribeCssVariable(selectedWidget, x => (x ? 1 : 0), '--dim-visible-left-panel');
subscribeCssVariable(visibleToolbar, x => (x ? 1 : 0), '--dim-visible-toolbar');

View File

@ -0,0 +1,86 @@
import _ from 'lodash';
import { isFileDragActive } from '../stores';
import { fromEvent } from 'file-selector';
import uploadFiles from './uploadFiles';
function isEvtWithFiles(event) {
if (!event.dataTransfer) {
return !!event.target && !!event.target.files;
}
// https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/types
// https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Recommended_drag_types#file
return Array.prototype.some.call(
event.dataTransfer.types,
type => type === 'Files' || type === 'application/x-moz-file'
);
}
export default function dragDropFileTarget(node, items) {
let dragTargetsRef = [];
function handleDragEnter(event) {
event.preventDefault();
event.stopPropagation();
dragTargetsRef = [...dragTargetsRef, event.target];
if (isEvtWithFiles(event)) {
isFileDragActive.set(true);
}
return false;
}
function handleDragOver(event) {
event.preventDefault();
event.stopPropagation();
if (event.dataTransfer) {
try {
event.dataTransfer.dropEffect = 'copy';
} catch {}
}
}
function handleDragLeave(event) {
event.preventDefault();
event.stopPropagation();
// Only deactivate once the dropzone and all children have been left
const targets = dragTargetsRef.filter(target => node && node.contains(target));
// Make sure to remove a target present multiple times only once
// (Firefox may fire dragenter/dragleave multiple times on the same element)
const targetIdx = targets.indexOf(event.target);
if (targetIdx !== -1) {
targets.splice(targetIdx, 1);
}
dragTargetsRef = targets;
if (targets.length > 0) {
return;
}
isFileDragActive.set(false);
}
async function handleDrop(event) {
event.preventDefault();
event.stopPropagation();
isFileDragActive.set(false);
if (isEvtWithFiles(event)) {
const files = await fromEvent(event);
uploadFiles(files);
}
}
node.addEventListener('dragenter', handleDragEnter);
node.addEventListener('dragover', handleDragOver);
node.addEventListener('dragleave', handleDragLeave);
node.addEventListener('drop', handleDrop);
return {
destroy() {
node.removeEventListener('dragenter', handleDragEnter);
node.removeEventListener('dragover', handleDragOver);
node.removeEventListener('dragleave', handleDragLeave);
node.removeEventListener('drop', handleDrop);
},
};
}

View File

@ -0,0 +1,47 @@
import { showModal } from '../modals/modalTools';
import newQuery from '../query/newQuery';
import ImportExportModal from '../modals/ImportExportModal.svelte';
export function canOpenByElectron(file, extensions) {
if (!file) return false;
const nameLower = file.toLowerCase();
if (nameLower.endsWith('.sql')) return true;
for (const format of extensions.fileFormats) {
if (nameLower.endsWith(`.${format.extension}`)) return true;
}
return false;
}
export function openElectronFileCore(filePath, extensions) {
const nameLower = filePath.toLowerCase();
const path = window.require('path');
const fs = window.require('fs');
const parsed = path.parse(filePath);
if (nameLower.endsWith('.sql')) {
const data = fs.readFileSync(filePath, { encoding: 'utf-8' });
newQuery({
title: parsed.name,
initialData: data,
// @ts-ignore
savedFilePath: filePath,
savedFormat: 'text',
});
}
for (const format of extensions.fileFormats) {
if (nameLower.endsWith(`.${format.extension}`)) {
showModal(ImportExportModal, {
openedFile: {
filePath,
storageType: format.storageType,
shortName: parsed.name,
},
importToArchive: true,
initialValues: {
sourceStorageType: format.storageType,
},
});
}
}
}

View File

@ -0,0 +1,78 @@
import { extensions } from '../stores';
import { get } from 'svelte/store';
import { canOpenByElectron, openElectronFileCore } from './openElectronFile';
import getElectron from './getElectron';
import resolveApi from './resolveApi';
import { findFileFormat } from '../plugins/fileformats';
import { showModal } from '../modals/modalTools';
import ImportExportModal from '../modals/ImportExportModal.svelte';
let uploadListener;
export function setUploadListener(value) {
uploadListener = value;
}
export default function uploadFiles(files) {
const ext = get(extensions);
const electron = getElectron();
files.forEach(async file => {
if (parseInt(file.size, 10) >= 4 * 1024 * 1024) {
// to big file
return;
}
console.log('FILE', file);
if (electron && canOpenByElectron(file.path, ext)) {
openElectronFileCore(file.path, ext);
return;
}
const formData = new FormData();
formData.append('data', file);
const fetchOptions = {
method: 'POST',
body: formData,
};
const apiBase = resolveApi();
const resp = await fetch(`${apiBase}/uploads/upload`, fetchOptions);
const fileData = await resp.json();
fileData.shortName = file.name;
for (const format of ext.fileFormats) {
if (file.name.endsWith('.' + format.extension)) {
fileData.shortName = file.name.slice(0, -format.extension.length - 1);
fileData.storageType = format.storageType;
}
}
if (uploadListener) {
uploadListener(fileData);
} else {
if (findFileFormat(ext, fileData.storageType)) {
showModal(ImportExportModal, {
uploadedFile: fileData,
importToArchive: true,
initialValues: {
sourceStorageType: fileData.storageType,
},
});
}
}
// const reader = new FileReader();
// reader.onabort = () => console.log('file reading was aborted');
// reader.onerror = () => console.log('file reading has failed');
// reader.onload = () => {
// // Do whatever you want with the file contents
// const binaryStr = reader.result;
// console.log(binaryStr);
// };
// reader.readAsArrayBuffer(file);
});
}

View File

@ -2789,6 +2789,13 @@ file-entry-cache@^5.0.1:
dependencies:
flat-cache "^2.0.1"
file-selector@^0.2.4:
version "0.2.4"
resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.2.4.tgz#7b98286f9dbb9925f420130ea5ed0a69238d4d80"
integrity sha512-ZDsQNbrv6qRi1YTDOEWzf5J2KjZ9KMI1Q2SGeTkCJmNNW25Jg4TW4UMcmoqcg4WrAyKRcpBXdbWRxkfrOzVRbA==
dependencies:
tslib "^2.0.3"
file-uri-to-path@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
@ -7224,7 +7231,7 @@ tslib@^1.9.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
tslib@^2.0.0:
tslib@^2.0.0, tslib@^2.0.3:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==