mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-926: Migrate upload directive into import page controller since they're so tangled up together to make it not worth seperating them.
This commit is contained in:
@@ -25,9 +25,14 @@
|
||||
angular.module('import').controller('importConnectionsController', ['$scope', '$injector',
|
||||
function importConnectionsController($scope, $injector) {
|
||||
|
||||
// The file types supported for connection import
|
||||
const LEGAL_FILE_TYPES = ['csv', 'json', 'yaml'];
|
||||
|
||||
// Required services
|
||||
const $document = $injector.get('$document');
|
||||
const $q = $injector.get('$q');
|
||||
const $routeParams = $injector.get('$routeParams');
|
||||
const $timeout = $injector.get('$timeout');
|
||||
const connectionParseService = $injector.get('connectionParseService');
|
||||
const connectionService = $injector.get('connectionService');
|
||||
const permissionService = $injector.get('permissionService');
|
||||
@@ -112,11 +117,13 @@ angular.module('import').controller('importConnectionsController', ['$scope', '$
|
||||
$scope.aborted = false;
|
||||
$scope.dataReady = false;
|
||||
$scope.processing = false;
|
||||
$scope.error = null;
|
||||
$scope.fileData = null;
|
||||
$scope.mimeType = null;
|
||||
$scope.fileReader = null;
|
||||
$scope.parseResult = null;
|
||||
$scope.patchFailure = null;
|
||||
$scope.fileName = null;
|
||||
|
||||
// Broadcast an event to clear the file upload UI
|
||||
$scope.$broadcast('clearFile');
|
||||
@@ -410,7 +417,6 @@ angular.module('import').controller('importConnectionsController', ['$scope', '$
|
||||
resetUploadState();
|
||||
|
||||
// Set the error for display
|
||||
console.error(error);
|
||||
$scope.error = error;
|
||||
|
||||
};
|
||||
@@ -462,8 +468,6 @@ angular.module('import').controller('importConnectionsController', ['$scope', '$
|
||||
}
|
||||
|
||||
// Make the call to process the data into a series of patches
|
||||
// TODO: Check if there's errors, and if so, display those rather than
|
||||
// just YOLOing a create call
|
||||
processDataCallback(data)
|
||||
|
||||
// Send the data off to be imported if parsing is successful
|
||||
@@ -537,7 +541,30 @@ angular.module('import').controller('importConnectionsController', ['$scope', '$
|
||||
* @argument {File} file
|
||||
* The file to upload onto the scope for further processing.
|
||||
*/
|
||||
$scope.handleFile = function(file) {
|
||||
const handleFile = file => {
|
||||
|
||||
// Clear any error from a previous attempted file upload
|
||||
clearError();
|
||||
|
||||
// The MIME type of the provided file
|
||||
const mimeType = file.type;
|
||||
|
||||
// Check if the mimetype ends with one of the supported types,
|
||||
// e.g. "application/json" or "text/csv"
|
||||
if (_.every(LEGAL_FILE_TYPES.map(
|
||||
type => !mimeType.endsWith(type)))) {
|
||||
|
||||
// If the provided file is not one of the supported types,
|
||||
// display an error and abort processing
|
||||
handleError(new ParseError({
|
||||
message: "Invalid file type: " + type,
|
||||
key: 'IMPORT.ERROR_INVALID_FILE_TYPE',
|
||||
variables: { TYPE: mimeType }
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.fileName = file.name;
|
||||
|
||||
// Clear any error message from the previous upload attempt
|
||||
clearError();
|
||||
@@ -578,5 +605,148 @@ angular.module('import').controller('importConnectionsController', ['$scope', '$
|
||||
// Read all the data into memory
|
||||
$scope.fileReader.readAsBinaryString(file);
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether a drag/drop operation is currently in progress (the user has
|
||||
* dragged a file over the Guacamole connection but has not yet
|
||||
* dropped it).
|
||||
*
|
||||
* @type boolean
|
||||
*/
|
||||
$scope.dropPending = false;
|
||||
|
||||
/**
|
||||
* The name of the file that's currently being uploaded, or has yet to
|
||||
* be imported, if any.
|
||||
*/
|
||||
$scope.fileName = null;
|
||||
|
||||
/**
|
||||
* The container for the file upload UI.
|
||||
*
|
||||
* @type Element
|
||||
*
|
||||
*/
|
||||
const uploadContainer = angular.element(
|
||||
$document.find('.file-upload-container'));
|
||||
|
||||
/**
|
||||
* The location where files can be dragged-and-dropped to.
|
||||
*
|
||||
* @type Element
|
||||
*/
|
||||
const dropTarget = uploadContainer.find('.drop-target');
|
||||
|
||||
/**
|
||||
* Displays a visual indication that dropping the file currently
|
||||
* being dragged is possible. Further propagation and default behavior
|
||||
* of the given event is automatically prevented.
|
||||
*
|
||||
* @param {Event} e
|
||||
* The event related to the in-progress drag/drop operation.
|
||||
*/
|
||||
const notifyDragStart = function notifyDragStart(e) {
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
$scope.$apply(() => {
|
||||
$scope.dropPending = true;
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the visual indication that dropping the file currently
|
||||
* being dragged is possible. Further propagation and default behavior
|
||||
* of the given event is automatically prevented.
|
||||
*
|
||||
* @param {Event} e
|
||||
* The event related to the end of the former drag/drop operation.
|
||||
*/
|
||||
const notifyDragEnd = function notifyDragEnd(e) {
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
$scope.$apply(() => {
|
||||
$scope.dropPending = false;
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// Add listeners to the drop target to ensure that the visual state
|
||||
// stays up to date
|
||||
dropTarget.on('dragenter', notifyDragStart);
|
||||
dropTarget.on('dragover', notifyDragStart);
|
||||
dropTarget.on('dragleave', notifyDragEnd);
|
||||
|
||||
/**
|
||||
* Drop target event listener that will be invoked if the user drops
|
||||
* anything onto the drop target. If a valid file is provided, the
|
||||
* onFile callback provided to this directive will be called; otherwise
|
||||
* an error will be displayed, if appropriate.
|
||||
*
|
||||
* @param {Event} e
|
||||
* The drop event that triggered this handler.
|
||||
*/
|
||||
dropTarget.on('drop', e => {
|
||||
|
||||
notifyDragEnd(e);
|
||||
|
||||
const files = e.originalEvent.dataTransfer.files;
|
||||
|
||||
// Ignore any non-files that are dragged into the drop area
|
||||
if (files.length < 1)
|
||||
return;
|
||||
|
||||
if (files.length >= 2) {
|
||||
|
||||
// If more than one file was provided, print an error explaining
|
||||
// that only a single file is allowed and abort processing
|
||||
handleError(new ParseError({
|
||||
message: 'Only a single file may be imported at once',
|
||||
key: 'IMPORT.ERROR_FILE_SINGLE_ONLY'
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
handleFile(files[0]);
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* The hidden file input used to create a file browser.
|
||||
*
|
||||
* @type Element
|
||||
*/
|
||||
const fileUploadInput = uploadContainer.find('.file-upload-input');
|
||||
|
||||
/**
|
||||
* A function that will click on the hidden file input to open a file
|
||||
* browser to allow the user to select a file for upload.
|
||||
*/
|
||||
$scope.openFileBrowser = () =>
|
||||
$timeout(() => fileUploadInput.click(), 0, false);
|
||||
|
||||
/**
|
||||
* A handler that will be invoked when a user selectes a file in the
|
||||
* file browser. After some error checking, the file will be passed to
|
||||
* the onFile callback provided to this directive.
|
||||
*
|
||||
* @param {Event} e
|
||||
* The event that was triggered when the user selected a file in
|
||||
* their file browser.
|
||||
*/
|
||||
fileUploadInput.on('change', e => {
|
||||
|
||||
// Process the uploaded file
|
||||
handleFile(e.target.files[0]);
|
||||
|
||||
// Clear the value to ensure that the change event will be fired
|
||||
// if the user selects the same file again
|
||||
fileUploadInput.value = null;
|
||||
|
||||
});
|
||||
|
||||
}]);
|
||||
|
@@ -1,252 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/* global _ */
|
||||
|
||||
/**
|
||||
* All legal import file types. Any file not belonging to one of these types
|
||||
* must be rejected.
|
||||
*/
|
||||
const LEGAL_FILE_TYPES = ["csv", "json", "yaml"];
|
||||
|
||||
/**
|
||||
* A directive that allows for file upload, either through drag-and-drop or
|
||||
* a file browser.
|
||||
*/
|
||||
angular.module('import').directive('connectionImportFileUpload', [
|
||||
function connectionImportFileUpload() {
|
||||
|
||||
const directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'app/import/templates/connectionImportFileUpload.html',
|
||||
scope: {
|
||||
|
||||
/**
|
||||
* The function to invoke when a file is provided to the file upload
|
||||
* UI, either by dragging and dropping, or by navigating using the
|
||||
* file browser. The function will be called with 2 arguments - the
|
||||
* mime type, and the raw string contents of the file.
|
||||
*
|
||||
* @type function
|
||||
*/
|
||||
onFile : '&',
|
||||
}
|
||||
};
|
||||
|
||||
directive.controller = ['$scope', '$injector', '$element',
|
||||
function fileUploadController($scope, $injector, $element) {
|
||||
|
||||
// Required services
|
||||
const $timeout = $injector.get('$timeout');
|
||||
|
||||
/**
|
||||
* Whether a drag/drop operation is currently in progress (the user has
|
||||
* dragged a file over the Guacamole connection but has not yet
|
||||
* dropped it).
|
||||
*
|
||||
* @type boolean
|
||||
*/
|
||||
$scope.dropPending = false;
|
||||
|
||||
/**
|
||||
* The error associated with the file upload, if any. An object of the
|
||||
* form { key, variables }, or null if no error has occured.
|
||||
*/
|
||||
$scope.error = null;
|
||||
|
||||
/**
|
||||
* The name of the file that's currently being uploaded, or has yet to
|
||||
* be imported, if any.
|
||||
*/
|
||||
$scope.fileName = null;
|
||||
|
||||
// Clear the file if instructed to do so by the parent
|
||||
$scope.$on('clearFile', () => delete $scope.fileName);
|
||||
|
||||
/**
|
||||
* Clear any displayed error message.
|
||||
*/
|
||||
const clearError = () => $scope.error = null;
|
||||
|
||||
/**
|
||||
* Set an error for display using the provided translation key and
|
||||
* translation variables.
|
||||
*
|
||||
* @param {String} key
|
||||
* The translation key.
|
||||
*
|
||||
* @param {Object.<String, String>} variables
|
||||
* The variables to subsitute into the message, if any.
|
||||
*/
|
||||
const setError = (key, variables) => $scope.error = { key, variables };
|
||||
|
||||
/**
|
||||
* The location where files can be dragged-and-dropped to.
|
||||
*
|
||||
* @type Element
|
||||
*/
|
||||
const dropTarget = $element.find('.drop-target')[0];
|
||||
|
||||
/**
|
||||
* Displays a visual indication that dropping the file currently
|
||||
* being dragged is possible. Further propagation and default behavior
|
||||
* of the given event is automatically prevented.
|
||||
*
|
||||
* @param {Event} e
|
||||
* The event related to the in-progress drag/drop operation.
|
||||
*/
|
||||
const notifyDragStart = function notifyDragStart(e) {
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
$scope.$apply(() => {
|
||||
$scope.dropPending = true;
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the visual indication that dropping the file currently
|
||||
* being dragged is possible. Further propagation and default behavior
|
||||
* of the given event is automatically prevented.
|
||||
*
|
||||
* @param {Event} e
|
||||
* The event related to the end of the former drag/drop operation.
|
||||
*/
|
||||
const notifyDragEnd = function notifyDragEnd(e) {
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
$scope.$apply(() => {
|
||||
$scope.dropPending = false;
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// Add listeners to the drop target to ensure that the visual state
|
||||
// stays up to date
|
||||
dropTarget.addEventListener('dragenter', notifyDragStart, false);
|
||||
dropTarget.addEventListener('dragover', notifyDragStart, false);
|
||||
dropTarget.addEventListener('dragleave', notifyDragEnd, false);
|
||||
|
||||
/**
|
||||
* Given a user-supplied file, validate that the file type is correct,
|
||||
* and invoke the onFile callback provided to this directive if so.
|
||||
*
|
||||
* @param {File} file
|
||||
* The user-supplied file.
|
||||
*/
|
||||
function handleFile(file) {
|
||||
|
||||
// Clear any error from a previous attempted file upload
|
||||
clearError();
|
||||
|
||||
// The MIME type of the provided file
|
||||
const mimeType = file.type;
|
||||
|
||||
// Check if the mimetype ends with one of the supported types,
|
||||
// e.g. "application/json" or "text/csv"
|
||||
if (_.every(LEGAL_FILE_TYPES.map(
|
||||
type => !mimeType.endsWith(type)))) {
|
||||
|
||||
// If the provided file is not one of the supported types,
|
||||
// display an error and abort processing
|
||||
setError('IMPORT.ERROR_INVALID_FILE_TYPE',
|
||||
{ TYPE: mimeType });
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.fileName = file.name;
|
||||
|
||||
// Invoke the provided file callback using the file
|
||||
$scope.onFile({ file });
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop target event listener that will be invoked if the user drops
|
||||
* anything onto the drop target. If a valid file is provided, the
|
||||
* onFile callback provided to this directive will be called; otherwise
|
||||
* an error will be displayed, if appropriate.
|
||||
*
|
||||
* @param {Event} e
|
||||
* The drop event that triggered this handler.
|
||||
*/
|
||||
dropTarget.addEventListener('drop', function(e) {
|
||||
|
||||
notifyDragEnd(e);
|
||||
|
||||
const files = e.dataTransfer.files;
|
||||
|
||||
// Ignore any non-files that are dragged into the drop area
|
||||
if (files.length < 1)
|
||||
return;
|
||||
|
||||
if (files.length > 2) {
|
||||
|
||||
// If more than one file was provided, print an error explaining
|
||||
// that only a single file is allowed and abort processing
|
||||
setError('IMPORT.ERROR_FILE_SINGLE_ONLY');
|
||||
return;
|
||||
}
|
||||
|
||||
handleFile(files[0]);
|
||||
|
||||
}, false);
|
||||
|
||||
/**
|
||||
* The hidden file input used to create a file browser.
|
||||
*
|
||||
* @type Element
|
||||
*/
|
||||
const fileUploadInput = $element.find('.file-upload-input')[0];
|
||||
|
||||
/**
|
||||
* A function that will click on the hidden file input to open a file
|
||||
* browser to allow the user to select a file for upload.
|
||||
*/
|
||||
$scope.openFileBrowser = () =>
|
||||
$timeout(() => fileUploadInput.click(), 0, false);
|
||||
|
||||
/**
|
||||
* A handler that will be invoked when a user selectes a file in the
|
||||
* file browser. After some error checking, the file will be passed to
|
||||
* the onFile callback provided to this directive.
|
||||
*
|
||||
* @param {Event} e
|
||||
* The event that was triggered when the user selected a file in
|
||||
* their file browser.
|
||||
*/
|
||||
fileUploadInput.onchange = e => {
|
||||
|
||||
// Process the uploaded file
|
||||
handleFile(e.target.files[0]);
|
||||
|
||||
// Clear the value to ensure that the change event will be fired
|
||||
// if the user selects the same file again
|
||||
fileUploadInput.value = null;
|
||||
|
||||
};
|
||||
|
||||
}];
|
||||
return directive;
|
||||
|
||||
}]);
|
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
.file-upload-container {
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 24px 24px 24px;
|
||||
|
||||
width: fit-content;
|
||||
|
||||
border: 1px solid rgba(0,0,0,.25);
|
||||
box-shadow: 1px 1px 2px rgb(0 0 0 / 25%);
|
||||
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .upload-header {
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 500px;
|
||||
margin-bottom: 5px;
|
||||
justify-content: space-between;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .file-error {
|
||||
|
||||
color: red;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .file-options {
|
||||
|
||||
font-weight: bold;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .file-upload-input {
|
||||
|
||||
display: none;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .drop-target {
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
|
||||
width: 500px;
|
||||
height: 200px;
|
||||
|
||||
background: rgba(0,0,0,.04);
|
||||
border: 1px solid black;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .drop-target.file-present {
|
||||
|
||||
background: rgba(0,0,0,.15);
|
||||
|
||||
}
|
||||
|
||||
|
||||
.file-upload-container .drop-target .file-name {
|
||||
|
||||
font-weight: bold;
|
||||
font-size: 1.5em;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .drop-target.drop-pending {
|
||||
|
||||
background: #3161a9;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .drop-target.drop-pending > * {
|
||||
|
||||
opacity: 0.5;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .drop-target .title {
|
||||
|
||||
font-weight: bold;
|
||||
font-size: 1.25em;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .drop-target .browse-link {
|
||||
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
|
||||
}
|
@@ -42,3 +42,104 @@
|
||||
.import .errors .error-message ul {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.file-upload-container {
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 24px 24px 24px;
|
||||
|
||||
width: fit-content;
|
||||
|
||||
border: 1px solid rgba(0,0,0,.25);
|
||||
box-shadow: 1px 1px 2px rgb(0 0 0 / 25%);
|
||||
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .upload-header {
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 500px;
|
||||
margin-bottom: 5px;
|
||||
justify-content: space-between;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .file-error {
|
||||
|
||||
color: red;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .file-options {
|
||||
|
||||
font-weight: bold;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .file-upload-input {
|
||||
|
||||
display: none;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .drop-target {
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
|
||||
width: 500px;
|
||||
height: 200px;
|
||||
|
||||
background: rgba(0,0,0,.04);
|
||||
border: 1px solid black;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .drop-target.file-present {
|
||||
|
||||
background: rgba(0,0,0,.15);
|
||||
|
||||
}
|
||||
|
||||
|
||||
.file-upload-container .drop-target .file-name {
|
||||
|
||||
font-weight: bold;
|
||||
font-size: 1.5em;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .drop-target.drop-pending {
|
||||
|
||||
background: #3161a9;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .drop-target.drop-pending > * {
|
||||
|
||||
opacity: 0.5;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .drop-target .title {
|
||||
|
||||
font-weight: bold;
|
||||
font-size: 1.25em;
|
||||
|
||||
}
|
||||
|
||||
.file-upload-container .drop-target .browse-link {
|
||||
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
|
||||
}
|
@@ -4,8 +4,32 @@
|
||||
<h2>{{'IMPORT.HEADER' | translate}}</h2>
|
||||
<guac-user-menu></guac-user-menu>
|
||||
</div>
|
||||
|
||||
<div class="file-upload-container">
|
||||
|
||||
<div class="upload-header">
|
||||
<span class="file-options">{{'IMPORT.UPLOAD_FILE_TYPES' | translate}}</span>
|
||||
<a
|
||||
href="#/import/connection/file-format-help" target="_blank"
|
||||
class="file-help-link">{{'IMPORT.UPLOAD_HELP_LINK' | translate}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="drop-target" ng-class="{ 'drop-pending': dropPending, 'file-present': fileName}">
|
||||
|
||||
<div ng-show="!fileName" class="title">{{'IMPORT.UPLOAD_DROP_TITLE' | translate}}</div>
|
||||
|
||||
<input type="file" class="file-upload-input"/>
|
||||
<a ng-show="!fileName" ng-click="openFileBrowser()" class="browse-link">
|
||||
{{'IMPORT.UPLOAD_BROWSE_LINK' | translate}}
|
||||
</a>
|
||||
|
||||
<div ng-show="fileName" class="file-name"> {{fileName}} </div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<connection-import-file-upload on-file="handleFile(file)"></connection-import-file-upload>
|
||||
|
||||
<div class="import-buttons">
|
||||
<button
|
||||
|
@@ -1,30 +0,0 @@
|
||||
<div class="file-upload-container">
|
||||
|
||||
<div class="upload-header">
|
||||
<span class="file-options">{{'IMPORT.UPLOAD_FILE_TYPES' | translate}}</span>
|
||||
<a
|
||||
href="#/import/connection/file-format-help" target="_blank"
|
||||
class="file-help-link">{{'IMPORT.UPLOAD_HELP_LINK' | translate}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="drop-target" ng-class="{ 'drop-pending': dropPending, 'file-present': fileName}">
|
||||
|
||||
<div ng-show="!fileName" class="title">{{'IMPORT.UPLOAD_DROP_TITLE' | translate}}</div>
|
||||
|
||||
<input type="file" class="file-upload-input"/>
|
||||
<a ng-show="!fileName" ng-click="openFileBrowser()" class="browse-link">
|
||||
{{'IMPORT.UPLOAD_BROWSE_LINK' | translate}}
|
||||
</a>
|
||||
|
||||
<div ng-show="fileName" class="file-name"> {{fileName}} </div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- The translatable error message regarding the provided file(s), if any -->
|
||||
<p
|
||||
class="file-error" ng-show="error.key"
|
||||
translate="{{error.key}}" translate-values="{{error.variables}}"
|
||||
></p>
|
||||
|
||||
</div>
|
Reference in New Issue
Block a user